From 5ba4228fcf2fd814a08218c904c93ab7bb4f7e96 Mon Sep 17 00:00:00 2001 From: Joan Date: Fri, 16 Feb 2024 20:28:54 +0100 Subject: [PATCH] Finally made it multichannel --- conjuntasbot/conjuntasbot.py | 145 ++++++++++++++++++++++++++--------- docker-compose.yml | 9 ++- 2 files changed, 115 insertions(+), 39 deletions(-) diff --git a/conjuntasbot/conjuntasbot.py b/conjuntasbot/conjuntasbot.py index f76758f..43d45af 100644 --- a/conjuntasbot/conjuntasbot.py +++ b/conjuntasbot/conjuntasbot.py @@ -24,7 +24,8 @@ httpx_logger.setLevel(logging.WARNING) # Cargar los identificadores de administradores desde la variable de entorno admin_ids = [int(admin_id) for admin_id in os.environ.get("ADMIN_IDS", "").split(",")] -group_chat_id = os.environ.get("GROUP_CHAT_ID") +general_group_chat_id = os.environ.get("GENERAL_GROUP_CHAT_ID") +vip_group_chat_id = os.environ.get("VIP_GROUP_CHAT_ID") bot_token = os.environ.get("TELEGRAM_TOKEN") spreadsheet_id = os.environ.get("SPREADSHEET_ID") @@ -33,7 +34,8 @@ conn = sqlite3.connect('/app/data/conjuntas.db') cursor = conn.cursor() cursor.execute('''CREATE TABLE IF NOT EXISTS conjuntas ( id INTEGER PRIMARY KEY AUTOINCREMENT, - message_id INTEGER, + message_id_general INTEGER, + message_id_vip INTEGER, product_name TEXT, product_description TEXT, limite INTEGER, @@ -99,7 +101,7 @@ async def edit_conjunta(update: Update, context: CallbackContext): conjunta = cursor.fetchone() if conjunta: - conjunta_id, message_id, product_name, product_description, limit, limit_per_user, price, price_member, closed, photo_id, message_date = conjunta + conjunta_id, message_id_general, message_id_vip, product_name, product_description, limit, limit_per_user, price, price_member, closed, photo_id, message_date = conjunta context.user_data['product_name'] = product_name context.user_data['original_product_name'] = product_name @@ -292,7 +294,7 @@ async def limit_per_user(update: Update, context: CallbackContext): await update.message.reply_text("Por favor, introduce un número válido como límite.") return LIMIT_PER_USER -# Función para enviar mensaje al grupo y añadir conjunta a la base de datos +# Función para enviar mensaje al grupo vip y añadir conjunta a la base de datos async def add_and_send(update: Update, context: CallbackContext, message): product_name = context.user_data['product_name'] limit = context.user_data['limit'] @@ -303,21 +305,20 @@ async def add_and_send(update: Update, context: CallbackContext, message): price_member = context.user_data['price_member'] if not context.user_data['edit']: - sent_message = await context.bot.send_photo(group_chat_id, photo=photo_id, caption=message) + sent_message = await context.bot.send_photo(vip_group_chat_id, photo=photo_id, caption=message) - cursor.execute("INSERT INTO conjuntas (message_id, product_name, product_description, price, price_member, limite, limit_per_user, closed, photo_id, message_date) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", - (sent_message.message_id, product_name, product_description, price, price_member, limit, limit_per_user, 0, photo_id, int(time.time()))) + cursor.execute("INSERT INTO conjuntas (message_id_general, message_id_vip, product_name, product_description, price, price_member, limite, limit_per_user, closed, photo_id, message_date) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", + (0, sent_message.message_id, product_name, product_description, price, price_member, limit, limit_per_user, 0, photo_id, int(time.time()))) conn.commit() conjunta_id = cursor.lastrowid # Creamos una nueva hoja en el documento worksheet = spreadsheet.add_worksheet(title=f"{product_name} - {conjunta_id}", rows=1, cols=3) - #worksheet.update(values = [2, 5, 3], range_name = "A1:C1") worksheet.append_row(["Usuario", "Cantidad", "Socio"]) # Anclar el mensaje en el grupo - await context.bot.pin_chat_message(group_chat_id, sent_message.message_id) + await context.bot.pin_chat_message(vip_group_chat_id, sent_message.message_id) else: conjunta_id = context.user_data['conjunta_id'] cursor.execute("UPDATE conjuntas SET product_name = ?, product_description = ?, price = ?, price_member = ?, limite = ?, limit_per_user = ?, photo_id = ? WHERE id=?", (product_name, product_description, price, price_member, limit, limit_per_user, photo_id, conjunta_id)) @@ -383,7 +384,7 @@ async def update_conjunta(update: Update, context: CallbackContext, conjunta_id) conjunta = cursor.fetchone() if conjunta: - conjunta_id, message_id, product_name, product_description, limit, limit_per_user, price, price_member, closed, photo_id, message_date = conjunta + conjunta_id, message_id_general, message_id_vip, product_name, product_description, limit, limit_per_user, price, price_member, closed, photo_id, message_date = conjunta message = f"Conjunta para 🛒 {product_name}\n\n" if limit: @@ -412,23 +413,54 @@ async def update_conjunta(update: Update, context: CallbackContext, conjunta_id) # quantity_string = "unidades" if quantity > 1 else "unidad" # message += f"@{user_name} - {quantity} {quantity_string}\n" - if (int(time.time()) - int(message_date)) < (24 * 3600 * 2): # borramos el mensaje si tiene más de 1 día - logging.info(f"Updating message for {product_name} - {conjunta_id}") - try: - await context.bot.edit_message_caption(chat_id=group_chat_id, message_id=message_id, caption=message, parse_mode=ParseMode.HTML) - except Exception as e: - logging.error(f"Error editing message: {e}") - else: - logging.info(f"Original message for {product_name} - {conjunta_id} is old, unpinning and sending new message") - try: - await context.bot.unpin_chat_message(chat_id=group_chat_id, message_id=message_id) - except Exception as e: - logging.error(f"Error unpinning message: {e}") - sent_message = await context.bot.send_photo(chat_id=group_chat_id, photo=photo_id, caption=message, parse_mode=ParseMode.HTML) - await context.bot.pin_chat_message(chat_id=group_chat_id, message_id=sent_message.message_id, disable_notification=True) - cursor.execute("UPDATE conjuntas SET message_id = ?, message_date = ? WHERE id = ?", (sent_message.message_id, int(time.time()), conjunta_id)) + if message_id_vip != 0: + if (int(time.time()) - int(message_date)) < (24 * 3600 * 2): # borramos el mensaje si tiene más de 1 día + logging.info(f"Updating message for {product_name} - {conjunta_id}") + try: + await context.bot.edit_message_caption(chat_id=vip_group_chat_id, message_id=message_id_vip, caption=message, parse_mode=ParseMode.HTML) + except Exception as e: + logging.error(f"Error editing message: {e}") + else: + logging.info(f"Original message for {product_name} - {conjunta_id} in vip chat is old, unpinning and sending new message") + try: + await context.bot.unpin_chat_message(chat_id=vip_group_chat_id, message_id=message_id_vip) + except Exception as e: + logging.error(f"Error unpinning message: {e}") + sent_message = await context.bot.send_photo(chat_id=vip_group_chat_id, photo=photo_id, caption=message, parse_mode=ParseMode.HTML) + await context.bot.pin_chat_message(chat_id=vip_group_chat_id, message_id=sent_message.message_id, disable_notification=True) + cursor.execute("UPDATE conjuntas SET message_id_vip = ?, message_date = ? WHERE id = ?", (sent_message.message_id, int(time.time()), conjunta_id)) + conn.commit() + logging.info("New message sent and pinned to vip chat") + else: # si por algún motivo no existe el mensaje en el grupo vip, lo enviamos + logging.info("Message didn't exist in VIP group, sending it right now") + sent_message = await context.bot.send_photo(vip_group_chat_id, photo=photo_id, caption='') + + # Anclar el mensaje en el grupo + await context.bot.pin_chat_message(vip_group_chat_id, sent_message.message_id) + + cursor.execute("UPDATE conjuntas SET message_id_general = ? WHERE id=?", (sent_message.message_id, conjunta_id)) conn.commit() - logging.info("New message sent and pinned") + + await update_conjunta(update, context, conjunta_id) + + if message_id_general != 0: # si existe un mensaje en el chat general, comprobamos y actualizamos + if (int(time.time()) - int(message_date)) < (24 * 3600 * 2): # borramos el mensaje si tiene más de 1 día + logging.info(f"Updating message for {product_name} - {conjunta_id}") + try: + await context.bot.edit_message_caption(chat_id=general_group_chat_id, message_id=message_id_general, caption=message, parse_mode=ParseMode.HTML) + except Exception as e: + logging.error(f"Error editing message: {e}") + else: + logging.info(f"Original message for {product_name} - {conjunta_id} in general chat is old, unpinning and sending new message") + try: + await context.bot.unpin_chat_message(chat_id=general_group_chat_id, message_id=message_id_general) + except Exception as e: + logging.error(f"Error unpinning message: {e}") + sent_message = await context.bot.send_photo(chat_id=general_group_chat_id, photo=photo_id, caption=message, parse_mode=ParseMode.HTML) + await context.bot.pin_chat_message(chat_id=general_group_chat_id, message_id=sent_message.message_id, disable_notification=True) + cursor.execute("UPDATE conjuntas SET message_id_general = ?, message_date = ? WHERE id = ?", (sent_message.message_id, int(time.time()), conjunta_id)) + conn.commit() + logging.info("New message sent and pinned to general chat") # Función para unirse a una conjunta async def handle_conjunta(update: Update, context: CallbackContext): @@ -436,13 +468,23 @@ async def handle_conjunta(update: Update, context: CallbackContext): user_id = update.effective_user.id user_name = update.effective_user.username message = update.message.text + group_id = update.message.chat_id + reply_message_id = update.message.reply_to_message.message_id - cursor.execute("SELECT * FROM conjuntas WHERE message_id=?", (reply_message_id,)) + logging.info(f"{user_name} replied to message {reply_message_id} in group {group_id}") + + if group_id == int(general_group_chat_id): + logging.info(f"Retrieving data for general group") + cursor.execute("SELECT * FROM conjuntas WHERE message_id_general=?", (reply_message_id,)) + elif group_id == int(vip_group_chat_id): + logging.info(f"Retrieving data for vip group") + cursor.execute("SELECT * FROM conjuntas WHERE message_id_vip=?", (reply_message_id,)) + conjunta = cursor.fetchone() if conjunta: - conjunta_id, message_id, product_name, product_description, limit, limit_per_user, price, price_member, closed, photo_id, message_date = conjunta + conjunta_id, message_id_general, message_id_vip, product_name, product_description, limit, limit_per_user, price, price_member, closed, photo_id, message_date = conjunta regex_borrar = r'\b(?!apunto)(desapunto|borro|desapuntar|borrar)\b' regex_apuntar = r'\b(apunto|me uno)\b' @@ -543,7 +585,7 @@ async def close_conjunta(update: Update, context: CallbackContext): conjunta = cursor.fetchone() if conjunta: - conjunta_id, message_id, product_name, product_description, limit, limit_per_user, price, price_member, closed, photo_id, message_date = conjunta + conjunta_id, message_id_general, message_id_vip, product_name, product_description, limit, limit_per_user, price, price_member, closed, photo_id, message_date = conjunta if user_id in admin_ids: cursor.execute("UPDATE conjuntas SET closed=1 WHERE id=?", (conjunta_id,)) @@ -563,10 +605,16 @@ async def close_conjunta(update: Update, context: CallbackContext): message += f"\n💰 Precio para socios: {price_member}€\n" message += f"💰 Precio para NO socios: {price}€\n" - await context.bot.send_message(chat_id=group_chat_id, text=message, parse_mode=ParseMode.HTML) + await context.bot.send_message(chat_id=vip_group_chat_id, text=message, parse_mode=ParseMode.HTML) - # Desanclamos el mensaje - await context.bot.unpin_chat_message(group_chat_id, message_id) + # Desanclamos el mensaje del grupo vip + await context.bot.unpin_chat_message(vip_group_chat_id, message_id_vip) + + if message_id_general != 0: + await context.bot.send_message(chat_id=general_group_chat_id, text=message, parse_mode=ParseMode.HTML) + + # Desanclamos el mensaje del grupo general + await context.bot.unpin_chat_message(general_group_chat_id, message_id_general) await context.bot.send_message(chat_id=user_id, text=f"La conjunta para {product_name} ha sido cerrada correctamente.") else: @@ -574,6 +622,30 @@ async def close_conjunta(update: Update, context: CallbackContext): else: await context.bot.send_message(chat_id=user_id, text="La conjunta no existe.") +async def general_conjunta(update: Update, context: CallbackContext): + user_id = update.effective_user.id + query = update.callback_query + await query.answer(text="Abriendo conjunta al chat general") + await query.edit_message_reply_markup(None) + + conjunta_id = int(query.data.split("general ")[1]) + + cursor.execute("SELECT * FROM conjuntas WHERE id=?", (conjunta_id,)) + conjunta = cursor.fetchone() + + if conjunta: + conjunta_id, message_id_general, message_id_vip, product_name, product_description, limit, limit_per_user, price, price_member, closed, photo_id, message_date = conjunta + + sent_message = await context.bot.send_photo(general_group_chat_id, photo=photo_id, caption='') + + # Anclar el mensaje en el grupo + await context.bot.pin_chat_message(general_group_chat_id, sent_message.message_id) + + cursor.execute("UPDATE conjuntas SET message_id_general = ? WHERE id=?", (sent_message.message_id, conjunta_id)) + conn.commit() + + await update_conjunta(update, context, conjunta_id) + # Función para obtener un resumen de las conjuntas activas async def admin_summary(update: Update, context: CallbackContext): user_id = update.effective_user.id @@ -585,7 +657,7 @@ async def admin_summary(update: Update, context: CallbackContext): if conjuntas: summary_text = "Resumen de conjuntas activas:\n\n" for conjunta in conjuntas: - conjunta_id, message_id, product_name, product_description, limit, limit_per_user, price, price_member, closed, photo_id, message_date = conjunta + conjunta_id, message_id_general, message_id_vip, product_name, product_description, limit, limit_per_user, price, price_member, closed, photo_id, message_date = conjunta cursor.execute("SELECT COUNT(*) FROM conjunta_users WHERE conjunta_id=?", (conjunta_id,)) num_users = cursor.fetchone()[0] cursor.execute("SELECT quantity FROM conjunta_users WHERE conjunta_id=?", (conjunta_id,)) @@ -611,10 +683,12 @@ async def admin_summary(update: Update, context: CallbackContext): conjuntas_line = [] count = 0 for conjunta in conjuntas: - conjunta_id, message_id, product_name, product_description, limit, limit_per_user, price, price_member, closed, photo_id, message_date = conjunta + conjunta_id, message_id_general, message_id_vip, product_name, product_description, limit, limit_per_user, price, price_member, closed, photo_id, message_date = conjunta conjuntas_line.append(InlineKeyboardButton(f"ℹ️ {product_name} ({str(conjunta_id)})", callback_data=f"info {str(conjunta_id)}")) conjuntas_line.append(InlineKeyboardButton(f"📝 {product_name} ({str(conjunta_id)})", callback_data=f"edit {str(conjunta_id)}")) conjuntas_line.append(InlineKeyboardButton(f"❌ {product_name} ({str(conjunta_id)})", callback_data=f"close {str(conjunta_id)}")) + if message_id_general == 0: + conjuntas_line.append(InlineKeyboardButton(f"🔓 {product_name} ({str(conjunta_id)})", callback_data=f"general {str(conjunta_id)}")) keyboard.append(conjuntas_line) conjuntas_line = [] reply_markup = InlineKeyboardMarkup(keyboard) @@ -634,7 +708,7 @@ async def show_conjunta_details(update: Update, context: CallbackContext): cursor.execute("SELECT * FROM conjuntas WHERE id = ?", (selected_conjunta_idx,)) conjunta = cursor.fetchone() - conjunta_id, message_id, product_name, product_description, limit, limit_per_user, price, price_member, closed, photo_id, message_date = conjunta + conjunta_id, message_id_general, message_id_vip, product_name, product_description, limit, limit_per_user, price, price_member, closed, photo_id, message_date = conjunta selected_conjunta_details = f"Detalles de la conjunta seleccionada:\n" selected_conjunta_details += f"🛒 {product_name}\n" @@ -700,6 +774,7 @@ def main()->None: application.add_handler(CommandHandler('admin_summary', admin_summary)) application.add_handler(CallbackQueryHandler(show_conjunta_details, pattern="info \d")) application.add_handler(CallbackQueryHandler(close_conjunta, pattern="close \d")) + application.add_handler(CallbackQueryHandler(general_conjunta, pattern="general \d")) application.add_handler(MessageHandler(filters.REPLY, handle_conjunta)) application.add_handler(CommandHandler('help', help)) diff --git a/docker-compose.yml b/docker-compose.yml index 167f83c..903a324 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,10 +1,10 @@ version: "3" services: - conjuntasbot: + conjuntasbot_staging: build: conjuntasbot - image: conjuntasbot - container_name: conjuntasbot + image: conjuntasbot_staging + container_name: conjuntasbot_staging volumes: - ./data:/app/data restart: unless-stopped @@ -12,7 +12,8 @@ services: - TZ="Europe/Madrid" - TELEGRAM_TOKEN=${TELEGRAM_TOKEN} - ADMIN_IDS=${ADMIN_IDS} - - GROUP_CHAT_ID=${GROUP_CHAT_ID} + - GENERAL_GROUP_CHAT_ID=${GENERAL_GROUP_CHAT_ID} + - VIP_GROUP_CHAT_ID=${VIP_GROUP_CHAT_ID} - SPREADSHEET_ID=${SPREADSHEET_ID} dns: - 8.8.8.8 \ No newline at end of file