Skip to content

Commit c76a806

Browse files
committed
feat(admin): paginate /movergrupo to show all groups
- Changed /movergrupo to display a paginated list of all validated groups - Selecting a group opens the category selection InlineKeyboard - This improves UX by removing the need to type exact group names
1 parent 535d978 commit c76a806

2 files changed

Lines changed: 83 additions & 52 deletions

File tree

handlers/admin.py

Lines changed: 30 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -29,53 +29,44 @@ async def joder(update: Update, context: ContextTypes.DEFAULT_TYPE):
2929
logger.error(f"Failed to send joder message: {e}")
3030
await update.message.reply_text(f"Error al enviar el mensaje: {e}")
3131

32+
import math
33+
34+
def get_movergrupo_keyboard(session, page: int = 0, items_per_page: int = 10):
35+
from models import Listable
36+
groups = session.query(Listable).filter_by(validated=True).order_by(Listable.name).all()
37+
total_pages = math.ceil(len(groups) / items_per_page)
38+
39+
start_idx = page * items_per_page
40+
end_idx = start_idx + items_per_page
41+
page_groups = groups[start_idx:end_idx]
42+
43+
keyboard = []
44+
for g in page_groups:
45+
keyboard.append([InlineKeyboardButton(f"{g.name} ({g.type})", callback_data=f"MoverGrupo|Select|{g.id}")])
46+
47+
nav_row = []
48+
if page > 0:
49+
nav_row.append(InlineKeyboardButton("⬅️ Anterior", callback_data=f"MoverGrupo|Page|{page - 1}"))
50+
if page < total_pages - 1:
51+
nav_row.append(InlineKeyboardButton("Siguiente ➡️", callback_data=f"MoverGrupo|Page|{page + 1}"))
52+
53+
if nav_row:
54+
keyboard.append(nav_row)
55+
56+
keyboard.append([InlineKeyboardButton("❌ Cancelar", callback_data="MoverGrupo|Cancel|0")])
57+
return InlineKeyboardMarkup(keyboard)
58+
3259
async def movergrupo(update: Update, context: ContextTypes.DEFAULT_TYPE):
3360
user_id = update.effective_user.id
3461
if user_id not in admin_ids and str(user_id) not in admin_ids:
3562
logger.warning(f"Unauthorized user {user_id} tried to access /movergrupo")
3663
return
3764

38-
if not context.args:
39-
await update.message.reply_text("Uso: /movergrupo <nombre exacto del grupo>")
40-
return
41-
42-
name = " ".join(context.args)
4365
with get_session() as session:
44-
from models import Listable
45-
groups = session.query(Listable).filter(Listable.name.ilike(f"%{name}%")).all()
46-
47-
if not groups:
48-
await update.message.reply_text("No se encontró ningún grupo con ese nombre.")
49-
return
50-
51-
if len(groups) > 1:
52-
names = "\n".join([f"- {g.name} ({g.type})" for g in groups])
53-
await update.message.reply_text(f"Se encontraron múltiples grupos:\n{names}\n\nPor favor, sé más específico.")
54-
return
55-
56-
group = groups[0]
57-
58-
keyboard = [
59-
[
60-
InlineKeyboardButton("Grupo (Oblig.)", callback_data=f"MoverGrupo|{group.id}|Grupo"),
61-
InlineKeyboardButton("GrupoOptativa", callback_data=f"MoverGrupo|{group.id}|GrupoOptativa"),
62-
InlineKeyboardButton("ECI", callback_data=f"MoverGrupo|{group.id}|ECI")
63-
],
64-
[
65-
InlineKeyboardButton("Otro", callback_data=f"MoverGrupo|{group.id}|Otro"),
66-
InlineKeyboardButton("GrupoOtros", callback_data=f"MoverGrupo|{group.id}|GrupoOtros"),
67-
InlineKeyboardButton("Obligatoria (viejo)", callback_data=f"MoverGrupo|{group.id}|Obligatoria"),
68-
],
69-
[
70-
InlineKeyboardButton("Optativa (viejo)", callback_data=f"MoverGrupo|{group.id}|Optativa"),
71-
InlineKeyboardButton("Cancelar", callback_data=f"MoverGrupo|{group.id}|Cancelar")
72-
]
73-
]
74-
reply_markup = InlineKeyboardMarkup(keyboard)
66+
reply_markup = get_movergrupo_keyboard(session, page=0)
7567
await update.message.reply_text(
76-
f"Seleccioná la nueva categoría para el grupo:\n\n*Nombre:* {group.name}\n*Categoría Actual:* {group.type}",
77-
reply_markup=reply_markup,
78-
parse_mode=ParseMode.MARKDOWN
68+
"Seleccioná el grupo que querés recategorizar:",
69+
reply_markup=reply_markup
7970
)
8071

