From 64dee28c4e47efa19dbdc9ff7107f1f29414972f Mon Sep 17 00:00:00 2001 From: sheepish Date: Mon, 21 Jun 2021 21:51:11 +0000 Subject: [PATCH] add module to manage disabled channels --- hermes/modules/disabled.py | 81 +++++++++++++++++ tests/test_modules_disabled.py | 158 +++++++++++++++++++++++++++++++++ 2 files changed, 239 insertions(+) create mode 100644 hermes/modules/disabled.py create mode 100644 tests/test_modules_disabled.py diff --git a/hermes/modules/disabled.py b/hermes/modules/disabled.py new file mode 100644 index 0000000..87250ea --- /dev/null +++ b/hermes/modules/disabled.py @@ -0,0 +1,81 @@ +from hermes.module import event, command +MAIN_CHANNEL = '#disabled' +INTERVIEW_CHANNEL_MAXID = 5 +INTERVIEW_CHANNEL_FMT = '#disabled-{chanid}' +INTERVIEW_CHANNELS = {INTERVIEW_CHANNEL_FMT.format(chanid=chan_id) + for chan_id in range(1, INTERVIEW_CHANNEL_MAXID + 1)} +ALLOWED_USER_CLASSES = {'Moderator', 'SeniorModerator', 'LeadDeveloper'} + + +class BadCommand(Exception): + pass + + +def check_auth(bot, host): + split_host = host.split('.') + if len(split_host) == 3 and split_host[0] == 'sysop' \ + and host.endswith(bot.config.site.tld): + return True + if len(split_host) != 4: + return False + + user_class = split_host[1] + return host.endswith(bot.config.site.tld) \ + and user_class in ALLOWED_USER_CLASSES + + +def process_arguments(bot, connection, event): + if not check_auth(bot, event.source.host): + connection.privmsg(event.target, + "You are not authorized to do this command!") + raise BadCommand() + + if len(event.args) > 0: + target_user = event.args[0] + else: + connection.privmsg(event.target, "{} []".format(event.cmd)) + raise BadCommand() + + if len(event.args) >= 2: + target_id = event.args[1] + target_chan = INTERVIEW_CHANNEL_FMT.format(chanid=target_id) + if target_chan not in INTERVIEW_CHANNELS: + connection.privmsg(event.target, "invalid chanid") + raise BadCommand() + elif event.target in INTERVIEW_CHANNELS: + target_chan = event.target + else: + connection.privmsg(event.target, "no chanid") + raise BadCommand() + + return target_user, target_chan + + +@event('privmsg', 'pubmsg') +@command('disabled-move') +def disabled_move(bot, connection, event): + try: + target_user, target_chan = process_arguments(bot, connection, event) + except BadCommand: + return + + if not bot.channels[MAIN_CHANNEL].has_user(target_user): + connection.privmsg(event.target, "user not in {}".format(MAIN_CHANNEL)) + return + + connection.send_items('SAJOIN', target_user, target_chan) + + +@event('privmsg', 'pubmsg') +@command('disabled-kick') +def disabled_kick(bot, connection, event): + try: + target_user, target_chan = process_arguments(bot, connection, event) + except BadCommand: + return + + if not bot.channels[target_chan].has_user(target_user): + connection.privmsg(event.target, "user not in channel") + return + + connection.kick(target_chan, target_user) diff --git a/tests/test_modules_disabled.py b/tests/test_modules_disabled.py new file mode 100644 index 0000000..f3ae390 --- /dev/null +++ b/tests/test_modules_disabled.py @@ -0,0 +1,158 @@ +import irc.client +import irc.bot +import pytest +from unittest.mock import MagicMock + +from hermes.modules import disabled +from hermes.utils import convert + + +class Event(irc.client.Event): + @property + def args(self): + args = self.arguments[0].split() + return args[1:] if len(args) > 1 else [] + + @property + def cmd(self): + return self.arguments[0].lower() + + +@pytest.fixture +def irc_bot(): + bot = irc.bot.SingleServerIRCBot( + server_list=[('localhost', '9999')], + realname='irclibbot', + nickname='irclibbot', + ) + channel = irc.bot.Channel() + channel.add_user('someuser') + bot.channels['#disabled'] = channel + channel = irc.bot.Channel() + channel.add_user('interviewuser') + bot.channels['#disabled-1'] = channel + bot.config = convert({'site': {'tld': 'example.test'}}) + bot.connection.send_raw = MagicMock() + bot.connection.send_items = MagicMock() + bot.connection.kick = MagicMock() + yield bot + + +def test_disabled_move_success(irc_bot): + event = Event( + type='privmsg', + source=irc.client.NickMask('nick!userid@name.Moderator.example.test'), + target='#disabled', + arguments=['.disabled-move someuser 1'] + ) + disabled.disabled_move(irc_bot, irc_bot.connection, event) + irc_bot.connection.send_items.assert_called_once() + call = irc_bot.connection.send_items.call_args + assert call.args[0] == 'SAJOIN' + + +def test_disabled_move_nouser(irc_bot): + event = Event( + type='privmsg', + source=irc.client.NickMask('nick!userid@name.Moderator.example.test'), + target='#disabled', + arguments=['.disabled-move notinterviewuser 1'] + ) + disabled.disabled_move(irc_bot, irc_bot.connection, event) + irc_bot.connection.kick.assert_not_called() + irc_bot.connection.send_items.assert_called_once() + call = irc_bot.connection.send_items.call_args + assert call.args[0] == 'PRIVMSG' + + +def test_disabled_kick_success(irc_bot): + event = Event( + type='privmsg', + source=irc.client.NickMask('nick!userid@name.Moderator.example.test'), + target='#disabled', + arguments=['.disabled-kick interviewuser 1'] + ) + disabled.disabled_kick(irc_bot, irc_bot.connection, event) + irc_bot.connection.kick.assert_called_once() + call = irc_bot.connection.kick.call_args + assert call.args[1] == 'interviewuser' + + +def test_disabled_kick_nouser(irc_bot): + event = Event( + type='privmsg', + source=irc.client.NickMask('nick!userid@name.Moderator.example.test'), + target='#disabled', + arguments=['.disabled-kick notinterviewuser 1'] + ) + disabled.disabled_kick(irc_bot, irc_bot.connection, event) + irc_bot.connection.kick.assert_not_called() + irc_bot.connection.send_items.assert_called_once() + call = irc_bot.connection.send_items.call_args + assert call.args[0] == 'PRIVMSG' + + +def test_process_arguments_unprivileged(irc_bot): + event = Event( + type='privmsg', + source=irc.client.NickMask('nick!userid@name.User.example.test'), + target='#disabled', + arguments=['.disabled-move someuser 1'] + ) + with pytest.raises(disabled.BadCommand): + disabled.process_arguments(irc_bot, irc_bot.connection, event) + + +def test_process_arguments_implicit_channel(irc_bot): + event = Event( + type='privmsg', + source=irc.client.NickMask('nick!userid@name.Moderator.example.test'), + target='#disabled-1', + arguments=['.disabled-move someuser'] + ) + result = disabled.process_arguments(irc_bot, irc_bot.connection, event) + assert result[1] == '#disabled-1' + + +def test_process_arguments_bad_channel(irc_bot): + event = Event( + type='privmsg', + source=irc.client.NickMask('nick!userid@name.Moderator.example.test'), + target='#disabled', + arguments=['.disabled-move someuser nope'] + ) + with pytest.raises(disabled.BadCommand): + disabled.process_arguments(irc_bot, irc_bot.connection, event) + + +def test_process_arguments_bad_channel2(irc_bot): + event = Event( + type='privmsg', + source=irc.client.NickMask('nick!userid@name.Moderator.example.test'), + target='#disabled', + arguments=['.disabled-move someuser -1'] + ) + with pytest.raises(disabled.BadCommand): + disabled.process_arguments(irc_bot, irc_bot.connection, event) + + +def test_process_arguments_no_channel(irc_bot): + event = Event( + type='privmsg', + source=irc.client.NickMask('nick!userid@name.Moderator.example.test'), + target='#disabled', + arguments=['.disabled-move someuser'] + ) + with pytest.raises(disabled.BadCommand): + disabled.process_arguments(irc_bot, irc_bot.connection, event) + + +def test_process_arguments_no_nick(irc_bot): + event = Event( + type='privmsg', + source=irc.client.NickMask('nick!userid@name.Moderator.example.test'), + target='#disabled', + arguments=['.disabled-move'] + ) + with pytest.raises(disabled.BadCommand): + disabled.process_arguments(irc_bot, irc_bot.connection, event)