164 lines
7.0 KiB
Python
164 lines
7.0 KiB
Python
from telegram import InlineKeyboardMarkup, InlineKeyboardButton
|
||
from database import get_participants, get_active_raffles
|
||
from config import *
|
||
|
||
def generate_numbers_keyboard(raffle_id, user_id, page=0):
|
||
"""Generates the 10x10 number selection keyboard with status icons and paging."""
|
||
participants = get_participants(raffle_id)
|
||
taken_numbers = {}
|
||
user_reserved = set()
|
||
user_taken = set()
|
||
|
||
# Process participants to determine number statuses
|
||
if participants:
|
||
for participant in participants:
|
||
participant_id = participant['user_id']
|
||
numbers = participant['numbers']
|
||
step = participant['step']
|
||
|
||
if numbers: # Ensure numbers is not None or empty
|
||
try:
|
||
numbers_set = {int(n) for n in numbers.split(',') if n.isdigit()} # Safer conversion
|
||
|
||
if participant_id == user_id:
|
||
if step == "waiting_for_payment":
|
||
user_reserved.update(numbers_set)
|
||
elif step == "completed":
|
||
user_taken.update(numbers_set)
|
||
|
||
for num in numbers_set:
|
||
# Store only if not already taken by the current user (avoids overwriting user status)
|
||
if num not in user_taken and num not in user_reserved:
|
||
taken_numbers[num] = participant_id # Track who took it generally
|
||
except ValueError:
|
||
logging.warning(f"Invalid number format in participant data for raffle {raffle_id}: {numbers}")
|
||
continue # Skip this participant's numbers if format is wrong
|
||
|
||
# Build the keyboard grid
|
||
keyboard = []
|
||
rows = 10
|
||
cols = 5
|
||
start = page * rows * cols
|
||
end = start + rows * cols
|
||
|
||
for i in range(rows):
|
||
row_buttons = []
|
||
for j in range(cols):
|
||
num = start + i * cols + j
|
||
if num >= 100: # Ensure we don't go beyond 99
|
||
break
|
||
num_str = f"{num:02}"
|
||
|
||
# Determine icon based on status
|
||
if num in user_taken:
|
||
icon = "⭐️" # Taken (Paid) by this user
|
||
elif num in user_reserved:
|
||
icon = "⏳" # Reserved (Not paid) by this user
|
||
elif num in taken_numbers: # Check general taken status *after* specific user status
|
||
icon = "🚫" # Taken by someone else
|
||
else:
|
||
icon = "🟦" # Free
|
||
|
||
row_buttons.append(InlineKeyboardButton(f"{icon} {num_str}", callback_data=f"number:{raffle_id}:{num}"))
|
||
if row_buttons: # Only add row if it contains buttons
|
||
keyboard.append(row_buttons)
|
||
|
||
# Add Paging Buttons
|
||
paging_buttons = []
|
||
if page > 0:
|
||
paging_buttons.append(InlineKeyboardButton("⬅️ Anterior", callback_data=f"number:{raffle_id}:prev"))
|
||
if end < 100: # Only show next if there are more numbers
|
||
paging_buttons.append(InlineKeyboardButton("Siguiente ➡️", callback_data=f"number:{raffle_id}:next"))
|
||
if paging_buttons:
|
||
keyboard.append(paging_buttons)
|
||
|
||
#action_buttons_row = [
|
||
# InlineKeyboardButton("✨ Número Aleatorio ✨", callback_data=f"random_num:{raffle_id}")
|
||
#]
|
||
#keyboard.append(action_buttons_row)
|
||
|
||
# Add Confirm/Cancel Buttons
|
||
confirm_cancel_row = [
|
||
InlineKeyboardButton("👍 Confirmar Selección", callback_data=f"confirm:{raffle_id}"),
|
||
InlineKeyboardButton("❌ Cancelar Selección", callback_data=f"cancel:{raffle_id}")
|
||
]
|
||
keyboard.append(confirm_cancel_row)
|
||
|
||
return InlineKeyboardMarkup(keyboard)
|
||
|
||
# --- Admin Menu Keyboards ---
|
||
|
||
def generate_admin_main_menu_keyboard():
|
||
keyboard = [
|
||
[InlineKeyboardButton("➕ Crear Nuevo Sorteo", callback_data=ADMIN_MENU_CREATE)],
|
||
[InlineKeyboardButton("📋 Listar/Gestionar Sorteos", callback_data=ADMIN_MENU_LIST)],
|
||
]
|
||
return InlineKeyboardMarkup(keyboard)
|
||
|
||
|
||
def generate_admin_list_raffles_keyboard():
|
||
"""Generates keyboard listing active raffles with management buttons."""
|
||
active_raffles = get_active_raffles()
|
||
keyboard = []
|
||
|
||
if not active_raffles:
|
||
keyboard.append([InlineKeyboardButton("No hay sorteos activos.", callback_data=ADMIN_NO_OP)])
|
||
else:
|
||
for raffle in active_raffles:
|
||
raffle_id = raffle['id']
|
||
raffle_name = raffle['name']
|
||
# Row for each raffle: Name Button (View Details), Announce Button, End Button
|
||
keyboard.append([
|
||
InlineKeyboardButton(f"ℹ️ {raffle_name}", callback_data=f"{ADMIN_VIEW_RAFFLE_PREFIX}{raffle_id}"),
|
||
InlineKeyboardButton("📢 Anunciar", callback_data=f"{ADMIN_ANNOUNCE_RAFFLE_PREFIX}{raffle_id}"),
|
||
InlineKeyboardButton("🏁 Terminar", callback_data=f"{ADMIN_END_RAFFLE_PROMPT_PREFIX}{raffle_id}")
|
||
])
|
||
|
||
keyboard.append([InlineKeyboardButton("⬅️ Volver al Menú Principal", callback_data=ADMIN_MENU_BACK_MAIN)])
|
||
return InlineKeyboardMarkup(keyboard)
|
||
|
||
def generate_admin_raffle_details_keyboard(raffle_id):
|
||
"""Generates keyboard for the raffle detail view."""
|
||
keyboard = [
|
||
# Add relevant actions here if needed later, e.g., edit description?
|
||
[InlineKeyboardButton("📢 Anunciar de Nuevo", callback_data=f"{ADMIN_ANNOUNCE_RAFFLE_PREFIX}{raffle_id}")],
|
||
[InlineKeyboardButton("🔄 Actualizar Imagen", callback_data=f"{ADMIN_UPDATE_IMAGE_PREFIX}{raffle_id}")],
|
||
[InlineKeyboardButton("🏁 Terminar Sorteo", callback_data=f"{ADMIN_END_RAFFLE_PROMPT_PREFIX}{raffle_id}")],
|
||
[InlineKeyboardButton("⬅️ Volver a la Lista", callback_data=ADMIN_MENU_LIST)] # Back to list view
|
||
]
|
||
return InlineKeyboardMarkup(keyboard)
|
||
|
||
def generate_admin_cancel_end_keyboard():
|
||
"""Generates a simple cancel button during the end process."""
|
||
keyboard = [
|
||
[InlineKeyboardButton("❌ Cancelar Finalización", callback_data=ADMIN_CANCEL_END_PROCESS)]
|
||
]
|
||
return InlineKeyboardMarkup(keyboard)
|
||
|
||
# --- Keyboards for Raffle Creation Conversation ---
|
||
|
||
def generate_channel_selection_keyboard():
|
||
"""Generates keyboard for admin to select target channels."""
|
||
|
||
buttons = []
|
||
for alias, channel_id in CHANNELS.items():
|
||
text = alias
|
||
buttons.append([InlineKeyboardButton(text, callback_data=f"{SELECT_CHANNEL_PREFIX}{channel_id}")])
|
||
|
||
return InlineKeyboardMarkup(buttons)
|
||
|
||
def generate_confirmation_keyboard():
|
||
"""Generates Yes/No keyboard for final confirmation."""
|
||
keyboard = [
|
||
[
|
||
InlineKeyboardButton("✅ Sí, crear sorteo", callback_data=CONFIRM_CREATION_CALLBACK),
|
||
InlineKeyboardButton("❌ No, cancelar", callback_data=CANCEL_CREATION_CALLBACK),
|
||
]
|
||
]
|
||
return InlineKeyboardMarkup(keyboard)
|
||
|
||
def generate_channel_participate_keyboard(raffle_id):
|
||
# The deep link URL opens a private chat with the bot
|
||
url = f"https://t.me/{BOT_NAME }?start=join_{raffle_id}"
|
||
keyboard = [[InlineKeyboardButton("✅ ¡Participar Ahora! ✅", url=url)]]
|
||
return InlineKeyboardMarkup(keyboard) |