From d7c43c20cbb46a7f421aa7515a02c01f3c3cd302 Mon Sep 17 00:00:00 2001 From: Dmytro Hoi Date: Sat, 12 Sep 2020 21:29:57 +0300 Subject: [PATCH] Add linking and update bridge --- tg-bridge.pyplugin/config.yml | 63 +++++++----- tg-bridge.pyplugin/plugin.py | 177 +++++++++++++++++++++++++++------- tg-bridge.pyplugin/plugin.yml | 7 +- 3 files changed, 190 insertions(+), 57 deletions(-) diff --git a/tg-bridge.pyplugin/config.yml b/tg-bridge.pyplugin/config.yml index 3ce0cc7..2aff84c 100644 --- a/tg-bridge.pyplugin/config.yml +++ b/tg-bridge.pyplugin/config.yml @@ -1,4 +1,4 @@ -# TelegramBridge v0.0.2 (on PyPlugins https://github.com/pyplugins/pyplugins) +# TelegramBridge v0.1.0 (on PyPlugins https://github.com/pyplugins/pyplugins) # Link: https://github.com/dmytrohoi/tg-bridge-pyplugin # # NOTE: Reload config after changing - /tg-bridge-config reload @@ -6,28 +6,47 @@ ## WARNING: Required fields # Telegram token (https://core.telegram.org/bots#6-botfather) TOKEN: + +## Bridge between Minecraft chat and Telegram group # Server chat Telegram ID (https://stackoverflow.com/questions/32423837/telegram-bot-how-to-get-a-group-chat-id) -CHAT_ID: +bridge: + # Bridge can be disabled but allow notifications (chat_id required) + enable: false + chat_id: -## TEMPLATES NOTE: -# - available HTML tag (https://core.telegram.org/bots/api#html-style) -# - encode <, > and & symbols to HTML entities - < with <, > with > and & with & -# - use
for newline (aka \n) -# - placeholders: {message_text} and {username} (WARNING: only for outcoming_msg_template and outcoming_msg_broadcast_template) -# - Minecraft formating is available for outcoming_msg_broadcast_template and incoming_msg_template (https://minecraft.gamepedia.com/Formatting_codes) -outcoming_msg_template: 'MINECRAFT <{username}>:
{message_text}' -outcoming_msg_broadcast_template: '[ §5Telegram Chat§r §5§l<<§r ] <{username}> {message_text}' -incoming_msg_template: '[ §5Telegram Chat§r §5§l>>§r ] {message_text}' + ## TEMPLATES + # - available HTML tag (https://core.telegram.org/bots/api#html-style) + # - encode <, > and & symbols to HTML entities - < with <, > with > and & with & + # - use
for newline (aka \n) + # - placeholders: {message_text} and {username} (WARNING: only for outcoming_msg_template and outcoming_msg_broadcast_template) + # - Minecraft formating is available for outcoming_msg_broadcast_template and incoming_msg_template (https://minecraft.gamepedia.com/Formatting_codes) + outcoming_msg_template: 'MINECRAFT <{username}>:
{message_text}' + outcoming_msg_broadcast_template: '[ §5Telegram Chat§r §5§l<<§r ] <{username}> {message_text}' + incoming_msg_template: '[ §5Telegram Chat§r §5§l>>§r ] {message_text}' + ## Notifications + # The message will be sent to the Telegram chat when the Server starts or shuts down + # Placeholders: + # {ip} - Server IP and Port + # {motd} - Server MOTD + startup_notification: + enable: true + template: "Server {ip} started!" + shutdown_notification: + enable: true + template: "Server {ip} closed." -## Notifications -# The message will be sent to the Telegram chat when the Server starts or shuts down -# Placeholders: -# {ip} - Server IP and Port -# {motd} - Server MOTD -startup_notification: - enable: true - template: "Server {ip} started!" -shutdown_notification: - enable: true - template: "Server {ip} closed." \ No newline at end of file +## LINKING +# Please implement catching of the inline button in your Telegram Bot +# Button callback_data format: tcp:link:{user_code} +linking: + enable: false + ## Formatting + # - available HTML tag (https://core.telegram.org/bots/api#html-style) + # - encode <, > and & symbols to HTML entities - < with <, > with > and & with & + # - use
for newline (aka \n) + # - placeholders: {username} + message_text_template: "Player with username {username} try to link Minecraft account to this Telegram account" + button_text: "Confirm" + # - please set userid as first parameter in code and separate by ":" + code_validation_regexp: \d+ diff --git a/tg-bridge.pyplugin/plugin.py b/tg-bridge.pyplugin/plugin.py index 7fee4e2..cd97841 100644 --- a/tg-bridge.pyplugin/plugin.py +++ b/tg-bridge.pyplugin/plugin.py @@ -4,26 +4,46 @@ """ Plugin: TelegramBridge (https://github.com/dmytrohoi/tg-bridge-pyplugin) File: plugin.py -Version: 0.0.2 +Version: 0.1.0 Author: hedgehoi (Dmytro Hoi) License: MIT License Dependencies: - - PyPlugins v0.0.1 / https://github.com/pyplugins/pyplugins + - PyPlugins >0.0.1 / https://github.com/pyplugins/pyplugins """ import urllib +import json +import re class TelegramChatCommands(PythonCommandExecutor): commands = [ PyCommand('telegram', 'telegramCommand', 'telegramOnTabComplete'), - PyCommand('telegram-chat-response', 'responseCommand', 'telegramOnTabComplete') + PyCommand('telegram-chat-response', 'responseCommand', 'telegramOnTabComplete'), + PyCommand('link', 'linkCommand', 'linkOnTabComplete') ] def telegramCommand(self, sender, command, label, args): + sender_name = sender.getName() message_text = " ".join(args) + self.plugin.logger.info('{sender} try to send message to Telegram: {message}'.format( + sender=sender_name, + message=message_text + )) + + bridge_section = self.plugin.config.get("bridge") + if not bridge_section \ + or not bridge_section.getBoolean("enable") \ + or not bridge_section.getString("chat_id"): + sender.sendMessage( + self.plugin.placeholder + + " Bridge disabled." + ) + self.plugin.logger.info('Bridge disabled.') + return True + if not message_text: sender.sendMessage( self.plugin.placeholder @@ -31,12 +51,7 @@ def telegramCommand(self, sender, command, label, args): ) return True - self.plugin.logger.info('{sender} try to send message to Telegram: {message}'.format( - sender=sender_name, - message=message_text - )) - - template = self.plugin.config.getString( + template = bridge_section.getString( 'outcoming_msg_template', "{message_text}" ) @@ -55,7 +70,7 @@ def telegramCommand(self, sender, command, label, args): + " Message sent to Telegram Chat." ) - bc_message = self.plugin.config.getString( + bc_message = bridge_section.getString( 'outcoming_msg_broadcast_template', "[ Telegram Chat << ] <{username}> {message_text}" ).format( @@ -91,13 +106,21 @@ def responseCommand(self, sender, command, label, args): ) ) - bc_message = self.plugin.config.getString( + bridge_section = self.plugin.config.get("bridge") + if not bridge_section or not bridge_section.getBoolean("enable"): + self.plugin.logger.info('Bridge not enabled.') + return True + + bc_message = bridge_section.getString( "incoming_msg_template", "[ Telegram Chat >> ] {message_text}" ).format(message_text=message_text) Bukkit.getServer().broadcastMessage(bc_message) - sender.sendMessage(self.plugin.placeholder + " Message sent to Minecraft Chat.") + sender.sendMessage( + self.plugin.placeholder + + " Message sent to Minecraft Chat." + ) return True def telegramOnTabComplete(self, sender, command, alias, args): @@ -106,6 +129,65 @@ def telegramOnTabComplete(self, sender, command, alias, args): else: return [] + def linkCommand(self, sender, command, label, args): + section = self.plugin.config.get("linking") + if not section or not section.getBoolean("enable"): + sender.sendMessage(self.plugin.placeholder + " Linking disabled.") + return True + + if sender.getName() == "CONSOLE": + sender.sendMessage(self.plugin.placeholder + " Command only for player in-game usage") + return True + + if len(args) > 1: + sender.sendMessage( + self.plugin.placeholder + " You sent more than 1 argument with /link command" + ) + return True + elif not len(args): + sender.sendMessage( + self.plugin.placeholder + " To connect Minecraft account and "\ + "Telegram account please go to Server's Telegram bot and "\ + "perform /link command to get start!" + ) + return True + + # User code + code = args[0] + + self.plugin.logger.info( + '{player} try to link Minecraft account to Telegram user with code: {code}'.format( + player=sender.getName(), + code=code + ) + ) + + text = section.getString( + "message_text_template", + "Player with username {username} try to link Minecraft account to this Telegram account" + ).format( + username=sender.getName() + ) + + #Validate code + validation_regex = section.getString("code_validation_regexp") + if validation_regex and not re.match(r'^' + validation_regex + r'$', code): + sender.sendMessage(self.plugin.placeholder + " Invalid code, please check code or call Server Admin.") + return True + + result = self.plugin.sendTelegramMessage(text, button_confirm_code=code) + if result: + sender.sendMessage(self.plugin.placeholder + " Please check your Telegram dialog and confirm linking.") + else: + sender.sendMessage(self.plugin.placeholder + " Somethink went wrong, please check code or call Server Admin.") + return True + + def linkOnTabComplete(self, sender, command, alias, args): + if len(args) == 1: + return [''] + else: + return [] + class TelegramBridgePlugin(PythonPlugin): @@ -117,13 +199,7 @@ def onEnable(self): # Add bStats metrics self.add_bstats(8809) - self.add_configuration( - available_options=[ - "outcoming_msg_template", - "outcoming_msg_broadcast_template", - "incoming_msg_template" - ] - ) + self.add_configuration() self.logger.info("plugin enabled!") bot_token = self.config.getString('TOKEN') @@ -133,24 +209,25 @@ def onEnable(self): "Plugin is not configured, please set TOKEN in config.yml" ) - chat_id = self.config.getString('CHAT_ID') - if not chat_id: - self.logger.warning( - "Plugin is not configured, please set CHAT_ID in config.yml" - ) - # Startup notification - self.notification("startup_notification") + bridge = self.config.get('bridge') + if not bridge or not bridge.getString("chat_id"): + self.logger.warning("Bridge disabled in config.yml") + else: + # Startup notification + self.notification("startup_notification") def onDisable(self): # Shutdown notification - self.notification("shutdown_notification") + bridge = self.config.get('bridge') + if bridge and bridge.getString("chat_id"): + self.notification("shutdown_notification") self.logger.info("plugin disabled!") def notification(self, name): - section = self.config.get(name) + section = self.config.get("bridge").get(name) if not section or (section and not section.getBoolean('enable')): - self.logger.info("{} skipped".format(name)) + self.logger.info("{} disabled.".format(name.replace("_", " ").capitalize())) return self.logger.info("{} option is enabled!".format(name)) @@ -172,14 +249,13 @@ def notification(self, name): ) self.sendTelegramMessage(text) - def sendTelegramMessage(self, text): + def sendTelegramMessage(self, text, button_confirm_code=None): - chat_id = self.config.getString('CHAT_ID') bot_token = self.config.getString('TOKEN') - if not chat_id or not bot_token: + if not bot_token: self.logger.warning( - "Plugin is not configured, please set CHAT_ID and TOKEN in " + "Plugin is not configured, please set TOKEN in " "config.yml" ) return False @@ -187,10 +263,43 @@ def sendTelegramMessage(self, text): # Make data query for url data_options = { 'text': text, - 'chat_id': chat_id, 'parse_mode': 'HTML' } + # Link command + if button_confirm_code: + # Default button text + confirm_button_text = "Confirm linking" + + # Check config + linking_section = self.config.get('linking') + if linking_section and linking_section.getString("button_text"): + confirm_button_text = linking_section.getString("button_text") + + data_options['reply_markup'] = json.dumps({ + "inline_keyboard": [ + [{ + "text": confirm_button_text, + "callback_data": "tcp:link:" + button_confirm_code + }] + ] + }) + user_id = button_confirm_code.split(":")[0] if ":" in button_confirm_code else button_confirm_code + if user_id.startswith("-"): + return False + + data_options["chat_id"] = user_id + else: + bridge_section = self.config.get('bridge') + if not bridge_section or not bridge_section.getString('chat_id'): + self.logger.warning( + "Bridge is not configured, please set 'bridge' > 'chat_id' in " + "config.yml" + ) + return False + + data_options["chat_id"] = bridge_section.getString('chat_id') + # Replace "
" to new line char data = urllib.urlencode(data_options).replace("%3Cbr%2F%3E", "%0A") telegramRequestURL = "https://api.telegram.org/bot{bot_token}/sendMessage?{data}".format( diff --git a/tg-bridge.pyplugin/plugin.yml b/tg-bridge.pyplugin/plugin.yml index 60a2d71..43bca45 100644 --- a/tg-bridge.pyplugin/plugin.yml +++ b/tg-bridge.pyplugin/plugin.yml @@ -1,7 +1,7 @@ name: TelegramBridge main: TelegramBridgePlugin prefix: tg-bridge -version: 0.0.2 +version: 0.1.0 author: hedgehoi website: https://github.com/dmytrohoi/tg-bridge-pyplugin commands: @@ -19,3 +19,8 @@ commands: description: Plugin settings aliases: [tg-config, telegram-config] permission: minecraft.command.op + + link: + description: Link Minecraft account to Telegram account + aliases: tg-link + usage: /<command> <telegram code>