diff --git a/src/pycamp_bot/commands/manage_pycamp.py b/src/pycamp_bot/commands/manage_pycamp.py index 61f2e2d..4df2be9 100644 --- a/src/pycamp_bot/commands/manage_pycamp.py +++ b/src/pycamp_bot/commands/manage_pycamp.py @@ -152,6 +152,7 @@ async def define_duration(update, context): chat_id=update.message.chat_id, text=msg ) + return ConversationHandler.END async def cancel(update, context): diff --git a/src/pycamp_bot/commands/projects.py b/src/pycamp_bot/commands/projects.py index 035f508..76d2ad6 100644 --- a/src/pycamp_bot/commands/projects.py +++ b/src/pycamp_bot/commands/projects.py @@ -1,6 +1,7 @@ import logging import peewee -from telegram.ext import ConversationHandler, CommandHandler, MessageHandler, filters +from telegram import InlineKeyboardButton, InlineKeyboardMarkup +from telegram.ext import CallbackQueryHandler, ConversationHandler, CommandHandler, MessageHandler, filters from pycamp_bot.models import Pycampista, Project, Slot, Vote from pycamp_bot.commands.base import msg_to_active_pycamp_chat from pycamp_bot.commands.manage_pycamp import active_needed, get_active_pycamp @@ -10,7 +11,15 @@ current_projects = {} -NOMBRE, DIFICULTAD, TOPIC = ["nombre", "dificultad", "topic"] + +NOMBRE = "nombre" +DIFICULTAD = "dificultad" +TOPIC = "topic" +CHECK_REPOSITORIO = "check_repositorio" +REPOSITORIO = "repositorio" + +REPO_EXISTS_PATTERN = 'repoexists' +PROJECT_NAME_PATTERN = 'projectname' logger = logging.getLogger(__name__) @@ -57,7 +66,11 @@ async def naming_project(update, context): username = update.message.from_user.username name = update.message.text + user = Pycampista.get_or_create(username=username, chat_id=update.message.chat_id)[0] + new_project = Project(name=name) + new_project.owner = user + current_projects[username] = new_project await context.bot.send_message( @@ -118,26 +131,81 @@ async def project_topic(update, context): new_project = current_projects[username] new_project.topic = text - chat_id = update.message.chat_id - user = Pycampista.get_or_create(username=username, chat_id=chat_id)[0] + await context.bot.send_message( + chat_id=update.message.chat_id, + text="Excelente {}! La temática de tu proyecto es: {}.".format(username, text) + ) + + keyboard = [ + [ + InlineKeyboardButton("Sí", callback_data=f"{REPO_EXISTS_PATTERN}:si"), + InlineKeyboardButton("No", callback_data=f"{REPO_EXISTS_PATTERN}:no"), + ] + ] + reply_markup = InlineKeyboardMarkup(keyboard) + + await context.bot.send_message( + chat_id=update.message.chat_id, + text="¿Existe un repositorio para tu proyecto?", + reply_markup=reply_markup, + ) + + return CHECK_REPOSITORIO + + +async def save_project(username, chat_id, context): + '''Save project to database''' + new_project = current_projects[username] - new_project.owner = user try: new_project.save() except peewee.IntegrityError: await context.bot.send_message( - chat_id=update.message.chat_id, + chat_id=chat_id, text="Ups ese proyecto ya fue cargado" ) + else: + await context.bot.send_message( + chat_id=chat_id, + text="Tu proyecto ha sido cargado" + ) + + +async def ask_if_repository_exists(update, context): + '''Dialog to ask if a repository exists''' + callback_query = update.callback_query + chat = callback_query.message.chat + + if callback_query.data.split(':')[1] == "si": + await context.bot.send_message( + chat_id=chat.id, + text="¿Cuál es la URL del repositorio?", + ) + return REPOSITORIO + else: + await context.bot.send_message( + chat_id=chat.id, + text="Si creás un repositorio, podés agregarlo con /agregar_repositorio." + ) + await save_project(callback_query.from_user.username, chat.id, context) return ConversationHandler.END + +async def project_repository(update, context): + '''Dialog to set project repository''' + username = update.message.from_user.username + text = update.message.text + + new_project = current_projects[username] + new_project.repository_url = text + await context.bot.send_message( chat_id=update.message.chat_id, - text="Excelente {}! La temática de tu proyecto es: {}.".format(username, text)) - await context.bot.send_message( - chat_id=update.message.chat_id, - text="Tu proyecto ha sido cargado" + text=f"El repositorio de tu proyecto es: {text}." ) + + await save_project(username, update.message.chat_id, context) + return ConversationHandler.END @@ -148,6 +216,67 @@ async def cancel(update, context): return ConversationHandler.END +@active_needed +async def ask_project_name(update, context): + '''Command to start the agregar_repositorio dialog''' + username = update.message.from_user.username + + projects = Project.select().join(Pycampista).where(Pycampista.username == username) + + if not projects: + await context.bot.send_message( + chat_id=update.message.chat_id, + text="No cargaste ningún proyecto", + ) + return ConversationHandler.END + + keyboard = [] + for project in projects: + keyboard.append([InlineKeyboardButton(project.name, callback_data=f"{PROJECT_NAME_PATTERN}:{project.name}")]) + reply_markup = InlineKeyboardMarkup(keyboard) + + await context.bot.send_message( + chat_id=update.message.chat_id, + text="¿A qué proyecto querés agregar un repositorio?", + reply_markup=reply_markup, + ) + + return 1 + + +async def ask_repository_name(update, context): + '''Dialog to set project name''' + callback_query = update.callback_query + chat = callback_query.message.chat + + username = callback_query.from_user.username + + current_projects[username] = callback_query.data.split(':')[1] + + await context.bot.send_message( + chat_id=chat.id, + text="¿Cuál es la URL del repositorio?", + ) + return 2 + + +async def add_repository(update, context): + '''Dialog to set repository''' + username = update.message.from_user.username + text = update.message.text + + project = Project.select().where(Project.name == current_projects[username]).get() + + project.repository_url = text + project.save() + + await context.bot.send_message( + chat_id=update.message.chat_id, + text=f'Repositorio "{text}" agregado al proyecto "{current_projects[username]}"', + ) + return ConversationHandler.END + + @active_needed @admin_needed async def start_project_load(update, context): @@ -186,7 +315,10 @@ async def end_project_load(update, context): states={ NOMBRE: [MessageHandler(filters.TEXT, naming_project)], DIFICULTAD: [MessageHandler(filters.TEXT, project_level)], - TOPIC: [MessageHandler(filters.TEXT, project_topic)]}, + TOPIC: [MessageHandler(filters.TEXT, project_topic)], + CHECK_REPOSITORIO: [CallbackQueryHandler(ask_if_repository_exists, pattern=f'{REPO_EXISTS_PATTERN}:')], + REPOSITORIO: [MessageHandler(filters.TEXT, project_repository)], + }, fallbacks=[CommandHandler('cancel', cancel)]) @@ -236,11 +368,12 @@ async def show_projects(update, context): projects = Project.select() text = [] for project in projects: - project_text = "{} \n Owner: {} \n Temática: {} \n Nivel: {}".format( + project_text = "{} \n Owner: {} \n Temática: {} \n Nivel: {} \n Repositorio: {}".format( project.name, project.owner.username, project.topic, - project.difficult_level + project.difficult_level, + project.repository_url or '(ninguno)', ) participants_count = Vote.select().where( (Vote.project == project) & (Vote.interest)).count() @@ -336,7 +469,18 @@ async def show_my_projects(update, context): await update.message.reply_text(text, parse_mode='MarkdownV2') def set_handlers(application): + add_repository_handler = ConversationHandler( + entry_points=[CommandHandler('agregar_repositorio', ask_project_name)], + states={ + 1: [CallbackQueryHandler(ask_repository_name, pattern=f'{PROJECT_NAME_PATTERN}:')], + 2: [MessageHandler(filters.TEXT, add_repository)], + }, + fallbacks=[CommandHandler('cancel', cancel)], + ) + application.add_handler(load_project_handler) + application.add_handler(add_repository_handler) + application.add_handler( CommandHandler('empezar_carga_proyectos', start_project_load)) application.add_handler( diff --git a/src/pycamp_bot/commands/voting.py b/src/pycamp_bot/commands/voting.py index fb90647..db8c143 100644 --- a/src/pycamp_bot/commands/voting.py +++ b/src/pycamp_bot/commands/voting.py @@ -9,6 +9,9 @@ from pycamp_bot.logger import logger +VOTE_PATTERN = 'vote' + + def vote_authorized(func): @functools.wraps(func) async def wrap(*args): @@ -61,7 +64,7 @@ async def button(update, context): # Save vote in the database and confirm the chosen proyects. - if query.data == "si": + if query.data.split(':')[1] == "si": result = f"✅ Sumade a {project_name}!" new_vote.interest = True else: @@ -96,8 +99,8 @@ async def vote(update, context): # ask user for each project in the database for project in Project.select(): - keyboard = [[InlineKeyboardButton("Me Sumo!", callback_data="si"), - InlineKeyboardButton("Paso", callback_data="no")]] + keyboard = [[InlineKeyboardButton("Me Sumo!", callback_data=f"{VOTE_PATTERN}:si"), + InlineKeyboardButton("Paso", callback_data=f"{VOTE_PATTERN}:no")]] reply_markup = InlineKeyboardMarkup(keyboard) @@ -129,7 +132,7 @@ async def vote_count(update, context): def set_handlers(application): application.add_handler( - CallbackQueryHandler(button)) + CallbackQueryHandler(button, pattern=f'{VOTE_PATTERN}:')) application.add_handler( CommandHandler('empezar_votacion_proyectos', start_voting)) application.add_handler( diff --git a/src/pycamp_bot/models.py b/src/pycamp_bot/models.py index b5e2bb2..3313111 100644 --- a/src/pycamp_bot/models.py +++ b/src/pycamp_bot/models.py @@ -158,6 +158,7 @@ class Project(BaseModel): topic = pw.CharField(null=True) slot = pw.ForeignKeyField(Slot, null=True) owner = pw.ForeignKeyField(Pycampista) + repository_url = pw.CharField(null=True) class Vote(BaseModel):