Initial commit
This commit is contained in:
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
*json
|
||||||
6
Dockerfile
Normal file
6
Dockerfile
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
FROM python:3.8-alpine
|
||||||
|
WORKDIR /usr/src/app
|
||||||
|
COPY ./requirements.txt .
|
||||||
|
RUN pip3 install --no-cache-dir -r requirements.txt
|
||||||
|
COPY . ./
|
||||||
|
CMD ["python", "bot.py"]
|
||||||
132
bot.py
Normal file
132
bot.py
Normal file
@ -0,0 +1,132 @@
|
|||||||
|
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)
|
||||||
23
docker-compose.yml
Normal file
23
docker-compose.yml
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
version: '3'
|
||||||
|
|
||||||
|
services:
|
||||||
|
bot:
|
||||||
|
build:
|
||||||
|
context: .
|
||||||
|
dockerfile: Dockerfile
|
||||||
|
restart: unless-stopped
|
||||||
|
environment:
|
||||||
|
- TOKEN=$TOKEN
|
||||||
|
- ADMIN=52033876
|
||||||
|
volumes:
|
||||||
|
- ./:/usr/src/app
|
||||||
|
depends_on:
|
||||||
|
- database
|
||||||
|
database:
|
||||||
|
image: "mvertes/alpine-mongo"
|
||||||
|
restart: unless-stopped
|
||||||
|
volumes:
|
||||||
|
- db:/data/db
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
db: {}
|
||||||
3
requirements.txt
Normal file
3
requirements.txt
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
pytelegrambotapi
|
||||||
|
pymongo
|
||||||
|
requests
|
||||||
Reference in New Issue
Block a user