def answer_photo_message(message: Message) -> None: """ Handles situations when user sends a photo as a photo not as a file, namely answers to him that he need to send his photo as a file :param message: Message objects from Telebot that contains all the data about user's message :return: none """ user = users.find_one(message) bot.send_message(user.chat_id, messages[user.language]['as_file']) log.info('%s sent photo as a photo.', user)
def create_main_keyboard(message: Message) -> None: """ Creates and renders the main keyboard :param message: message from a user :return: None """ user = users.find_one(message) current_user_lang = user.language markup = types.ReplyKeyboardMarkup(one_time_keyboard=True, resize_keyboard=True) markup.row('Русский/English') markup.row(messages[current_user_lang]['top_cams']) markup.row(messages[current_user_lang]['top_lens']) markup.row(messages[current_user_lang]['top_countries']) bot.send_message(user.chat_id, messages[current_user_lang]['menu_header'], reply_markup=markup)
def find_one(self, message: Message) -> User: """ Look up a user by a message which we get together with request from Telegram :param message: object from Telegram that contains info about user's message and about himself :return: user object that represents a Telegram user in this bot """ # look up user in the cache of the bot user = self.users.get(message.chat.id, None) if user: return user # otherwise look up the user in the database log.debug("Looking up the user in the database as it doesn't " "appear in cache") query = (f'SELECT first_name, nickname, last_name, language ' f'FROM users ' f'WHERE chat_id=%s') parameters = message.chat.id, try: cursor = db.execute_query(query, parameters) except DatabaseConnectionError: # Even if the database in unreachable add user to dictionary # with users otherwise the bot will crash requesting this # user's info log.error('Cannot lookup the user with chat_id %d in database', message.chat.id) msg = message.from_user user = self.add_new_one(message.chat.id, msg.first_name, msg.last_name, msg.username, language='en-US', add_to_db=False) return user if not cursor.rowcount: # This user uses our photoGPSbot for the first time as we # can't find him in the database log.info('Adding totally new user to the system...') msg = message.from_user user = self.add_new_one(message.chat.id, msg.first_name, msg.last_name, msg.username, language='en-US') bot.send_message(config.MY_TELEGRAM, text=f'You have a new user! {user}') log.info('You have a new user! Welcome %s', user) # finally if the user wasn't found in the cache of the bot, but was # found in the database else: log.debug('User %d has been found in the database', message.chat.id) user_data = cursor.fetchall()[0] user = self.add_new_one(message.chat.id, *user_data, add_to_db=False) return user
def get_most_popular_items(item_type: str, message: Message) -> str: """ Get the most common cameras/lenses/countries from database and make list of them :param item_type: string with column name to choose between cameras, lenses and countries :param message: telebot object with info about user and his message :return: string which is either list of most common cameras/lenses/countries or message which states that list is empty """ user = users.find_one(message) def tuple_to_ordered_str_list(list_of_gadgets: Tuple[Tuple[str]]) -> str: """ Converts Python list to ordered list as a string Example: 1. Canon 80D 2. iPhone 4S :param list_of_gadgets: tuple of tuples with string where every string is a name of a camera or lens or a country :return: ordered list as a string """ string_roaster = '' index = 1 for item in list_of_gadgets: if not item[0]: continue string_roaster += '{}. {}\n'.format(index, item[0]) index += 1 return string_roaster log.debug('Evaluating most popular things...') # This query returns item types in order where the first one item # has the highest number of occurrences # in a given column query = (f'SELECT {item_type} FROM photo_queries_table2 ' f'GROUP BY {item_type} ' f'ORDER BY count({item_type}) ' 'DESC') try: cursor = db.execute_query(query) except DatabaseConnectionError: log.error("Can't evaluate a list of the most popular items") return messages[user.language]['doesnt work'] # Almost impossible case but still if not cursor.rowcount: log.warning('There is nothing in the main database table') bot.send_message(chat_id=config.MY_TELEGRAM, text='There is nothing in the main database table') return messages[user.language]['no_top'] popular_items = cursor.fetchall() log.info('Finish evaluating the most popular items') return tuple_to_ordered_str_list(popular_items[:30])
def admin_menu(call: CallbackQuery) -> None: """ Respond to commands from the admin menu :param call: object that contains info about user's reaction to an interactive keyboard :return: None """ # Remove progress bar from pressed button bot.answer_callback_query(callback_query_id=call.id, show_alert=False) if call.data == 'off': if db.disconnect(): bot.turn_off() else: log.error('Cannot stop bot.') bot.send_message(chat_id=config.MY_TELEGRAM, text='Cannot stop bot.') elif call.data == 'last active': bot.send_message(config.MY_TELEGRAM, text=get_admin_stat('last active users')) elif call.data == 'total number photos sent': bot.send_message(config.MY_TELEGRAM, text=get_admin_stat('total number photos sent')) elif call.data == 'photos today': bot.send_message(config.MY_TELEGRAM, text=get_admin_stat('photos today')) elif call.data == 'number of users': bot.send_message(config.MY_TELEGRAM, text=get_admin_stat('number of users')) elif call.data == 'number of gadgets': bot.send_message(config.MY_TELEGRAM, text=get_admin_stat('number of gadgets')) elif call.data == 'uptime': bot.send_message(config.MY_TELEGRAM, text=get_admin_stat('uptime'))
def handle_menu_response(message: Message) -> None: """ Function that handles user's respond to the main keyboard :param message: user's message :return: None """ # keyboard_hider = telebot.types.ReplyKeyboardRemove() current_user_lang = users.find_one(message).language user = users.find_one(message) if message.text == 'Русский/English': new_lang = users.find_one(message).switch_language() if current_user_lang != new_lang: bot.send_message(user.chat_id, messages[new_lang] ['switch_lang_success']) create_main_keyboard(message) else: bot.send_message(user.chat_id, messages[new_lang] ['switch_lang_failure']) create_main_keyboard(message) elif message.text == messages[current_user_lang]['top_cams']: log.info('User %s asked for top cams', user) bot.send_message(user.chat_id, text=get_most_popular_items(item_type='camera_name', message=message)) log.info('List of most popular cameras ' 'has been returned to %s', user) # in order not to check whether user has changed his nickname or # whatever every time his sends any request the bot will just check # it every time a user wants to get a statistic about the most # popular cameras users.compare_and_update(user, message) elif message.text == messages[current_user_lang]['top_lens']: log.info('User %s asked for top lens', user) bot.send_message(user.chat_id, text=get_most_popular_items(item_type='lens_name', message=message)) log.info('List of most popular lens has been returned to %s', user) elif message.text == messages[current_user_lang]['top_countries']: log.info('User %s asked for top countries', user) lang_table_name = ('country_ru' if current_user_lang == 'ru-RU' else 'country_en') bot.send_message(user.chat_id, text=get_most_popular_items(item_type=lang_table_name, message=message)) log.info('List of most popular countries has ' 'been returned to %s', user) elif (message.text.lower() == 'admin' and user.chat_id == int(config.MY_TELEGRAM)): # Creates inline keyboard with options for admin Function that handle # user interaction with the keyboard called admin_menu keyboard = types.InlineKeyboardMarkup() # Make keyboard object button = types.InlineKeyboardButton # just an alias to save space keyboard.add(button(text='Turn bot off', callback_data='off')) keyboard.add(button(text='Last active users', callback_data='last active')) keyboard.add(button(text='Total number of photos were sent', callback_data='total number photos sent')) keyboard.add(button(text='Number of photos today', callback_data='photos today')) keyboard.add(button(text='Number of users', callback_data='number of users')) keyboard.add(button(text='Number of gadgets', callback_data='number of gadgets')) keyboard.add(button(text='Uptime', callback_data='uptime')) bot.send_message(config.MY_TELEGRAM, 'Admin commands', reply_markup=keyboard) else: log.info('%s sent text message.', user) # Answer to user that bot can't make a conversation with him bot.send_message(user.chat_id, messages[current_user_lang]['dont_speak'])