def route_callback_query(plugins, get_me, config, http, callback_query): """ Routes a callback query to the appropriate plugin. Callback data is stored in mysql. https://core.telegram.org/bots/api#callbackquery """ database = MySQLdb.connect(**config['DATABASE']) data = callback_query['data'] query = 'SELECT plugin_name, plugin_data FROM callback_queries WHERE callback_data="{}"' database.query(query.format(data)) query = database.store_result() rows = query.fetch_row(how=1, maxrows=0) for db_result in rows: plugin_name = db_result['plugin_name'] plugin_data = json.loads( db_result['plugin_data']) if db_result['plugin_data'] else None if 'message' in callback_query: api_object = TelegramApi(database, get_me, plugin_name, config, http, plugin_data=plugin_data, callback_query=callback_query) else: api_object = InlineCallbackQuery(database, config, http, callback_query) try: plugins[plugin_name].main(api_object) except Exception: api_object = TelegramApi(database, get_me, plugin_name, config, http) send_error_report(data, traceback.format_exc(), api_object) database.commit() database.close()
def check_time_args(): """ Continuously checks the MySQL database for time arguments and runs the relevant plugin. Creates a different api_object depending on whether it was initialized with a standard message or callback query. """ database = MySQLdb.connect(**CONFIG['DATABASE']) cursor = database.cursor() flagged_time_http = urllib3.PoolManager(cert_reqs='CERT_REQUIRED', ca_certs=certifi.where()) flagged_time_http.timeout = urllib3.Timeout(connect=1.0) flagged_time_http.retries = 3 while RUNNING.value: database.query( "SELECT time_id, plugin_name,plugin_data,previous_message FROM flagged_time WHERE " "argument_time <= from_unixtime({})".format(int(time.time()))) query = database.store_result() rows = query.fetch_row(how=1, maxrows=0) for result in rows: time_id = result['time_id'] plugin_name = result['plugin_name'] if result['plugin_data']: plugin_data = json.loads(result['plugin_data']) else: plugin_data = None previous_message = json.loads(result['previous_message']) previous_message['time_id'] = time_id if 'message_id' in previous_message: api_object = TelegramApi(database, GET_ME, plugin_name, CONFIG, flagged_time_http, message=previous_message, plugin_data=plugin_data) else: api_object = TelegramApi(database, GET_ME, plugin_name, CONFIG, flagged_time_http, callback_query=previous_message, plugin_data=plugin_data) cursor.execute('DELETE FROM `flagged_time` WHERE time_id=%s;', (time_id, )) try: PLUGINS[plugin_name].main(api_object) except KeyError: continue database.commit() time.sleep(SLEEP_TIME) database.close()
def run_plugin(self, plugin_name, plugin_module, message): """ Inits a plugin with its own DB and commits/closes it after. Wrapped for concurrent.futures """ database = MySQLdb.connect(**self.config['DATABASE']) api_object = TelegramApi(database, self.get_me, plugin_name, self.config, self.http, message) try: plugin_module.main(api_object) except Exception: message = "<code>{}</code>".format(clean_text(traceback.format_exc())) api_object.admin_alert(message, forward_message=True) database.commit() database.close()
def check_db_reply(self): """ Checks if the recieved message is a reply to a message flagged by a plugin. If not it then runs the standard handle_plugins check. """ chat_id = self.message['chat']['id'] message_id = self.message['reply_to_message']['message_id'] self.database.query( "SELECT plugin_name, user_id, single_use, currently_active, plugin_data " "FROM flagged_messages WHERE message_id={} AND chat_id={};".format( message_id, chat_id)) query = self.database.store_result() rows = query.fetch_row(how=1, maxrows=0) for result in rows: if result['user_id'] and result['user_id'] != self.message['from'][ 'id']: return False if result['single_use']: self.cursor.execute( "DELETE FROM flagged_messages WHERE message_id=%s", (message_id, chat_id)) self.message['flagged_message'] = True plugin_data = json.loads( result['plugin_data']) if result['plugin_data'] else None api_object = TelegramApi(self.database, self.get_me, result['plugin_name'], self.config, self.http, self.message, plugin_data) self.plugins[result['plugin_name']].main(api_object) self.database.commit() if not rows: self.handle_plugins()
def check_db_pm(self): """ Checks if there is a currently active flagged_message in the chat where the message was sent. In a private chat it is not necessary to reply to the flagged message for it to trigger. """ chat_id = self.message['chat']['id'] self.database.query( "SELECT plugin_name, single_use, message_id, plugin_data FROM flagged_messages WHERE " "chat_id={} AND currently_active=1".format(chat_id)) query = self.database.store_result() rows = query.fetch_row(how=1, maxrows=0) if query else list() for result in rows: message_id = result["message_id"] if result['single_use']: self.cursor.execute( "DELETE FROM flagged_messages WHERE message_id=%s AND chat_id=%s", (chat_id, message_id)) plugin_data = json.loads( result['plugin_data']) if result['plugin_data'] else None self.message['flagged_message'] = True self.cursor.execute( "UPDATE flagged_messages SET currently_active=FALSE WHERE chat_id=%s", (chat_id, )) self.database.commit() self.plugins[result['plugin_name']].main( TelegramApi(self.database, self.get_me, result['plugin_name'], self.config, self.http, self.message, plugin_data))
def run_plugin(self, plugin_name, plugin_module, message): """ Inits a plugin with its own DB and commits/closes it after. Wrapped for concurrent.futures """ database = MySQLdb.connect(**self.config['DATABASE']) api_object = TelegramApi(database, self.get_me, plugin_name, self.config, self.http, message) try: plugin_module.main(api_object) except Exception: message = "<code>{}</code>".format( clean_text(traceback.format_exc())) api_object.admin_alert(message, forward_message=True) database.commit() database.close()
def plugin_check(self): plugin_triggered = False for plugin in self.plugins: for key, value in plugin.arguments.items(): if self.check_argument(key, value, self.message): plugin_triggered = True plugin.main( TelegramApi(self.message, self.misc, self.plugins, self.database, plugin_id=self.plugins.index(plugin)) ) return plugin_triggered
def route_callback_query(callback_query, database, plugins, misc): if int(time.time()) - int(callback_query['message']['date']) >= 30: return db_selection = database.select("callback_queries", ["DISTINCT plugin_id", "plugin_data", "data"], {"data": callback_query['data']}) for db_result in db_selection: plugin_id = db_result['plugin_id'] plugin_data = json.loads(db_result['plugin_data']) if db_result['plugin_data'] else None api_obj = TelegramApi(misc, database, plugin_id, plugin_data=plugin_data, callback_query=callback_query) plugins[plugin_id].main(api_obj)
def route_inline_query(plugins, get_me, config, http, inline_query): """ Routes inline arguments to the appropriate plugin. Only the first match runs. https://core.telegram.org/bots/api#inlinequery """ default_plugin = config['BOT_CONFIG']['default_inline_plugin'] query = str(inline_query['query']) for plugin_name, plugin in plugins.items(): if hasattr(plugin, 'inline_arguments'): for argument in plugin.inline_arguments: match = re.findall(str(argument), query) if match: database = MySQLdb.connect(**config['DATABASE']) inline_query['matched_regex'] = argument inline_query['match'] = match[0] try: plugin.main( TelegramInlineAPI(database, get_me, plugin_name, config, http, inline_query)) except Exception: api_object = TelegramApi(database, get_me, plugin_name, config, http) send_error_report(query, traceback.format_exc(), api_object) database.commit() database.close() return if default_plugin: database = MySQLdb.connect(**config['DATABASE']) inline_query['matched_regex'] = None inline_query['match'] = inline_query['query'] try: plugins[default_plugin].main( TelegramInlineAPI(database, get_me, plugin_name, config, http, inline_query)) except Exception: api_object = TelegramApi(database, get_me, plugin_name, config, http) send_error_report(query, traceback.format_exc(), api_object) database.commit() database.close()
def plugin_check(self): if int(time.time()) - int(self.message['date']) >= 180: return False plugin_triggered = False for plugin in self.plugins: for key, value in plugin.arguments.items(): if self.check_argument(key, value, self.message): plugin_triggered = True plugin.main( TelegramApi(self.misc, self.database, self.plugins.index(plugin), self.message) ) return plugin_triggered
def check_db(self): chat_id = self.message['chat']['id'] if 'text' in self.message: self.message['text'] = util.clean_message(self.message['text'], self.misc['bot_info']['username']) if 'reply_to_message' in self.message: message_id = self.message['reply_to_message']['message_id'] db_selection = self.database.select("flagged_messages", ["plugin_id", "user_id", "single_use", "currently_active"], {"message_id": message_id, "chat_id": chat_id}) if db_selection: for result in db_selection: if result['user_id'] and result['user_id'] != self.message['from']['id']: return True if result['single_use']: self.database.delete('flagged_messages', {'message_id': message_id, 'chat_id': chat_id}) self.message['flagged_message'] = True self.plugins[result['plugin_id']].main( TelegramApi(self.message, self.misc, self.plugins, self.database, result['plugin_id'])) return False if self.message['chat']['type'] == 'private': if self.plugin_check(): return False db_selection = self.database.select("flagged_messages", ["plugin_id", "single_use", "message_id"], {"chat_id": chat_id, "currently_active": True}) if db_selection: for result in db_selection: message_id = result["message_id"] if result['single_use']: self.database.delete('flagged_messages', {'message_id': message_id, 'chat_id': chat_id}) self.message['flagged_message'] = True self.plugins[result['plugin_id']].main( TelegramApi(self.message, self.misc, self.plugins, self.database, result['plugin_id']) ) self.database.update("flagged_messages", {"currently_active": False}, {"chat_id": chat_id}) return False return True
def check_time_args(): global extensions time_args = database.select("flagged_time", ["plugin_id", "time", "plugin_data"]) for argument in time_args: # See if any plugins want to be activated at this time if argument['time'] <= time.time(): plugin_id = argument['plugin_id'] plugin_data = json.loads( argument['plugin_data']) if argument['plugin_data'] else None tg = TelegramApi(misc, database, plugin_id, plugin_data=plugin_data) plugins[plugin_id].main(tg) database.delete("flagged_time", argument)
def check_pm_parameters(self): """ Retrieves payload from pm_parameters and sends to relevant plugin https://core.telegram.org/bots/#deep-linking """ if 'text' not in self.message: return match = re.findall("^/start (.*)", self.message['text']) if match: self.message['pm_parameter'] = match[0] self.database.query('SELECT plugin_name FROM pm_parameters WHERE parameter="{}"'.format(match[0])) query = self.database.store_result() result = query.fetch_row() for plugin in result: api_object = TelegramApi(self.database, self.get_me, plugin[0], self.config, self.http, self.message) self.plugins[plugin[0]].main(api_object) return True if result else False
def check_db_reply(self): chat_id = self.message['chat']['id'] message_id = self.message['reply_to_message']['message_id'] db_selection = self.database.select("flagged_messages", ["DISTINCT plugin_id", "user_id", "single_use", "currently_active", "plugin_data"], {"message_id": message_id, "chat_id": chat_id}) if db_selection: for result in db_selection: if result['user_id'] and result['user_id'] != self.message['from']['id']: return True if result['single_use']: self.database.delete('flagged_messages', {'message_id': message_id, 'chat_id': chat_id}) self.message['flagged_message'] = True if result['plugin_data']: plugin_data = json.loads(result['plugin_data']) else: plugin_data = None self.plugins[result['plugin_id']].main( TelegramApi(self.misc, self.database, result['plugin_id'], self.message, plugin_data)) return True
def get_update(self): # Gets new messages and sends them to plugin_handler url = "{}{}getUpdates?offset={}".format(self.misc['base_url'], self.misc['token'], self.update_id) response = util.fetch(url, self.misc['session']) try: response = response.json() except AttributeError: time.sleep(5) return if response['ok']: try: self.update_id = response['result'][-1]['update_id'] + 1 except IndexError: time.sleep(self.config.sleep) return with concurrent.futures.ThreadPoolExecutor(max_workers=5) as e: for i in response['result']: if self.time - int(i['message']['date']) <= 180000: e.submit(self.route_message, TelegramApi(i['message'], self.misc)) time.sleep(self.config.sleep) else: print('Error fetching new messages:\nCode: {}'.format(response['error_code'])) time.sleep(self.config.sleep)
def run_plugin(self, plugin_name, plugin_module, message): """ Inits a plugin with its own DB and commits/closes it after. Wrapped for concurrent.futures """ database = MySQLdb.connect(**self.config['DATABASE']) api_object = TelegramApi(database, self.get_me, plugin_name, self.config, self.http, message) try: plugin_module.main(api_object) except Exception: admin_list = self.config['BOT_CONFIG']['admins'].split(',') for admin_id in admin_list: message = "<code>{}</code>".format(traceback.format_exc()) api_object.forward_message(admin_id) api_object.send_message(message, chat_id=admin_id) database.commit() database.close()
def check_db_pm(self): if self.plugin_check(): return chat_id = self.message['chat']['id'] db_selection = self.database.select("flagged_messages", ["DISTINCT plugin_id", "single_use", "message_id", "plugin_data"], {"chat_id": chat_id, "currently_active": True}) if db_selection: for result in db_selection: message_id = result["message_id"] if result['single_use']: self.database.delete('flagged_messages', {'message_id': message_id, 'chat_id': chat_id}) if result['plugin_data']: plugin_data = json.loads(result['plugin_data']) else: plugin_data = None self.message['flagged_message'] = True self.database.update("flagged_messages", {"currently_active": False}, {"chat_id": chat_id}) self.plugins[result['plugin_id']].main( TelegramApi(self.misc, self.database, result['plugin_id'], self.message, plugin_data) )