From 9e96ac1325a6b0b35ab63a10d21e803630af0bd5 Mon Sep 17 00:00:00 2001 From: Five Boroughs Date: Mon, 16 Dec 2019 23:24:02 +0100 Subject: [PATCH] Improve code quality --- README.md | 12 +++---- Twilio2Telegram.py | 62 ++++++++++++++++++-------------- static/Twilio2Telegram_logo.png | Bin 0 -> 8038 bytes 3 files changed, 42 insertions(+), 32 deletions(-) create mode 100644 static/Twilio2Telegram_logo.png diff --git a/README.md b/README.md index 79e743f..4863bba 100644 --- a/README.md +++ b/README.md @@ -1,22 +1,22 @@ -# Twilio2Telegram +# ![Logo](/static/Twilio2Telegram_logo.png) Twilio2Telegram Forward SMS and Calls from your Twilio number to Telegram -## Usage +## Installation ### Clone the repository -`git clone git@github.com:FiveBoroughs/Twilio2Telegram.git` +`git clone git@github.com:FiveBoroughs/Twilio2Telegram.git && cd Twilio2Telegram` ### Set the envirronement variables `cp sample.env .env && vim .env` -Create your bot and obtain the BotToken by following the BotFather instructions : t.me/botfather +Create your bot and obtain the BotToken by following the BotFather instructions : Get the telegram owner and subscribers chat id by talking to the bot in telegram, and watching this url `https://api.telegram.org/bot/getUpdates` -And the Twilio Token from twilio.com/console : hidden behind the "View" button, next to auth token +And the Twilio Token from : hidden behind the "View" button, next to auth token ### Launch the docker container @@ -24,7 +24,7 @@ And the Twilio Token from twilio.com/console : hidden behind the "View" button, ### Set the Twilio webhooks destination -Click on the desired number twilio.com/console/phone-numbers/incoming +Click on the desired number And add the domain or ip of the server hosting Twilio2Telgram, `/call` for calls and `/message` for messages diff --git a/Twilio2Telegram.py b/Twilio2Telegram.py index 8bfc394..de2047a 100644 --- a/Twilio2Telegram.py +++ b/Twilio2Telegram.py @@ -1,21 +1,22 @@ -import os -import logging -from functools import wraps -from flask import Flask, request, abort -from waitress import serve -from twilio.request_validator import RequestValidator -from telegram import ParseMode -from telegram.ext import Updater, CommandHandler +try: + import os + import logging + from functools import wraps + from flask import Flask, request, abort + from waitress import serve + from twilio.request_validator import RequestValidator + from telegram import ParseMode + from telegram.ext import Updater, CommandHandler +except ImportError as err: + print(f"Failed to import required modules: {err}") -# Enable logging +# FB - Enable logging logging.basicConfig( format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', level=logging.INFO) logger = logging.getLogger(__name__) webhook_listener = Flask(__name__) -telegram_bot = None - def validate_twilio_request(f): """Validates that incoming requests genuinely originated from Twilio""" @@ -34,12 +35,14 @@ def validate_twilio_request(f): if request_valid: return f(*args, **kwargs) else: + logger.error('Invalid twilio request, aborting') return abort(403) return decorated_function -def tg_help_handler(update): +def tg_help_handler(update, context): """Send a message when the command /help is issued.""" + logger.info('/help command received in chat: %s', update.message.chat) update.message.reply_markdown( 'Find out more on [Github](https://github.com/FiveBoroughs/Twilio2Telegram)') @@ -51,32 +54,32 @@ def tg_error_handler(update, context): def tg_bot_start(): """Start the telegram bot.""" - # Create the Updater - updater = Updater(os.environ.get('TELEGRAM_BOT_TOKEN')) + # FB - Create the Updater + updater = Updater(os.environ.get('TELEGRAM_BOT_TOKEN'), use_context=True) - # Get the dispatcher to register handlers - dp = updater.dispatcher + # FB - Get the dispatcher to register handlers + dispatcher = updater.dispatcher - # on /help command - dp.add_handler(CommandHandler("help", tg_help_handler)) + # FB - on /help command + dispatcher.add_handler(CommandHandler("help", tg_help_handler)) - # log all errors - dp.add_error_handler(tg_error_handler) + # FB - log all errors + dispatcher.add_error_handler(tg_error_handler) - # Start the Bot + # FB - Start the Bot updater.start_polling() return updater.bot def tg_send_owner_message(message): - """Send telegram to owner.""" + """Send telegram message to owner.""" telegram_bot.sendMessage(text=message, chat_id=os.environ.get( 'TELEGRAM_OWNER'), parse_mode=ParseMode.MARKDOWN) def tg_send_subscribers_message(message): - """Send telegram messages.""" + """Send telegram messages to subscribers.""" for telegram_destination in os.environ.get('TELEGRAM_SUBSCRIBERS').split(','): telegram_bot.sendMessage( text=message, chat_id=telegram_destination, parse_mode=ParseMode.MARKDOWN) @@ -84,14 +87,17 @@ def tg_send_subscribers_message(message): @webhook_listener.route('/', methods=['GET']) def index(): - """Return homepage.""" + """Upon call of homepage.""" + logger.info('"/" reached, IP: %s', request.remote_addr) + return webhook_listener.send_static_file('Index.html') # FB - Message Webhook @webhook_listener.route('/message', methods=['POST']) -# @validate_twilio_request +@validate_twilio_request def recv_message(): """Upon reception of a SMS.""" + logger.info(' "/message" reached, IP: %s', request.remote_addr) # FB - Format telegram Message telegram_message = 'Text from `+{From}` ({Country}, {State}) :``` {Body}```'.format( From=request.values.get('From', 'unknown'), @@ -100,6 +106,7 @@ def recv_message(): Body=request.values.get('Body', 'unknown') ) + logger.info(telegram_message) # FB - Send telegram alerts tg_send_owner_message('Twilio ID : `{Id}`\n'.format( Id=request.values.get('MessageSid', 'unknown')) + telegram_message) @@ -110,9 +117,10 @@ def recv_message(): # FB - Call Webhook @webhook_listener.route('/call', methods=['POST']) -# @validate_twilio_request +@validate_twilio_request def recv_call(): """Upon reception of a call.""" + logger.info(' "/call" reached, IP: %s', request.remote_addr) # FB - Format telegram Message telegram_message = 'Call from `+{From}` ({Country}, {State}) :``` {Status}```'.format( From=request.values.get('From', 'unknown'), @@ -121,6 +129,7 @@ def recv_call(): Status=request.values.get('CallStatus', 'unknown') ) + logger.info(telegram_message) # FB - Send telegram alerts tg_send_owner_message('Twilio ID : `{Id}`\n'.format( Id=request.values.get('CallSid', 'unknown')) + telegram_message) @@ -131,6 +140,7 @@ def recv_call(): if __name__ == "__main__": + logger.info('Starting bot') # FB - Start the telegram bot telegram_bot = tg_bot_start() # FB - Start the website diff --git a/static/Twilio2Telegram_logo.png b/static/Twilio2Telegram_logo.png new file mode 100644 index 0000000000000000000000000000000000000000..8d931fa0318db76f4619e75726027f0fc00cfb38 GIT binary patch literal 8038 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