diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..05499d5 --- /dev/null +++ b/.env.example @@ -0,0 +1,3 @@ +TOKEN=bot_token:your_bot_token_here +PYCAMP_BOT_MASTER_KEY=your_secret_key_here +SENTRY_DATA_SOURCE_NAME= diff --git a/Dockerfile b/Dockerfile index 9438710..612ed63 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,9 +1,12 @@ -FROM python:3.10 +FROM python:3.10-slim USER root +# Install git for de /mostrar_version command. +RUN apt-get update && apt-get install -y --no-install-recommends git && rm -rf /var/lib/apt/lists/* + COPY . /pycamp/telegram_bot WORKDIR /pycamp/telegram_bot -RUN pip3 install -U -e . +RUN pip3 install -U -e '.[dev]' CMD [ "python", "bin/run_bot.py" ] diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..4bc407d --- /dev/null +++ b/Makefile @@ -0,0 +1,45 @@ +# ============================================================================= +# PyCamp Bot — Makefile +# ============================================================================= +# Todos los comandos (bot, tests, etc.) se ejecutan dentro del contenedor. +# El código se monta como volumen para que los cambios locales se reflejen +# sin necesidad de reconstruir la imagen (rebuild). +# +# Requiere: imagen construida (make build) y archivo .env para run/test. +# ============================================================================= + +.PHONY: build run test test-cov all + +# Ruta del proyecto en el host; se monta en el contenedor para evitar rebuild. +PROJECT_PATH := $(shell pwd) +# Ruta dentro del contenedor (debe coincidir con WORKDIR del Dockerfile). +CONTAINER_PATH := /pycamp/telegram_bot + +build: + docker build --rm -t pycamp_bot . + +# Ejecuta el bot. Código montado en rw para que pycamp_projects.db pueda +# crearse/actualizarse en el directorio del proyecto. +run: + docker run --rm --env-file .env \ + -v "$(PROJECT_PATH):$(CONTAINER_PATH)" \ + pycamp_bot + +# Tests: código montado en solo lectura (:ro). Los tests usan DB en memoria, +# así que no se escribe nada en el árbol del proyecto. +test: + docker run --rm --env-file .env \ + -v "$(PROJECT_PATH):$(CONTAINER_PATH):ro" \ + pycamp_bot pytest + +# Tests con reporte de cobertura. Código :ro; el reporte se escribe en /tmp +# para no necesitar escritura en el árbol del proyecto. +test-cov: + docker run --rm --env-file .env \ + -e COVERAGE_FILE=/tmp/.coverage \ + -v "$(PROJECT_PATH):$(CONTAINER_PATH):ro" \ + pycamp_bot pytest --cov=pycamp_bot --cov-report=term-missing + +all: build run + +.DEFAULT_GOAL := all diff --git a/README.md b/README.md index 50c5c3c..0e5b71c 100644 --- a/README.md +++ b/README.md @@ -1,98 +1,171 @@ # Este es el bot del Pycamp -## Documentación del módulo +Bot de Telegram para organizar y gestionar PyCamps: carga de proyectos, votación, cronogramas y asignación de magos. -Puede encontrar una documentación mas detallada para programadores en [https://pyar.github.io/PyCamp_Bot](https://pyar.github.io/PyCamp_Bot) +--- -## Variables de entorno +## 📚 Documentación -* TOKEN: Token del bot generado con BotFather. -* PYCAMP_BOT_MASTER_KEY: Password para agregar nuevos admins. -* SENTRY_DATA_SOURCE_NAME: ID de proyecto de Sentry para habilitar el monitoreo. +Encontrá documentación más detallada para programadores en [https://pyar.github.io/PyCamp_Bot](https://pyar.github.io/PyCamp_Bot) -## Development +--- -Si queres contribuir en este proyecto lo primero que vas a necesitar es crearte un bot para hacer -las pruebas. +## 🚀 Desarrollo -Esto lo podes hacer hablandole a @BotFather que es el "Bot padre de todos los bots" de telegram. -Él te a a guiar para que puedas hacer tu propio bot. +### 1️⃣ Crear tu bot de prueba -Una vez creado el bot, deberías tener un TOKEN\_PERSONAL (BotFather te lo da en el mismo proceso de -creación). +Para contribuir necesitás tu propio bot de Telegram: -Despues instala el paquete en modo desarrollo en un virtual environment +1. Hablale a [@BotFather](https://t.me/BotFather) en Telegram +2. Seguí las instrucciones para crear tu bot +3. Guardá el **TOKEN** que te da (lo vas a necesitar) -~~~bash +### 2️⃣ Instalar dependencias + +```bash python3 -m venv venv source venv/bin/activate pip install -e '.[dev]' -~~~ +``` + +### 3️⃣ Ejecutar el bot + +#### Opción 1: Variables inline (más rápido para probar) + +```bash +TOKEN='TU_TOKEN_AQUI' PYCAMP_BOT_MASTER_KEY='TU_CLAVE' python bin/run_bot.py +``` + +#### Opción 2: Con archivo .env (recomendado) + +1. Crear el archivo de configuración: + ```bash + cp .env.example .env + ``` + +2. Editar `.env` con tus valores: + ``` + TOKEN=tu_token_aqui + PYCAMP_BOT_MASTER_KEY=tu_clave_secreta + SENTRY_DATA_SOURCE_NAME=tu_sentry_dsn # Opcional + ``` + +3. Ejecutar: + ```bash + python bin/run_bot.py + ``` + +#### Opción 3: Con Docker + +```bash +make # Construye la imagen (si no existe) y ejecuta el bot +``` + +**¡Listo!** Tu bot está corriendo. Probalo mandándole `/start` por Telegram. + +--- + +## 🧪 Testing + +### Opción 1: Local en tu máquina + +Ejecutar todos los tests: + +```bash +pytest +``` + +Ejecutar un test específico: + +```bash +pytest test/test_wizard.py +``` + +Con variables de entorno inline: + +```bash +TOKEN='TOKEN_TEST' PYCAMP_BOT_MASTER_KEY='KEY_TEST' pytest +``` + +### Opción 2: Con Docker + +```bash +make test +``` + +--- -y estas listo para trabajar. +## 🔧 Variables de entorno -## Testeo +| Variable | Descripción | Requerida | +|----------|-------------|-----------| +| `TOKEN` | Token del bot generado con BotFather | ✅ Sí | +| `PYCAMP_BOT_MASTER_KEY` | Password para comandos de admin | ✅ Sí | +| `SENTRY_DATA_SOURCE_NAME` | ID de proyecto de Sentry para monitoreo | ❌ No | -Para correr el bot ejecutá (con el virtual environment activado): +--- -~~~bash -TOKEN='TOKEN_PERSONAL' PYCAMP_BOT_MASTER_KEY='KEY' python bin/run_bot.py -~~~ +## 🎯 ¿Cómo usar el bot en un nuevo PyCamp? -Y listo! Tu bot está corriendo en tu máquina, esperando que alguien le escriba por telegram. -Podés probarlo mandandole un `/start` +### Preparación inicial -## ¿Cómo usar el bot en un nuevo pycamp? +1. Configurar las variables de entorno (ver tabla arriba) +2. Ejecutar el bot: `python bin/run_bot.py` +3. Verificar que funciona enviándole `/start` -Primero es necesario setear las siguientes variables de entorno: +--- -* `TOKEN`: token del bot que se usará durante el pycamp (gestionar desde telegram con BotFather) -* `PYCAMP_BOT_MASTER_KEY`: con alguna password secreta que se va a usar para acceder a comandos de superuser -* `SENTRY_DATA_SOURCE_NAME`: ID del proyecto de Sentry "telegrambot" de la cuenta de PyAr +## 👥 Comandos del bot -Una vez creadas las variables de entorno, correr el bot con el comando `python bin/run_bot.py` +### 🔐 Para Admins -En este momento ya se puede hablar con el bot. ¿Qué le digo? +#### Inicialización (al comienzo de cada PyCamp) -* `/start` para chequear que esté andando bien +| Comando | Descripción | +|---------|-------------| +| `/su ` | Reclamar permisos de admin con la clave de `PYCAMP_BOT_MASTER_KEY` | +| `/empezar_pycamp ` | Crear el PyCamp (pide fecha de inicio y duración) | +| `/activar_pycamp ` | Activar un PyCamp específico (si hace falta) | -### Flujo admin +#### Gestión de Proyectos -#### Inicialización (requerida al comienzo de cada PyCamp) +| Comando | Descripción | +|---------|-------------| +| `/empezar_carga_proyectos` | Habilitar la carga de proyectos | +| `/terminar_carga_proyectos` | Cerrar la carga de proyectos | +| `/empezar_votacion_proyectos` | Activar la votación | +| `/terminar_votacion_proyectos` | Cerrar la votación | +| `/cronogramear` | Generar el cronograma (pide días y slots) | +| `/cambiar_slot ` | Mover un proyecto de horario | -* `/su ` para reclamar permisos de admin, reemplazando `` por la contraseña que hayamos elegido en la envvar `PYCAMP_BOT_MASTER_KEY` -* `/empezar_pycamp ` inicia el flujo de creación de un pycamp. Lo carga en la db, pide fecha de inicio y duración. Lo deja activo. - * `/activar_pycamp ` activa un pycamp, en caso que haga falta. +#### Gestión de Magxs -#### Flujo de Proyectos +| Comando | Descripción | +|---------|-------------| +| `/agendar_magx` | Asignar magos automáticamente (9-13 y 14-19hs) | -* `/empezar_carga_proyectos` habilita la carga de los proyectos. En este punto los pycampistas pueden cargar sus proyectos, -enviandole al bot el comando `/cargar_proyecto` -* `/terminar_carga_proyectos` termina carga proyectos -* `/empezar_votacion_proyectos` activa la votacion (a partir de ahora los pycampistas pueden votar con `/votar`) -* `/terminar_votacion_proyectos` termina la votacion +> **Nota:** Los magos deben registrarse primero con `/ser_magx` -Para generar el schedule: +--- -* `/cronogramear` te va a preguntar cuantos dias queres cronogramear y cuantos slots por dia tenes y hacer el cronograma. -* `/cambiar_slot` toma un nombre de proyecto y un slot; y te cambia ese proyecto a ese slot. +### 🙋 Para Pycampistas -#### Flujo de magia +#### Proyectos -Para agendar los magos todos los candidatos tienen que haberse registrado con `/ser_magx` +| Comando | Descripción | +|---------|-------------| +| `/cargar_proyecto` | Cargar tu proyecto (si la carga está habilitada) | +| `/votar` | Votar proyectos de tu interés | +| `/ver_cronograma` | Ver el cronograma del evento | -* `/agendar_magx` Asigna un mago por hora durante todo el PyCamp. - * De 9 a 13 y de 14 a 19. - * El primer día arranca después del almuerzo (14hs). - * El último día termina al almuerzo (13hs). +#### Sistema de Magxs -### Flujo pycampista +| Comando | Descripción | +|---------|-------------| +| `/ser_magx` | Registrarte como mago | +| `/ver_magx` | Ver la lista de magos registrados | +| `/evocar_magx` | Llamar al mago de turno para pedir ayuda | +| `/ver_agenda_magx [completa]` | Ver la agenda de magos (usa `completa` para ver todos los turnos) | -* `/cargar_proyecto` carga un proyecto (si está habilitada la carga) -* `/votar` envia opciones para votar (si está habilitada la votacion) -* `/ver_cronograma` te muestra el cronograma! -* `/ser_magx` te registra como mago. -* `/ver_magx` Lista los magos registrados. -* `/evocar_magx` llama al mago de turno para pedirle ayuda. -* `/ver_agenda_magx completa` te muestra la agenda de magos del PyCamp. El parámetro `completa` es opcional, si se omite solo muestra los turnos pendientes. +--- diff --git a/pyproject.toml b/pyproject.toml index 6934f48..4011c8b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -23,6 +23,7 @@ dev = [ "flake8==7.1.2", "freezegun==1.5.1", "pytest==8.3.4", + "pytest-cov==6.0.0", ] doc = [ "sphinx==7.3.7",