import logging import json import asyncio import nest_asyncio from telegram import InlineKeyboardButton, InlineKeyboardMarkup, Update from telegram.ext import Application, CommandHandler, CallbackQueryHandler, ContextTypes from apscheduler.schedulers.asyncio import AsyncIOScheduler from apscheduler.triggers.cron import CronTrigger from datetime import datetime import pytz # Aplica nest_asyncio para evitar problemas con el event loop nest_asyncio.apply() # Configuración del logging logging.basicConfig( format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', level=logging.INFO ) logger = logging.getLogger(__name__) # --------- DATOS DEL CUADRANTE --------- CUADRANTE = [ { "Planta Baja": "Feminismos", "Villa Paloma": "OVT", "Planta 2 (Escalera)": "Enrefugio" }, { "Planta Baja": "Kamanchaka", "Villa Paloma": "F.F.F", "Planta 2 (Escalera)": "Yoga" }, { "Planta Baja": "Warawas + F.L.O.R", "Villa Paloma": "Circo", "Planta 2 (Escalera)": "Asamblea" }, { "Planta Baja": "Autodefensa", "Villa Paloma": "Hacklab", "Planta 2 (Escalera)": "Fermentos + hongos" } ] # --- PON AQUÍ EL CHAT_ID DE TU GRUPO --- GROUP_CHAT_ID = -1002113687479 # <--- Reemplaza por el ID de tu grupo # Mensaje de bienvenida con emojis WELCOME_MESSAGE = ( "👋 *Bienvenidos a La Enredadera*\n\n" "🏠 Un centro social ubicado en *Tetuán, Madrid* 📍, en la Calle de la Coruña 5.\n\n" "🤝 En La Enredadera trabajamos por la igualdad, el respeto y la solidaridad, " "rechazando categóricamente la homofobia, la transfobia, la xenofobia y cualquier forma de discriminación. \n\n" "💬 Aquí fomentamos la participación, el diálogo y la defensa de los derechos de todas las personas.\n\n" "👉 *Selecciona una opción para saber más:*" ) # Textos de respuesta para cada opción, con emojis añadidos NUEVOS_COLECTIVOS = ( "📢 *NUEVOS COLECTIVOS*\n\n" "📝 *Presentación:*\n" "• Cómo se llama el proyecto/colectivo\n" "• De qué tipo es (colectivo/asociación, etc.)\n" "• Cuántas personas sois. (Abierto/Cerrado)\n" "• Desde cuándo funcionáis\n\n" "💡 *Valores y política:*\n" "• Cuáles son los objetivos\n" "• Valores y principios\n" "• Cómo funcionáis internamente (asambleas, consensos, votación, líder…)\n" "• ¿Estáis en conexión con alguna red/iniciativa/colectivo?\n\n" "🚚 *Logística:*\n" "• Actividad que queréis realizar\n" "• Qué necesidades tenéis (material, espacio, etc.)\n" "• Cuándo lo queréis realizar y cada cuánto\n\n" "🤝 *Compromisos con la Enre:*\n" "• Asistencia obligatoria a la asamblea de la Enre (todos los lunes a las 20:00)\n" "• Limpieza del espacio una vez al mes 🧹\n" "• Bienvenida a externos (todos los lunes de 19:00-20:00)\n" "• Organización de una Kafeta Enre cada 3-4 meses\n" "• Apoyo a otros colectivos\n" "• Participación en el grupo de Telegram “Enredando colectives”\n" "• Gestión de llaves de la Enre para necesidades puntuales 🔑\n\n" "🚫 *Líneas rojas en colectivos/eventos:*\n" "• Masculinidad exclusiva\n" "• No toleramos actitudes violentas, discriminatorias o de exclusión (homofobia, transfobia, xenofobia, etc.)" ) EVENTOS_EXTERNOS = ( "🎉 *EVENTOS EXTERNOS*\n\n" "👥 *Información del colectivo:*\n" "• Cómo se llama el colectivo\n" "• Líneas políticas\n" "• Organización interna\n" "• Qué aportan al espacio\n\n" "📅 *Información del evento:*\n" "• Público objetivo, aforo y si es abierto\n" "• Espacio y enseres necesarios\n" "• Evitar solapes de eventos/actividades\n" "• Horario (máximo hasta las 23:30)\n" "• Bebida y comida a cargo del evento (si es necesario, la Enre gestiona la bebida: pedidos@distribucioneslavapies.es)\n" "• Equipo de Scum: Contactar con Julita y tarifa de 20 € (o lo que se acuerde)\n\n" "⚠️ *Líneas rojas en colectivos/eventos:*\n" "• No a actitudes excluyentes o discriminatorias\n\n" "🤝 *Compromisos con la Enre:*\n" "• Asistencia a la asamblea previa al evento (entre las 19:00 y 20:00)\n" "• Turno de puerta y barra durante el evento\n" "• Limpieza posterior del espacio 🧼\n" "• Aporte del 10% de lo recaudado para la Enre\n\n" "🎶 *Eventos con música:*\n" "• Música se para a las 23:00/23:30; se debe desalojar el espacio salvo para el personal de limpieza\n" "• Conciertos/pinchadas en la planta baja (NO en Villa Paloma)\n" "• Preferencia por conciertos por la tarde para evitar molestias nocturnas\n" "• Respeto por los fines de semana\n\n" "📞 *Desde la asamblea:*\n" "• Contacto Enre: Persona asignada para confirmar y coordinar el evento\n" "• Madrina: Acompaña y coordina el evento, se asigna dos semanas antes\n" "• Protocolo policial a entregar y mediación en el evento\n" "• Valoración posterior del evento" ) KAFETAS_ENRE = ( "☕ *KAFETAS ENRE*\n\n" "🎯 *Objetivo:*\n" "• Punto de encuentro entre colectivos\n" "• Recaudar fondos para el espacio\n\n" "🔄 *Funcionamiento:*\n" "• Bebida a cargo de la Enre, verificación de cantidad por el colectivo\n" "• Recaudación destinada a la Enre\n" "• Organización conjunta entre colectivos\n" "• Posible presencia de comida, según recursos disponibles\n" "• Frecuencia: Dos kafetas al mes\n\n" "🛠 *Tareas durante la kafeta:*\n" "• Turno de puerta\n" "• Turno de barra\n" "• Limpieza posterior del espacio 🧽" ) # CUADRANTE LIMPIEZA FORMATO LISTA CUADRANTE_LIMPIEZA = ( "*🧹 Cuadrante de Limpieza Semanal*\n\n" "🏠 *Planta Baja*\n" " • Semana 1: Feminismos\n" " • Semana 2: Kamanchaka\n" " • Semana 3: Warawas + F.L.O.R\n" " • Semana 4: Autodefensa\n\n" "🏛️ *Villa Paloma*\n" " • Semana 1: OVT\n" " • Semana 2: F.F.F\n" " • Semana 3: Circo\n" " • Semana 4: Hacklab\n\n" "⬆️ *Planta 2 (Escalera)*\n" " • Semana 1: Enrefugio\n" " • Semana 2: Yoga\n" " • Semana 3: Asamblea\n" " • Semana 4: Fermentos + hongos\n" ) def get_main_menu(): """Devuelve el teclado principal con las 4 opciones.""" keyboard = [ [InlineKeyboardButton("NUEVOS COLECTIVOS 📢", callback_data='nuevos_colectivos')], [InlineKeyboardButton("EVENTOS EXTERNOS 🎉", callback_data='eventos_externos')], [InlineKeyboardButton("KAFETAS ENRE ☕", callback_data='kafetas_enre')], [InlineKeyboardButton("CUADRANTE LIMPIEZA 🧹", callback_data='cuadrante_limpieza')] ] return InlineKeyboardMarkup(keyboard) def get_back_menu(): """Devuelve un teclado con el botón para volver al menú principal.""" keyboard = [ [InlineKeyboardButton("🔙 Volver al menú", callback_data='volver')] ] return InlineKeyboardMarkup(keyboard) async def info(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None: # Comando /info que muestra la bienvenida y el menú principal if update.message: await update.message.reply_text( WELCOME_MESSAGE, parse_mode='Markdown', reply_markup=get_main_menu() ) async def button(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None: query = update.callback_query await query.answer() # Si el usuario pulsa "volver", se muestra el menú principal nuevamente if query.data == 'volver': await query.edit_message_text( text=WELCOME_MESSAGE, parse_mode='Markdown', reply_markup=get_main_menu() ) return # Selecciona el contenido según la opción elegida if query.data == 'nuevos_colectivos': texto = NUEVOS_COLECTIVOS elif query.data == 'eventos_externos': texto = EVENTOS_EXTERNOS elif query.data == 'kafetas_enre': texto = KAFETAS_ENRE elif query.data == 'cuadrante_limpieza': texto = CUADRANTE_LIMPIEZA else: texto = "❓ Opción no reconocida." # Muestra el contenido seleccionado junto con el botón para volver await query.edit_message_text( text=texto, parse_mode='Markdown', reply_markup=get_back_menu() ) # ----- AVISO AUTOMÁTICO DE LIMPIEZA ----- async def aviso_cuadrante(bot): # Calcula la semana del mes (0-3) today = datetime.now(pytz.timezone('Europe/Madrid')) week_num = ((today.day - 1) // 7) % 4 cuadrante = CUADRANTE[week_num] msg = ( f"🧹 *Aviso semanal de limpieza*\n\n" f"🏠 *Planta Baja*: {cuadrante['Planta Baja']}\n" f"🏛️ *Villa Paloma*: {cuadrante['Villa Paloma']}\n" f"⬆️ *Planta 2 (Escalera)*: {cuadrante['Planta 2 (Escalera)']}\n\n" f"¡Recordad pasaros a limpiar esta semana! 😉" ) await bot.send_message(chat_id=GROUP_CHAT_ID, text=msg, parse_mode="Markdown") # ----- FIN AVISO AUTOMÁTICO ----- # ----- PRINT CHAT_ID SOLO EN LOG ----- async def print_chat_id(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None: chat = update.effective_chat logger.info(f"El chat_id de este chat es: {chat.id}") await update.message.reply_text("¡ID registrado en el log del servidor! 👍") # -------------------------------------- async def main() -> None: # Cargar el token desde config.json with open('config.json', 'r') as config_file: config = json.load(config_file) token = config.get("TOKEN") if not token: logger.error("El token no se ha encontrado en el archivo config.json") return application = Application.builder().token(token).build() # Se registra el comando /info en lugar de /start application.add_handler(CommandHandler('info', info)) application.add_handler(CommandHandler('id', print_chat_id)) application.add_handler(CallbackQueryHandler(button)) # ------ SCHEDULER ------ scheduler = AsyncIOScheduler(timezone='Europe/Madrid') # Lunes a las 13:12 scheduler.add_job( aviso_cuadrante, trigger=CronTrigger(day_of_week='mon', hour=13, minute=12), args=[application.bot] ) scheduler.start() # ----------------------- await application.run_polling() if __name__ == '__main__': asyncio.run(main())