8172
async def checodepers(update: Update, context: ContextTypes.DEFAULT_TYPE):

handlers/callbacks.py

Lines changed: 53 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -31,21 +31,61 @@ async def button(update: Update, context: ContextTypes.DEFAULT_TYPE):
3131
await query.edit_message_text(text=message.text + "\n[Botón huérfano: El grupo ya no existe en la base de datos]")
3232

3333
elif buttonType == "MoverGrupo":
34-
if action == "Cancelar":
35-
await query.edit_message_text(text=f"❌ Operación cancelada para el grupo ID {id_val}.")
34+
sub_action = id_val
35+
value = action
36+
37+
if sub_action == "Cancel":
38+
await query.edit_message_text(text="❌ Operación cancelada.")
3639
return
40+
elif sub_action == "Page":
41+
from handlers.admin import get_movergrupo_keyboard
42+
reply_markup = get_movergrupo_keyboard(session, page=int(value))
43+
await query.edit_message_text(
44+
text="Seleccioná el grupo que querés recategorizar:",
45+
reply_markup=reply_markup
46+
)
47+
return
48+
elif sub_action == "Select":
49+
group = session.query(Listable).filter_by(id=int(value)).first()
50+
if not group:
51+
await query.edit_message_text(text="[Botón huérfano: El grupo ya no existe]")
52+
return
3753

38-
group = session.query(Listable).filter_by(id=int(id_val)).first()
39-
if group:
40-
old_type = group.type
41-
new_type = action
42-
# Update the polymorphic identity directly via the type column
43-
group.type = new_type
44-
# Depending on SQLAlchemy, modifying the polymorphic column directly might require
45-
# a raw SQL update or session.flush() to be safe. We'll rely on SQLAlchemy's update.
46-
await query.edit_message_text(text=f"✅ Grupo *{group.name}* movido exitosamente:\nDe `{old_type}` ➡️ a `{new_type}`", parse_mode=ParseMode.MARKDOWN)
47-
else:
48-
await query.edit_message_text(text=message.text + "\n[Botón huérfano: El grupo ya no existe]")
54+
from telegram import InlineKeyboardButton, InlineKeyboardMarkup
55+
keyboard = [
56+
[
57+
InlineKeyboardButton("Grupo (Oblig.)", callback_data=f"MoverGrupo|Move|{group.id}|Grupo"),
58+
InlineKeyboardButton("GrupoOptativa", callback_data=f"MoverGrupo|Move|{group.id}|GrupoOptativa"),
59+
InlineKeyboardButton("ECI", callback_data=f"MoverGrupo|Move|{group.id}|ECI")
60+
],
61+
[
62+
InlineKeyboardButton("Otro", callback_data=f"MoverGrupo|Move|{group.id}|Otro"),
63+
InlineKeyboardButton("GrupoOtros", callback_data=f"MoverGrupo|Move|{group.id}|GrupoOtros"),
64+
InlineKeyboardButton("Obligatoria (v.)", callback_data=f"MoverGrupo|Move|{group.id}|Obligatoria")
65+
],
66+
[
67+
InlineKeyboardButton("Optativa (v.)", callback_data=f"MoverGrupo|Move|{group.id}|Optativa"),
68+
InlineKeyboardButton("❌ Cancelar", callback_data="MoverGrupo|Cancel|0")
69+
]
70+
]
71+
await query.edit_message_text(
72+
text=f"Seleccioná la nueva categoría para el grupo:\n\n*Nombre:* {group.name}\n*Categoría Actual:* {group.type}",
73+
reply_markup=InlineKeyboardMarkup(keyboard),
74+
parse_mode=ParseMode.MARKDOWN
75+
)
76+
return
77+
elif sub_action == "Move":
78+
group_id = int(data_parts[2])
79+
new_type = data_parts[3]
80+
81+
group = session.query(Listable).filter_by(id=group_id).first()
82+
if group:
83+
old_type = group.type
84+
group.type = new_type
85+
await query.edit_message_text(text=f"✅ Grupo *{group.name}* movido exitosamente:\nDe `{old_type}` ➡️ a `{new_type}`", parse_mode=ParseMode.MARKDOWN)
86+
else:
87+
await query.edit_message_text(text="[Botón huérfano: El grupo ya no existe]")
88+
return
4989

5090
elif buttonType == "Noticia":
5191
noticia = session.query(Noticia).filter_by(id=int(id_val)).first()

0 commit comments

Comments
 (0)