from matrixbot import MatrixBot from functools import partial import random import json import os import logging from googletrans import LANGUAGES,Translator logging.basicConfig(level=logging.DEBUG) log = logging.getLogger("Kalauerbot") version = "1.0.0" class Kalauerbot(MatrixBot): def __init__(self,host,display_name,token,user_id,dbpath = "kalauerdb.json",allowlist=None): log.debug(f"dbpath: {dbpath}") log.debug(f"allowlist: {allowlist}") self.allowlist = allowlist self.dbpath=dbpath self.load_db() super().__init__(host,display_name,token,user_id) def load_db(self): try: log.info(f"loading entries from {self.dbpath}") self.db = json.load(open(self.dbpath)) log.debug(self.db) except: log.info(f"Cannot open {self.dbpath}, creating empty db") self.db = { "__chosen__": None } self.save_db() def save_db(self): json.dump(self.db,open(self.dbpath,"w+")) log.debug(f"saving db to {self.dbpath}") def active_db(self): return dict(self._get_active()) def _get_active(self): for name,entry in self.db.items(): if name == "__chosen__": continue # skip the __chosen__ special object elif entry['active']: yield name,entry else: log.debug(f"skipping {name} because user is inactive") continue def process_event(self, room, event): # {'content': {'body': 'hello bot', 'msgtype': 'm.text'}, 'event_id': '$1597412611141040kQPEC:thales.citadel.team', 'origin_server_ts': 1597412611511, 'sender': '@frichter:thales.citadel.team', 'type': 'm.room.message', 'unsigned': {'age': 98}, 'room_id': '!eXmPERUmuMagsLVxar:thales.citadel.team'} if self.user_id == event['sender']: return # don't answer own message if event['type'] != 'm.room.message': return msg = event['content']['body'] if self.allowlist and room.room_id not in self.allowlist: log.debug("Ignoring message {msg} because {room.room_id} is not in allowlist") say = partial(self.say,room) db = self.db chosen = db['__chosen__'] if msg == "!help" or msg == "!commands": say(f""" Kalauerbot Version {version} available commands: !add - add a new person to the kalauer roster (alias: !activate, !reactivate) !delete - deactivate the person from the roster (alias: !remove, !deactivate, !freeze) !deactivate - deactivate person (e.g. because he is in holiday) !activate - re-activate person !kill - ultimately remove person from kalauer roster (cannot be reversed) !choose - choose the next person to be the kalauer könig !who - find out who was chosen to be todays kalauer könig (alias: !wer, !current) !ok - confirm the kalauer (alias: !gut !passt !reicht !approved) !reject - reject the kalauer (alias: !zu-gut !zu-schlecht !französisch !french) !demand - demand a certain person to be the new kalauer könig !list - list the current roster and weight,totals !kalauer - an emergency kalauer """) try: command,args= msg.split(" ",1) except: command = msg if command in ["!add", "!activate", "!reactivate"]: name = args.strip() if name in db and db[name]['active']: say(f"{name} already part of the kalauer roster") elif name in db and not db[name]['active']: say(f"Reactivating {name}. Welcome back to the world of fun, {name}!") db[name]['active'] = True else: say(f"{name} has been added to the kalauer roster, starting weight is 1") db[name] = { "weight": 1, "total":0, "active": True} self.save_db() elif command in ["!delete","!remove","!deactivate","!freeze"]: name = args.strip() if name not in db: say(f"Cannot deactiate someone who was never in kalauer db") elif name in db and db[name]['active']: say(f"Deactivating {name}, see you soon!") db[name]['active'] = False else: say(f"{name} was already deactivated in the kalauer db") self.save_db() elif command == "!choose": # TODO: refactor this, maybe? names = [] weights = [] for name,entity in self.active_db().items(): names.append(name) weights.append(entity['weight']) log.debug(names) log.debug(weights) db["__chosen__"] = chosen = random.choices(names,weights=weights)[0] say(f"{chosen} was chosen to be the next kalauer könig, congratulations!") self.save_db() elif command in ["!who","!wer", "!current"]: if chosen: say(f"{chosen} was chosen to be the next kalauer könig") else: say(f"Nobody was chosen to be the the kalauer könig, start the process with `!choose`") elif command in [ "!ok", "!approved", "!gut", "!passt", "!reicht" ]: if not db['__chosen__']: say("Nobody is nominated, cannot approve kalauer") else: log.info("Increasing weight of all active persons") for name in self.active_db(): db[name]['weight'] += 1 log.info("The kalauer könig gets his weight set to 0") db[chosen]['weight'] = 0 db[chosen]['total'] += 1 say(f"""Your kalauer has been approved, your total number of approved kalauers is {db[chosen]['total']}\n\n{chosen}, please choose a new potential kalauer könig by typing in `!choose` to let the kalauerbot choose or `!demand ` to force your choice""") log.debug("Unsetting current chosen") db["__chosen__"] = None self.save_db() elif command in [ "!reject", "!zu-gut", "!zu-schlecht", "!französisch", "!french"]: if not db['__chosen__']: say("Nobody is nominated, cannot reject kalauer") else: say(f"{chosen}, your kalauer privilege was revoked, nobody is chosen now. Choose another kalauer könig with `!choose`") db["__chosen__"] = None self.save_db() elif command == "!demand": name = args.strip() if name in self.active_db(): say(f"The previous kalauer könig demands user {name} to be the next kalauer könig. The rules of the Kalauer are divine and shall be respected.") db["__chosen__"] = name elif name in db: say(f"{name} is currently not active, cannot be chosen") else: say(f"{name} name does not exist in the database, add the user before demanding a kalauer from him") self.save_db() elif command == "!list": txt = "Kalauer roster:\n\n" for name,entry in db.items(): if name == '__chosen__': continue txt += f"* {name} - {entry['weight']} weight - {entry['total']} total {'(active)' if entry['active'] else '(inactive)'}\n" say(txt) elif command == "!kill": name = args.strip() if name in db: say(f"Ultimately removing {name} from Kalauer König db (weight: {db[name]['weight']},total: {db[name]['total']}), we will miss you!") del db[name] else: say(f"Cannot delete someone who was never in the kalauer db") self.save_db() elif command == "!kalauer": kalauer = "Wie nennt man einen dicken Vegetarier? Biotonne!" #kalauer = "What do you call a fat vegetarian? Compost bin" translator = Translator() lang = random.choice(list(LANGUAGES)) ret = translator.translate(kalauer,src='de',dest=lang) log.debug(ret) say(f"Your emergency kalauer in {LANGUAGES[lang]}: {ret.text}" ) #needs a newer googletrans if ret.pronunciation: say(f"Pronounced: {ret.pronunciation}") else: log.debug(f"Receive message {msg}") def main(): allowlist = os.environ.get("KALAUER_ALLOWLIST",None) if allowlist: allowlist = allowlist.split(',') bot = Kalauerbot( host = "ext01.citadel.team", display_name = "Kalauerbot", token = os.environ['CITADEL_TOKEN'], user_id = os.environ["CITADEL_ID"], dbpath = os.environ.get("KALAUER_DBPATH",None) or "kalauerdb.json", allowlist = allowlist ) bot.start() if __name__ == "__main__": main()