From b1f428517eb49ee1fea0dd0e62a361e1ce8a2795 Mon Sep 17 00:00:00 2001 From: Frank Becker Date: Thu, 6 Feb 2020 00:19:45 +0100 Subject: [PATCH] enable / disable bot module use !bot enable oder !bot disable to enabel or disable a module. to get a list of available modules and see if they are enabled run !bot modules --- bot.py | 32 ++++++++++++++++------------- modules/bot.py | 44 +++++++++++++++++++++++++++++++++++++++- modules/common/module.py | 14 +++++++++++-- modules/cron.py | 5 ++++- modules/googlecal.py | 5 ++++- modules/help.py | 18 ++++++++++------ modules/loc.py | 2 +- modules/teamup.py | 6 +++++- modules/twitter.py | 3 +++ modules/url.py | 5 ++++- 10 files changed, 106 insertions(+), 28 deletions(-) diff --git a/bot.py b/bot.py index dbf9b7b..6796ce1 100755 --- a/bot.py +++ b/bot.py @@ -119,7 +119,7 @@ class Bot: moduleobject = self.modules.get(command) - if "matrix_message" in dir(moduleobject): + if moduleobject.enabled and ("matrix_message" in dir(moduleobject)): try: await moduleobject.matrix_message(bot, room, event) except CommandRequiresAdmin: @@ -183,11 +183,12 @@ class Bot: while True: self.pollcount = self.pollcount + 1 for modulename, moduleobject in self.modules.items(): - if "matrix_poll" in dir(moduleobject): - try: - await moduleobject.matrix_poll(bot, self.pollcount) - except Exception: - traceback.print_exc(file=sys.stderr) + if moduleobject.enabled: + if "matrix_poll" in dir(moduleobject): + try: + await moduleobject.matrix_poll(bot, self.pollcount) + except Exception: + traceback.print_exc(file=sys.stderr) await asyncio.sleep(10) def set_account_data(self, data): @@ -243,20 +244,24 @@ class Bot: self.join_on_invite = join_on_invite is not None self.owners = bot_owners.split(',') self.get_modules() + else: print("The environment variables MATRIX_SERVER, MATRIX_USER and BOT_OWNERS are mandatory") sys.exit(1) def start(self): - print(f'Starting {len(self.modules)} modules..') + self.load_settings(self.get_account_data()) + enabled_modules = [module for module_name, module in self.modules.items() if module.enabled] + print(f'Starting {len(enabled_modules)} modules..') for modulename, moduleobject in self.modules.items(): - print('Starting', modulename, '..') - if "matrix_start" in dir(moduleobject): - try: - moduleobject.matrix_start(bot) - except Exception: - traceback.print_exc(file=sys.stderr) + if moduleobject.enabled: + print('Starting', modulename, '..') + if "matrix_start" in dir(moduleobject): + try: + moduleobject.matrix_start(bot) + except Exception: + traceback.print_exc(file=sys.stderr) def stop(self): print(f'Stopping {len(self.modules)} modules..') @@ -322,7 +327,6 @@ class Bot: else: await self.client.client_session.close() - bot = Bot() bot.init() try: diff --git a/modules/bot.py b/modules/bot.py index 8a9d09c..39fc2a5 100644 --- a/modules/bot.py +++ b/modules/bot.py @@ -4,6 +4,10 @@ from modules.common.module import BotModule class MatrixModule(BotModule): + def __init__(self): + super().__init__() + self.enable() + def matrix_start(self, bot): self.starttime = datetime.now() @@ -22,6 +26,14 @@ class MatrixModule(BotModule): await self.stats(bot, room) elif args[1] == 'leave': await self.leave(bot, room, event) + elif args[1] == 'modules': + await self.show_modules(bot, room) + + elif len(args) == 3: + if args[1] == 'enable': + await self.enable_module(bot, room, event, args[2]) + elif args[1] == 'disable': + await self.disable_module(bot, room, event, args[2]) else: await bot.send_text(room, 'Unknown command, sorry.') @@ -72,5 +84,35 @@ class MatrixModule(BotModule): print(f'{event.sender} commanded bot to quit, so quitting..') bot.bot_task.cancel() + async def enable_module(self, bot, room, event, module_name): + bot.must_be_admin(room, event) + print(f"asked to enable {module_name}") + if bot.modules.get(module_name): + module = bot.modules.get(module_name) + module.enable() + module.matrix_start(bot) + bot.save_settings() + await bot.send_text(room, f"module {module_name} enabled") + else: + await bot.send_text(room, f"module with name {module_name} not found. execute !bot modules for a list of available modules") + + async def disable_module(self, bot, room, event, module_name): + bot.must_be_admin(room, event) + print(f"asked to disable {module_name}") + if bot.modules.get(module_name): + module = bot.modules.get(module_name) + module.disable() + module.matrix_stop(bot) + bot.save_settings() + await bot.send_text(room, f"module {module_name} disabled") + else: + await bot.send_text(room, f"module with name {module_name} not found. execute !bot modules for a list of available modules") + + + async def show_modules(self, bot, room): + await bot.send_text(room, "Modules:\n") + for modulename, module in bot.modules.items(): + await bot.send_text(room, f"Name: {modulename:20s} Enabled: {module.enabled}") + def help(self): - return 'Bot management commands' + return 'Bot management commands. (quit, version, reload, status, stats, leave, modules, enable, disable)' diff --git a/modules/common/module.py b/modules/common/module.py index 88cc5e4..aaa62bf 100644 --- a/modules/common/module.py +++ b/modules/common/module.py @@ -25,6 +25,9 @@ class BotModule(ABC): """ + def __init__(self): + self.enabled = False + def matrix_start(self, bot): """Called once on startup @@ -75,7 +78,7 @@ class BotModule(ABC): :return: a dict object that can be converted to JSON :rtype: dict """ - pass + return {'enabled': self.enabled} def set_settings(self, data): """Load these settings. It should be the same JSON you returned in previous get_settings @@ -83,4 +86,11 @@ class BotModule(ABC): :param data: a dict object containing the settings read from the account :type data: dict """ - pass + if data.get('enabled'): + self.enabled = data['enabled'] + + def enable(self): + self.enabled = True + + def disable(self): + self.enabled = False \ No newline at end of file diff --git a/modules/cron.py b/modules/cron.py index a411da8..24e8c16 100644 --- a/modules/cron.py +++ b/modules/cron.py @@ -34,9 +34,12 @@ class MatrixModule(BotModule): return ('Runs scheduled commands') def get_settings(self): - return {'daily_commands': self.daily_commands} + data = super().get_settings() + data['daily_commands'] = self.daily_commands + return data def set_settings(self, data): + super().set_settings(data) if data.get('daily_commands'): self.daily_commands = data['daily_commands'] diff --git a/modules/googlecal.py b/modules/googlecal.py index bfabb7f..0a49cfd 100644 --- a/modules/googlecal.py +++ b/modules/googlecal.py @@ -166,9 +166,12 @@ class MatrixModule(BotModule): return ('Google calendar. Lists 10 next events by default. today = list today\'s events.') def get_settings(self): - return {'calendar_rooms': self.calendar_rooms} + data = super().get_settings() + data['calendar_rooms'] = self.calendar_rooms + return data def set_settings(self, data): + super().set_settings(data) if data.get('calendar_rooms'): self.calendar_rooms = data['calendar_rooms'] diff --git a/modules/help.py b/modules/help.py index 020870a..dc77952 100644 --- a/modules/help.py +++ b/modules/help.py @@ -2,16 +2,22 @@ from modules.common.module import BotModule class MatrixModule(BotModule): + + def __init__(self): + super().__init__() + self.enable() + async def matrix_message(self, bot, room, event): msg = f'This is Hemppa {bot.version}, a generic Matrix bot. Known commands:\n\n' for modulename, moduleobject in bot.modules.items(): - msg = msg + '!' + modulename - try: - msg = msg + ' - ' + moduleobject.help() + '\n' - except AttributeError: - pass - msg + msg + '\n' + if moduleobject.enabled: + msg = msg + '!' + modulename + try: + msg = msg + ' - ' + moduleobject.help() + '\n' + except AttributeError: + pass + msg + msg + '\n' msg = msg + "\nAdd your own commands at https://github.com/vranki/hemppa" await bot.send_text(room, msg) diff --git a/modules/loc.py b/modules/loc.py index dc341d5..7e1217f 100644 --- a/modules/loc.py +++ b/modules/loc.py @@ -1,5 +1,5 @@ from geopy.geocoders import Nominatim -from nio import RoomMessageUnknown +from nio import RoomMessageUnknown, AsyncClient from modules.common.module import BotModule diff --git a/modules/teamup.py b/modules/teamup.py index 848adf0..c2bc421 100644 --- a/modules/teamup.py +++ b/modules/teamup.py @@ -146,9 +146,13 @@ class MatrixModule(BotModule): self.calendars[calid].timestamp = int(time.time()) def get_settings(self): - return {'apikey': self.api_key or '', 'calendar_rooms': self.calendar_rooms} + data = super().get_settings() + data['apikey'] = self.api_key + data['calendar_rooms'] = self.calendar_rooms + return data def set_settings(self, data): + super().set_settings(data) if data.get('calendar_rooms'): self.calendar_rooms = data['calendar_rooms'] if data.get('apikey'): diff --git a/modules/twitter.py b/modules/twitter.py index 0542b38..4479368 100644 --- a/modules/twitter.py +++ b/modules/twitter.py @@ -1,3 +1,6 @@ +import sys +import traceback + from twitterscraper import query_tweets_from_user from modules.common.pollingservice import PollingService diff --git a/modules/url.py b/modules/url.py index 371daea..3f37e56 100644 --- a/modules/url.py +++ b/modules/url.py @@ -146,9 +146,12 @@ class MatrixModule(BotModule): return def get_settings(self): - return {"status": self.status} + data = super().get_settings() + data['status'] = self.status + return data def set_settings(self, data): + super().set_settings(data) if data.get("status"): self.status = data["status"]