|
1 | | -from telegram.ext import CommandHandler |
| 1 | +from telegram import Update, Bot |
| 2 | +from telegram.ext import ConversationHandler, CommandHandler, MessageHandler, filters, CallbackContext |
2 | 3 | from pycamp_bot.models import Project, Pycampista, Vote |
3 | 4 | from pycamp_bot.commands.auth import get_admins_username |
| 5 | +from pycamp_bot.logger import logger |
| 6 | +from pycamp_bot.commands.manage_pycamp import active_needed |
4 | 7 |
|
| 8 | +PROYECTO, LUGAR, MENSAJE = ["proyecto", "lugar", "mensaje"] |
5 | 9 |
|
6 | | -async def announce(update, context): |
7 | | - username = update.message.from_user.username |
8 | | - admins = get_admins_username() |
9 | | - project_name = update.message.text.split()[1:] |
| 10 | +ERROR_MESSAGES = { |
| 11 | + "format_error": "Error de formato, recuerde que el formato debe ser el siguiente:\n/anunciar tu_proyecto\nPor favor comienza de nuevo.", |
| 12 | + "not_admin": "No tenes proyectos para anunciar y no eres admin.", |
| 13 | + "not_found": "No se encontro el proyecto *{project_name}*. Intenta de nuevo por favor.", |
| 14 | + "no_admin": "No puedes anunciar proyectos si no eres el owner.\nPor favor contacta un admin" |
| 15 | +} |
10 | 16 |
|
11 | | - project_name = " ".join(project_name) |
12 | | - project = Project.select().where(Project.name == project_name) |
13 | 17 |
|
14 | | - if len(project) <= 0: |
15 | | - await context.bot.send_message( |
16 | | - chat_id=update.message.chat_id, |
17 | | - text=f"El proyecto '{project_name}' no existe o esta mal escroto.\n" |
18 | | - "El formato de este comando es:\n" |
19 | | - "/anunciar NOMBRE_DEL_PROYECTO" |
20 | | - ) |
21 | | - return |
| 18 | +class AnnouncementState: |
| 19 | + def __init__(self): |
| 20 | + self.username = None |
| 21 | + self.p_name = '' |
| 22 | + self.current_project = False |
| 23 | + self.projects = [] |
| 24 | + self.owner = '' |
| 25 | + self.lugar = '' |
| 26 | + self.mensaje = '' |
22 | 27 |
|
23 | | - if not (project.get().owner.username == username or username in admins): |
24 | | - await context.bot.send_message( |
25 | | - chat_id=update.message.chat_id, |
26 | | - text="No sos ni admin ni el owner de este proyecto, Careta." |
27 | | - ) |
28 | | - return |
| 28 | +state = AnnouncementState() |
| 29 | + |
| 30 | +async def user_is_admin(pycampist: str) -> bool: |
| 31 | + return pycampist in get_admins_username() |
| 32 | + |
| 33 | +async def should_be_able_to_announce(pycampista: str, proyect: Project) -> bool: |
| 34 | + return pycampista == proyect.owner.username or await user_is_admin(pycampista) |
| 35 | + |
| 36 | + |
| 37 | +@active_needed |
| 38 | +async def announce(update: Update, context: CallbackContext) -> str: |
| 39 | + logger.info("Announcement project process started") |
| 40 | + parameters: list[str] = update.message.text.split() |
| 41 | + |
| 42 | + if len(parameters) > 2: |
| 43 | + await handle_error(context, update.message.chat_id, "format_error") |
| 44 | + logger.warning("Error de formato en la solicitud. Too many parameters") |
| 45 | + return ConversationHandler.END |
| 46 | + state.username = update.message.from_user.username |
| 47 | + state.projects = Project.select().join(Pycampista).where(Pycampista.username == state.username) |
| 48 | + |
| 49 | + if len(state.projects) == 0: |
| 50 | + if not await user_is_admin(state.username): |
| 51 | + await context.bot.send_message( |
| 52 | + chat_id=update.message.chat_id, |
| 53 | + text=ERROR_MESSAGES["no_admin"], |
| 54 | + ) |
| 55 | + logger.warn(f"Pycampista {state.username} no contiene proyectos creados.") |
| 56 | + return ConversationHandler.END |
| 57 | + else: |
| 58 | + state.projects = Project.select() |
| 59 | + return await get_project(update, context) |
| 60 | + |
| 61 | + if len(parameters) == 1: |
| 62 | + project_list: str = "" |
| 63 | + if len(state.projects) == 0: |
| 64 | + await context.bot.send_message( |
| 65 | + chat_id=update.message.chat_id, |
| 66 | + text="Ingresá el Nombre del Proyecto a anunciar." |
| 67 | + ) |
| 68 | + else: |
| 69 | + project_list = "\n".join(p.name.capitalize() for p in state.projects) |
| 70 | + await context.bot.send_message( |
| 71 | + chat_id=update.message.chat_id, |
| 72 | + text=f"""Ingresá el Nombre del Proyecto a anunciar.\n\nTienes los siguientes proyectos:\n{project_list}""", |
| 73 | + ) |
| 74 | + |
| 75 | + if len(parameters) == 2: |
| 76 | + print('-Handle correct commands-') |
| 77 | + state.p_name = update.message.text.split()[1].lower() |
| 78 | + _projects = Project.select().join(Pycampista).where(Project.name == state.p_name) |
| 79 | + |
| 80 | + if len(_projects) == 0: |
| 81 | + await context.bot.send_message( |
| 82 | + chat_id=update.message.chat_id, |
| 83 | + text=f"No existe el proyecto: *{state.p_name}*.", |
| 84 | + parse_mode='Markdown' |
| 85 | + ) |
| 86 | + return ConversationHandler.END |
| 87 | + elif not await should_be_able_to_announce(state.username, _projects[0]): |
| 88 | + await context.bot.send_message( |
| 89 | + chat_id=update.message.chat_id, |
| 90 | + text=ERROR_MESSAGES["no_admin"], |
| 91 | + ) |
| 92 | + logger.warn(f"Solicitud de anuncio no autorizada.") |
| 93 | + return ConversationHandler.END |
| 94 | + else: |
| 95 | + await context.bot.send_message( |
| 96 | + chat_id=update.message.chat_id, |
| 97 | + text=f"Anunciando el proyecto: *{_projects[0].name.capitalize()}* !!!", |
| 98 | + parse_mode='Markdown' |
| 99 | + ) |
| 100 | + state.owner = _projects[0].owner.username |
| 101 | + state.current_project = _projects[0] |
| 102 | + return await get_project(update, context) |
| 103 | + return PROYECTO |
| 104 | + |
| 105 | + |
| 106 | +async def get_project(update: Update, context: CallbackContext) -> str: |
| 107 | + '''Dialog to set project to announce''' |
| 108 | + logger.info("Getting project") |
| 109 | + parameters_list: list[str] = update.message.text.split() |
| 110 | + |
| 111 | + if len(parameters_list) > 2: |
| 112 | + await handle_error(context, update.message.chat_id, "format_error") |
| 113 | + return ConversationHandler.END |
| 114 | + |
| 115 | + if "/anunciar" in parameters_list: |
| 116 | + if len(parameters_list) == 2: |
| 117 | + state.current_project = Project.select().join(Pycampista).where(Project.name == parameters_list[1].lower()) |
| 118 | + if not await should_be_able_to_announce(update.message.from_user.username, state.current_project[0]): |
| 119 | + await handle_error(context, update.message.chat_id, "format_error", state.current_project) |
| 120 | + logger.warning(f"Project {parameters_list[1]} not found!") |
| 121 | + return PROYECTO |
| 122 | + else: |
| 123 | + await context.bot.send_message( |
| 124 | + chat_id=update.message.chat_id, |
| 125 | + text="Ingrese lugar donde comienza el proyecto." |
| 126 | + ) |
| 127 | + state.p_name = parameters_list[1].lower() |
| 128 | + state.current_project = state.current_project[0] |
| 129 | + if len(parameters_list) == 1: |
| 130 | + await context.bot.send_message( |
| 131 | + chat_id=update.message.chat_id, |
| 132 | + text="Ingrese el nombre del proyecto." |
| 133 | + ) |
| 134 | + return PROYECTO |
| 135 | + |
| 136 | + elif len(parameters_list) == 2: |
| 137 | + await handle_error(context, update.message.chat_id, "format_error") |
| 138 | + logger.warning("Error de formato en la solicitud. Too many parameters") |
| 139 | + return PROYECTO |
29 | 140 |
|
30 | | - pycampistas = Vote.select().join(Pycampista).where((Vote.project == project) & (Vote.interest)) |
| 141 | + else: |
| 142 | + c_proyect = Project.select().where(Project.name == parameters_list[0].lower()).first() |
| 143 | + print('c_proyect: ', c_proyect) |
| 144 | + if c_proyect: |
| 145 | + if await should_be_able_to_announce(update.message.from_user.username, c_proyect): |
| 146 | + state.current_project = c_proyect |
| 147 | + state.p_name = c_proyect.name |
| 148 | + state.owner = c_proyect.owner.username |
| 149 | + await context.bot.send_message( |
| 150 | + chat_id=update.message.chat_id, |
| 151 | + text="Ingrese lugar donde comienza el proyecto." |
| 152 | + ) |
| 153 | + else: |
| 154 | + logger.warning("Solicitud de anuncio no autorizada.") |
| 155 | + await handle_error( |
| 156 | + context, |
| 157 | + update.message.chat_id, |
| 158 | + "no_admin" |
| 159 | + ) |
| 160 | + return ConversationHandler.END |
| 161 | + else: |
| 162 | + logger.warning("Solicitud de anuncio no autorizada.") |
| 163 | + await handle_error( |
| 164 | + context, |
| 165 | + update.message.chat_id, |
| 166 | + "not_found", |
| 167 | + project_name=parameters_list[0] |
| 168 | + ) |
| 169 | + logger.warning("Error de formato en la solicitud. No se encontró el proyecto.") |
| 170 | + return PROYECTO |
| 171 | + return LUGAR |
31 | 172 |
|
32 | | - chat_id_list = [user.pycampista.chat_id for user in pycampistas] |
33 | 173 |
|
| 174 | +async def meeting_place(update: Update, context: CallbackContext) -> str: |
| 175 | + '''Dialog to set the place of the meeting''' |
| 176 | + logger.info("Setting place") |
| 177 | + state.lugar = update.message.text.capitalize() |
| 178 | + await context.bot.send_message( |
| 179 | + chat_id=update.message.chat_id, |
| 180 | + text="Escribe un mensaje a los pycampistas suscriptos ..." |
| 181 | + ) |
| 182 | + return MENSAJE |
| 183 | + |
| 184 | + |
| 185 | +async def message_project(update: Update, context: CallbackContext) -> str: |
| 186 | + '''Dialog to set project topic''' |
| 187 | + state.mensaje = update.message.text.capitalize() |
| 188 | + pycampistas: list[Vote] = Vote.select().join( |
| 189 | + Pycampista).where( |
| 190 | + (Vote.project == Project.select().where( |
| 191 | + Project.name == state.current_project.name)) & (Vote.interest)) |
| 192 | + chat_id_list: list[int] = [user.pycampista.chat_id for user in pycampistas] |
34 | 193 | for chat_id in chat_id_list: |
35 | | - await context.bot.send_message( |
36 | | - chat_id=chat_id, |
37 | | - text=f"Esta por empezar {project_name} a cargo de @{project.get().owner.username}." |
38 | | - ) |
| 194 | + try: |
| 195 | + await context.bot.send_message( |
| 196 | + chat_id=chat_id, |
| 197 | + text=f'''Está por empezar el proyecto *"{(state.p_name).capitalize()}"* a cargo de *@{state.owner}*.\n*¿Dónde?* 👉🏼 {state.lugar}''', |
| 198 | + parse_mode='Markdown' |
| 199 | + ) |
| 200 | + if update.message.from_user.username == state.owner: |
| 201 | + await context.bot.send_message( |
| 202 | + chat_id=chat_id, |
| 203 | + text=f'*Project Owner says:* **{state.mensaje}**', |
| 204 | + parse_mode='Markdown' |
| 205 | + ) |
| 206 | + else: |
| 207 | + await context.bot.send_message( |
| 208 | + chat_id=chat_id, |
| 209 | + text=f'Admin *@{update.message.from_user.username}* says: **{state.mensaje}**', |
| 210 | + parse_mode='Markdown' |
| 211 | + ) |
| 212 | + except Exception as e: |
| 213 | + logger.error(f"Error al enviar el mensaje: {e}") |
39 | 214 | await context.bot.send_message( |
40 | 215 | chat_id=update.message.chat_id, |
41 | 216 | text="Anunciado!" |
42 | 217 | ) |
| 218 | + logger.info('Project announced!') |
| 219 | + return ConversationHandler.END |
| 220 | + |
| 221 | + |
| 222 | +async def cancel(update: Update, context: CallbackContext) -> str: |
| 223 | + '''Cancel the project announcement''' |
| 224 | + await context.bot.send_message( |
| 225 | + chat_id=update.message.chat_id, |
| 226 | + text="Has cancelado el anuncio del proyecto") |
| 227 | + logger.warning("Announcement canceled") |
| 228 | + return ConversationHandler.END |
| 229 | + |
| 230 | + |
| 231 | +async def handle_error(context: CallbackContext, chat_id: int, error_key: str, **kwargs: list) -> None: |
| 232 | + error_message = ERROR_MESSAGES[error_key].format(**kwargs) |
| 233 | + print('error_message: ', error_message) |
| 234 | + '''Handle error messages''' |
| 235 | + try: |
| 236 | + await context.bot.send_message( |
| 237 | + chat_id=chat_id, |
| 238 | + text=error_message, |
| 239 | + #parse_mode='Markdown' |
| 240 | + ) |
| 241 | + except Exception as e: |
| 242 | + logger.error(f"Error al enviar el mensaje: {e}") |
| 243 | + |
43 | 244 |
|
| 245 | +start_project_handler = ConversationHandler( |
| 246 | + entry_points=[CommandHandler('anunciar', announce)], |
| 247 | + states={ |
| 248 | + PROYECTO: [MessageHandler(filters.TEXT & ~filters.COMMAND, get_project)], |
| 249 | + LUGAR: [MessageHandler(filters.TEXT & ~filters.COMMAND, meeting_place)], |
| 250 | + MENSAJE: [MessageHandler(filters.TEXT & ~filters.COMMAND, message_project)] |
| 251 | + }, |
| 252 | + fallbacks=[CommandHandler('cancel', cancel)] |
| 253 | +) |
44 | 254 |
|
45 | 255 | def set_handlers(application): |
46 | | - application.add_handler(CommandHandler('anunciar', announce)) |
| 256 | + '''Add handlers to the application''' |
| 257 | + application.add_handler(start_project_handler) |
0 commit comments