From 3ebd87865cdc8c0f82853d1769b085be766453c4 Mon Sep 17 00:00:00 2001 From: Seth Hendrick Date: Wed, 20 Oct 2021 15:51:11 -0400 Subject: [PATCH] Add topic handler (#383) * Added new topic setting. * Added Topic handler that will optionally forward topic changes from IRC to the Telegram channel. Co-authored-by: Tim Zabel --- docs/user/config-file-glossary.rst | 3 + env.example | 1 + internal/config.go | 1 + internal/handlers/irc/handlers.go | 28 +++++- internal/handlers/irc/handlers_test.go | 114 +++++++++++++++++++++++++ 5 files changed, 143 insertions(+), 4 deletions(-) diff --git a/docs/user/config-file-glossary.rst b/docs/user/config-file-glossary.rst index 21ce1b0..18739d0 100644 --- a/docs/user/config-file-glossary.rst +++ b/docs/user/config-file-glossary.rst @@ -130,6 +130,9 @@ Telegram settings ``MAX_MESSAGES_PER_MINUTE=20`` Maximum number of messages sent to Telegram from IRC per minute. +``SHOW_TOPIC_MESSAGE=true`` + Send Telegram message when the topic in the IRC channel is changed. + ``SHOW_ACTION_MESSAGE=true`` Relay action messages (e.g. ``/me thinks TeleIRC is cool!``). diff --git a/env.example b/env.example index 1e50485..52c02cd 100644 --- a/env.example +++ b/env.example @@ -62,6 +62,7 @@ IRC_QUIT_MESSAGE="TeleIRC bridge stopped." TELEGRAM_CHAT_ID=-0000000000000 TELEIRC_TOKEN=000000000:AAAAAAaAAa2AaAAaoAAAA-a_aaAAaAaaaAA MAX_MESSAGES_PER_MINUTE=20 +SHOW_TOPIC_MESSAGE=true SHOW_ACTION_MESSAGE=true SHOW_JOIN_MESSAGE=false JOIN_MESSAGE_ALLOW_LIST="" diff --git a/internal/config.go b/internal/config.go index fb7a10b..d6f1331 100644 --- a/internal/config.go +++ b/internal/config.go @@ -51,6 +51,7 @@ type TelegramSettings struct { ChatID int64 `env:"TELEGRAM_CHAT_ID,required"` Prefix string `env:"TELEGRAM_MESSAGE_PREFIX" envDefault:"<"` Suffix string `env:"TELEGRAM_MESSAGE_SUFFIX" envDefault:">"` + ShowTopicMessage bool `env:"SHOW_TOPIC_MESSAGE" envDefault:"false"` ShowJoinMessage bool `env:"SHOW_JOIN_MESSAGE" envDefault:"false"` JoinMessageAllowList []string `env:"JOIN_MESSAGE_ALLOW_LIST" envDefault:"[]string{}"` ShowActionMessage bool `env:"SHOW_ACTION_MESSAGE" envDefault:"false"` diff --git a/internal/handlers/irc/handlers.go b/internal/handlers/irc/handlers.go index 7995b72..cd9c2bd 100644 --- a/internal/handlers/irc/handlers.go +++ b/internal/handlers/irc/handlers.go @@ -8,10 +8,12 @@ import ( ) const ( - joinFmt = "* %s joins" - partFmt = "* %s parts" - quitFmt = "* %s quit (%s)" - kickFmt = "* %s kicked %s from %s: %s" + joinFmt = "* %s joins" + partFmt = "* %s parts" + quitFmt = "* %s quit (%s)" + kickFmt = "* %s kicked %s from %s: %s" + topicChangeFmt = "* %s changed topic to: %s" + topicClearedFmt = "* %s removed topic" ) /* @@ -151,6 +153,23 @@ func partHandler(c ClientInterface) func(*girc.Client, girc.Event) { } } +func topicHandler(c ClientInterface) func(*girc.Client, girc.Event) { + return func(gc *girc.Client, e girc.Event) { + c.Logger().LogDebug("topicHandler triggered") + if c.TgSettings().ShowTopicMessage { + // e.Source.Name is the user who changed the topic. + // e.Params[0] is the channel where the topic changed. + // e.Params[1] is the new topic. We should assume that + // this may or may not appear as its possible to clear a topic. + if len(e.Params) <= 1 { + c.SendToTg(fmt.Sprintf(topicClearedFmt, e.Source.Name)) + } else { + c.SendToTg(fmt.Sprintf(topicChangeFmt, e.Source.Name, e.Params[1])) + } + } + } +} + func quitHandler(c ClientInterface) func(*girc.Client, girc.Event) { return func(gc *girc.Client, e girc.Event) { c.Logger().LogDebug("quitHandler triggered") @@ -190,6 +209,7 @@ func getHandlerMapping() map[string]Handler { girc.KICK: kickHandler, girc.PRIVMSG: messageHandler, girc.PART: partHandler, + girc.TOPIC: topicHandler, girc.QUIT: quitHandler, } } diff --git a/internal/handlers/irc/handlers_test.go b/internal/handlers/irc/handlers_test.go index 7645da6..e2116b2 100644 --- a/internal/handlers/irc/handlers_test.go +++ b/internal/handlers/irc/handlers_test.go @@ -555,6 +555,120 @@ func TestKickHandlerNoReason(t *testing.T) { }) } +func TestTopicHandler_On(t *testing.T) { + ctrl := gomock.NewController(t) + + defer ctrl.Finish() + + tgSettings := internal.TelegramSettings{ + ShowTopicMessage: true, + } + + mockClient := NewMockClientInterface(ctrl) + mockLogger := internal.NewMockDebugLogger(ctrl) + mockClient. + EXPECT(). + Logger(). + Return(mockLogger) + mockLogger. + EXPECT(). + LogDebug(gomock.Eq("topicHandler triggered")) + mockClient. + EXPECT(). + TgSettings(). + Return(&tgSettings) + mockClient. + EXPECT(). + SendToTg(gomock.Eq("* TEST_NAME changed topic to: NEW TOPIC!")) + + myHandler := topicHandler(mockClient) + myHandler(&girc.Client{}, girc.Event{ + Source: &girc.Source{ + Name: "TEST_NAME", + }, + Params: []string{ + "#testchannel", + "NEW TOPIC!", + }, + }) +} + +func TestTopicHandler_Off(t *testing.T) { + ctrl := gomock.NewController(t) + + defer ctrl.Finish() + + tgSettings := internal.TelegramSettings{ + ShowTopicMessage: false, + } + + mockClient := NewMockClientInterface(ctrl) + mockLogger := internal.NewMockDebugLogger(ctrl) + mockClient. + EXPECT(). + Logger(). + Return(mockLogger) + mockLogger. + EXPECT(). + LogDebug(gomock.Eq("topicHandler triggered")) + mockClient. + EXPECT(). + TgSettings(). + Return(&tgSettings) + mockClient. + EXPECT(). + SendToTg(gomock.Any()). + MaxTimes(0) + + myHandler := topicHandler(mockClient) + myHandler(&girc.Client{}, girc.Event{ + Source: &girc.Source{ + Name: "TEST_NAME", + }, + Params: []string{ + "#testchannel", + "NEW TOPIC!", + }, + }) +} + +func TestTopicHandlerCleared(t *testing.T) { + ctrl := gomock.NewController(t) + + defer ctrl.Finish() + + tgSettings := internal.TelegramSettings{ + ShowTopicMessage: true, + } + + mockClient := NewMockClientInterface(ctrl) + mockLogger := internal.NewMockDebugLogger(ctrl) + mockClient. + EXPECT(). + Logger(). + Return(mockLogger) + mockLogger. + EXPECT(). + LogDebug(gomock.Eq("topicHandler triggered")) + mockClient. + EXPECT(). + TgSettings(). + Return(&tgSettings) + mockClient. + EXPECT(). + SendToTg(gomock.Eq("* TEST_NAME removed topic")) + + myHandler := topicHandler(mockClient) + myHandler(&girc.Client{}, girc.Event{ + Source: &girc.Source{ + Name: "TEST_NAME", + }, + Params: []string{ + "#testchannel", + }, + }) +} + func TestConnectHandlerKey(t *testing.T) { ctrl := gomock.NewController(t)