diff --git a/Pipfile b/Pipfile index ce28a43..022e6ee 100644 --- a/Pipfile +++ b/Pipfile @@ -17,6 +17,7 @@ twitterscraper = "*" httpx = "*" PyYAML = "==5.3" wolframalpha = "*" +Mastodon-py = "*" [dev-packages] pylint = "*" diff --git a/README.md b/README.md index c156787..e1afbf2 100644 --- a/README.md +++ b/README.md @@ -359,6 +359,28 @@ bot ownership) If enabled, Jitsi calls created with Matrix clients will be sent as text messages to rooms, allowing non-matrix users to join them. +Note: Currently supports only calls placed from Element Web. Android version +sends different messages and has not yet been reverse engineered. + +### Mastodon + +Send toots to Mastodon. You can login to Mastodon with the bot and toot with it. Login is +personal - it's mapped to your Matrix ID. You can limit usage to bot owners only or make +it public. + +Commands: + +* !md status - print status of mastodon module +* !md login [instanceurl] [e-mail] [password] - log in your Matrix user to mastodon instance (do in private chat!) +* !md toot [toot] - send a toot message +* !md logout - log out the user from the bot +* !md setpublic - ANY user can use login command to login and use the Mastodon module (must be done as bot owner) +* !md setprivate - Only bot owners can use Mastodon module (default) (must be done as bot owner) + +Example of login command: + +* !md login https://my.instance/ me@email.invalid r00tm3 + ## Bot setup * Create a Matrix user diff --git a/modules/md.py b/modules/md.py new file mode 100644 index 0000000..3b78fbc --- /dev/null +++ b/modules/md.py @@ -0,0 +1,91 @@ +from mastodon import Mastodon + +from modules.common.module import BotModule + + +class MatrixModule(BotModule): + apps = dict() # instance url <-> [app_id, app_secret] + logins = dict() # mxid <-> [username, accesstoken, instanceurl] + public = False + + async def matrix_message(self, bot, room, event): + args = event.body.split() + args.pop(0) + if len(args) >= 1: + if args[0] == "toot": + if not self.public: + bot.must_be_owner(event) + toot_body = " ".join(args[1:]) + if event.sender in self.logins.keys(): + username = self.logins[event.sender][0] + accesstoken = self.logins[event.sender][1] + instanceurl = self.logins[event.sender][2] + toottodon = Mastodon( + access_token = accesstoken, + api_base_url = instanceurl + ) + tootdict = toottodon.toot(toot_body) + print(tootdict) + await bot.send_text(room, tootdict['url']) + else: + await bot.send_text(room, f'{event.sender} has not logged in yet with the bot. Please do so.') + return + + if len(args) == 4: + if args[0] == "login": + if not self.public: + bot.must_be_owner(event) + mxid = event.sender + instanceurl = args[1] + username = args[2] + password = args[3] + if not instanceurl in self.apps.keys(): + app = Mastodon.create_app(f'Hemppa The Bot - {bot.client.user}', api_base_url = instanceurl) + self.apps[instanceurl] = [app[0], app[1]] + bot.save_settings() + await bot.send_text(room, f'Registered Mastodon app on {instanceurl}') + + mastodon = Mastodon(client_id = self.apps[instanceurl][0], client_secret = self.apps[instanceurl][1], api_base_url = instanceurl) + access_token = mastodon.log_in(username, password) + self.logins[mxid] = [username, access_token, instanceurl] + bot.save_settings() + await bot.send_text(room, f'Logged into {instanceurl} as {username}') + return + if len(args) == 1: + if args[0] == "status": + await bot.send_text(room, f'{len(self.logins)} users logged in, app registered on {len(self.apps)} instances, public use enabled: {self.public}') + if args[0] == "logout": + if event.sender in self.logins.keys(): + # TODO: Is there a way to invalidate the access token with API? + del self.logins[event.sender] + bot.save_settings() + await bot.send_text(room, f'{event.sender} login data removed from the bot.') + if args[0] == "setpublic": + bot.must_be_owner(event) + self.public = True + bot.save_settings() + await bot.send_text(room, f'Mastodon usage is now public use') + if args[0] == "setprivate": + bot.must_be_owner(event) + self.public = False + bot.save_settings() + await bot.send_text(room, f'Mastodon usage is now restricted to bot owners') + + def get_settings(self): + data = super().get_settings() + data['apps'] = self.apps + data['logins'] = self.logins + data['public'] = self.public + return data + + def set_settings(self, data): + super().set_settings(data) + if data.get("apps"): + self.apps = data["apps"] + if data.get("logins"): + self.logins = data["logins"] + if data.get("public"): + self.public = data["public"] + + def help(self): + return ('Mastodon')