Finally made it multichannel

This commit is contained in:
Joan
2024-02-16 20:28:54 +01:00
parent 4b30aa30f5
commit 5ba4228fcf
2 changed files with 115 additions and 39 deletions

View File

@@ -24,7 +24,8 @@ httpx_logger.setLevel(logging.WARNING)
# Cargar los identificadores de administradores desde la variable de entorno # 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(",")] 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") bot_token = os.environ.get("TELEGRAM_TOKEN")
spreadsheet_id = os.environ.get("SPREADSHEET_ID") spreadsheet_id = os.environ.get("SPREADSHEET_ID")
@@ -33,7 +34,8 @@ conn = sqlite3.connect('/app/data/conjuntas.db')
cursor = conn.cursor() cursor = conn.cursor()
cursor.execute('''CREATE TABLE IF NOT EXISTS conjuntas ( cursor.execute('''CREATE TABLE IF NOT EXISTS conjuntas (
id INTEGER PRIMARY KEY AUTOINCREMENT, id INTEGER PRIMARY KEY AUTOINCREMENT,
message_id INTEGER, message_id_general INTEGER,
message_id_vip INTEGER,
product_name TEXT, product_name TEXT,
product_description TEXT, product_description TEXT,
limite INTEGER, limite INTEGER,
@@ -99,7 +101,7 @@ async def edit_conjunta(update: Update, context: CallbackContext):
conjunta = cursor.fetchone() conjunta = cursor.fetchone()
if conjunta: 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['product_name'] = product_name
context.user_data['original_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.") await update.message.reply_text("Por favor, introduce un número válido como límite.")
return LIMIT_PER_USER 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): async def add_and_send(update: Update, context: CallbackContext, message):
product_name = context.user_data['product_name'] product_name = context.user_data['product_name']
limit = context.user_data['limit'] 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'] price_member = context.user_data['price_member']
if not context.user_data['edit']: 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 (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", 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 (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
(sent_message.message_id, product_name, product_description, price, price_member, limit, limit_per_user, 0, photo_id, int(time.time()))) (0, sent_message.message_id, product_name, product_description, price, price_member, limit, limit_per_user, 0, photo_id, int(time.time())))
conn.commit() conn.commit()
conjunta_id = cursor.lastrowid conjunta_id = cursor.lastrowid
# Creamos una nueva hoja en el documento # Creamos una nueva hoja en el documento
worksheet = spreadsheet.add_worksheet(title=f"{product_name} - {conjunta_id}", rows=1, cols=3) 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"]) worksheet.append_row(["Usuario", "Cantidad", "Socio"])
# Anclar el mensaje en el grupo # 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: else:
conjunta_id = context.user_data['conjunta_id'] 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)) 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() conjunta = cursor.fetchone()
if conjunta: 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 🛒 <b>{product_name}</b>\n\n" message = f"Conjunta para 🛒 <b>{product_name}</b>\n\n"
if limit: if limit:
@@ -412,23 +413,54 @@ async def update_conjunta(update: Update, context: CallbackContext, conjunta_id)
# quantity_string = "unidades" if quantity > 1 else "unidad" # quantity_string = "unidades" if quantity > 1 else "unidad"
# message += f"@{user_name} - {quantity} {quantity_string}\n" # message += f"@{user_name} - {quantity} {quantity_string}\n"
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 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}") logging.info(f"Updating message for {product_name} - {conjunta_id}")
try: try:
await context.bot.edit_message_caption(chat_id=group_chat_id, message_id=message_id, caption=message, parse_mode=ParseMode.HTML) 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: except Exception as e:
logging.error(f"Error editing message: {e}") logging.error(f"Error editing message: {e}")
else: else:
logging.info(f"Original message for {product_name} - {conjunta_id} is old, unpinning and sending new message") logging.info(f"Original message for {product_name} - {conjunta_id} in vip chat is old, unpinning and sending new message")
try: try:
await context.bot.unpin_chat_message(chat_id=group_chat_id, message_id=message_id) await context.bot.unpin_chat_message(chat_id=vip_group_chat_id, message_id=message_id_vip)
except Exception as e: except Exception as e:
logging.error(f"Error unpinning message: {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) 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=group_chat_id, message_id=sent_message.message_id, disable_notification=True) 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 = ?, message_date = ? WHERE id = ?", (sent_message.message_id, int(time.time()), conjunta_id)) cursor.execute("UPDATE conjuntas SET message_id_vip = ?, message_date = ? WHERE id = ?", (sent_message.message_id, int(time.time()), conjunta_id))
conn.commit() conn.commit()
logging.info("New message sent and pinned") 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()
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 # Función para unirse a una conjunta
async def handle_conjunta(update: Update, context: CallbackContext): 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_id = update.effective_user.id
user_name = update.effective_user.username user_name = update.effective_user.username
message = update.message.text message = update.message.text
group_id = update.message.chat_id
reply_message_id = update.message.reply_to_message.message_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() conjunta = cursor.fetchone()
if conjunta: 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_borrar = r'\b(?!apunto)(desapunto|borro|desapuntar|borrar)\b'
regex_apuntar = r'\b(apunto|me uno)\b' regex_apuntar = r'\b(apunto|me uno)\b'
@@ -543,7 +585,7 @@ async def close_conjunta(update: Update, context: CallbackContext):
conjunta = cursor.fetchone() conjunta = cursor.fetchone()
if conjunta: 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: if user_id in admin_ids:
cursor.execute("UPDATE conjuntas SET closed=1 WHERE id=?", (conjunta_id,)) 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: <b>{price_member}€</b>\n" message += f"\n💰 Precio para socios: <b>{price_member}€</b>\n"
message += f"💰 Precio para NO socios: <b>{price}€</b>\n" message += f"💰 Precio para NO socios: <b>{price}€</b>\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 # Desanclamos el mensaje del grupo vip
await context.bot.unpin_chat_message(group_chat_id, message_id) 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.") await context.bot.send_message(chat_id=user_id, text=f"La conjunta para {product_name} ha sido cerrada correctamente.")
else: else:
@@ -574,6 +622,30 @@ async def close_conjunta(update: Update, context: CallbackContext):
else: else:
await context.bot.send_message(chat_id=user_id, text="La conjunta no existe.") 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 # Función para obtener un resumen de las conjuntas activas
async def admin_summary(update: Update, context: CallbackContext): async def admin_summary(update: Update, context: CallbackContext):
user_id = update.effective_user.id user_id = update.effective_user.id
@@ -585,7 +657,7 @@ async def admin_summary(update: Update, context: CallbackContext):
if conjuntas: if conjuntas:
summary_text = "Resumen de conjuntas activas:\n\n" summary_text = "Resumen de conjuntas activas:\n\n"
for conjunta in conjuntas: 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,)) cursor.execute("SELECT COUNT(*) FROM conjunta_users WHERE conjunta_id=?", (conjunta_id,))
num_users = cursor.fetchone()[0] num_users = cursor.fetchone()[0]
cursor.execute("SELECT quantity FROM conjunta_users WHERE conjunta_id=?", (conjunta_id,)) 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 = [] conjuntas_line = []
count = 0 count = 0
for conjunta in conjuntas: 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"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"edit {str(conjunta_id)}"))
conjuntas_line.append(InlineKeyboardButton(f"{product_name} ({str(conjunta_id)})", callback_data=f"close {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) keyboard.append(conjuntas_line)
conjuntas_line = [] conjuntas_line = []
reply_markup = InlineKeyboardMarkup(keyboard) 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,)) cursor.execute("SELECT * FROM conjuntas WHERE id = ?", (selected_conjunta_idx,))
conjunta = cursor.fetchone() 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"Detalles de la conjunta seleccionada:\n"
selected_conjunta_details += f"🛒 <b>{product_name}</b>\n" selected_conjunta_details += f"🛒 <b>{product_name}</b>\n"
@@ -700,6 +774,7 @@ def main()->None:
application.add_handler(CommandHandler('admin_summary', admin_summary)) application.add_handler(CommandHandler('admin_summary', admin_summary))
application.add_handler(CallbackQueryHandler(show_conjunta_details, pattern="info \d")) application.add_handler(CallbackQueryHandler(show_conjunta_details, pattern="info \d"))
application.add_handler(CallbackQueryHandler(close_conjunta, pattern="close \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(MessageHandler(filters.REPLY, handle_conjunta))
application.add_handler(CommandHandler('help', help)) application.add_handler(CommandHandler('help', help))

View File

@@ -1,10 +1,10 @@
version: "3" version: "3"
services: services:
conjuntasbot: conjuntasbot_staging:
build: conjuntasbot build: conjuntasbot
image: conjuntasbot image: conjuntasbot_staging
container_name: conjuntasbot container_name: conjuntasbot_staging
volumes: volumes:
- ./data:/app/data - ./data:/app/data
restart: unless-stopped restart: unless-stopped
@@ -12,7 +12,8 @@ services:
- TZ="Europe/Madrid" - TZ="Europe/Madrid"
- TELEGRAM_TOKEN=${TELEGRAM_TOKEN} - TELEGRAM_TOKEN=${TELEGRAM_TOKEN}
- ADMIN_IDS=${ADMIN_IDS} - 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} - SPREADSHEET_ID=${SPREADSHEET_ID}
dns: dns:
- 8.8.8.8 - 8.8.8.8