import _thread import os import logging import telebot from telebot import types from pymongo import MongoClient telebot.logger.setLevel(logging.DEBUG) # Bot & config bot = telebot.TeleBot(os.environ['TOKEN']) admin = int(os.environ['ADMIN']) # Acceso a bd client = MongoClient('database:27017') db = client.bot tests = db.tests users = db.users # Funciones de utilidad def is_user(cid): return users.find_one(str(cid)) is not None def add_user(cid): users.insert_one({ "_id": str(cid), "taken_tests": [], "current_tests": [] }) def restart_process(): _thread.interrupt_main() def is_admin(cid): return str(cid) == str(admin) def split(a, n): k, m = divmod(len(a), n) return (a[i*k+min(i, m):(i+1)*k+min(i+1, m)] for i in range(n)) def find_question(test, question): questions = tests.find_one({'test': int(test)}, {'preguntas':{'$elemMatch': {'pregunta': int(question)}}, '_id':0}) if questions: return questions['preguntas'][0] return {} def generate_tests_keyboard(): keyboard = types.InlineKeyboardMarkup(row_width=4) buttons = [] for test in tests.find({},{'test':1, '_id':0}): buttons.append(types.InlineKeyboardButton('Test {}'.format(test['test']-100), callback_data='test {}'.format(test['test']))) for chunk in split(buttons, 4): keyboard.add(*chunk) return keyboard def generate_test_keyboard(question, test): keyboard = types.InlineKeyboardMarkup() for i,answer in enumerate(question.get('respuestas')): keyboard.add(types.InlineKeyboardButton('{}'.format(answer['texto']), callback_data='pregunta {} {} {}'.format(test, question['pregunta'], i))) next_prev_buttons = [] if question.get('pregunta') == 1: next_prev_buttons.append(types.InlineKeyboardButton('⏩', callback_data='pregunta {} {} +'.format(test, question['pregunta']))) elif question.get('pregunta') == 20: next_prev_buttons.append(types.InlineKeyboardButton('⏪', callback_data='pregunta {} {} -'.format(test, question['pregunta']))) else: next_prev_buttons.append(types.InlineKeyboardButton('⏪', callback_data='pregunta {} {} -'.format(test, question['pregunta']))) next_prev_buttons.append(types.InlineKeyboardButton('⏩', callback_data='pregunta {} {} +'.format(test, question['pregunta']))) keyboard.add(*next_prev_buttons) return keyboard # Manejadores de comandos @bot.message_handler(commands=['start']) def start_handler(m): cid = m.chat.id if not is_user(cid): add_user(cid) bot.send_message(cid, "Bienvenid@") @bot.message_handler(commands=['reload']) def reload_handler(m): cid = m.chat.id if is_admin(cid): restart_process() @bot.message_handler(commands=['tests']) def tests_handler(m): cid = m.chat.id keyboard = generate_tests_keyboard() bot.send_message(cid, "Haz click en un test para empezar a resolverlo", reply_markup=keyboard) @bot.callback_query_handler(func=lambda call: call.data.startswith('test')) def test_callback_handler(call): cid = call.message.chat.id test = call.data.split()[-1] question = find_question(test, 1) keyboard = generate_test_keyboard(question, test) txt = "Test: {}\nPregunta: {}\n\n{}" bot.send_photo(cid, question.get('img'), caption=txt.format(test, 1, question['encabezado']), reply_markup=keyboard) # TODO: Añadir el test a current_tests del usuario bot.answer_callback_query(call.id) @bot.callback_query_handler(func=lambda call: call.data.startswith('pregunta') and (call.data.endswith('+') or call.data.endswith('-'))) def question_answer_callback_handler(call): cid = call.message.chat.id mid = call.message.id _, test, q, option = call.data.split() question = find_question(test, int(q)+1) keyboard = generate_test_keyboard(question, test) txt = "Test: {}\nPregunta: {}\n\n{}" @bot.callback_query_handler(func=lambda call: call.data.startswith('pregunta') and (call.data.endswith('+') or call.data.endswith('-'))) def question_pager_callback_handler(call): cid = call.message.chat.id mid = call.message.id _, test, q, action = call.data.split() question = find_question(test, eval(q+action+'1')) keyboard = generate_test_keyboard(question, test) txt = "Test: {}\nPregunta: {}\n\n{}" try: bot.edit_message_media(types.InputMediaPhoto(question.get('img'), caption=txt.format(test, question['pregunta'], question['encabezado'])), cid, mid, reply_markup=keyboard) bot.answer_callback_query(call.id) except: bot.answer_callback_query(call.id, "No se pudo cargar la pregunta") # Iniciar bot bot.send_message(admin, "Reiniciado") bot.polling(skip_pending=True)