version 1.4.4: MarkdownV2 dot escape fix в show_users, try/except для бота

- bot.py: числа трафика в бэктиках (избегание unescaped dots в MarkdownV2)
- bot.py: try/except в show_users с выводом ошибки пользователю
This commit is contained in:
2026-06-29 19:25:43 +03:00
parent 4a3e22e08e
commit 8242027859
+87 -78
View File
@@ -150,88 +150,97 @@ async def show_main(update: Update, context: ContextTypes.DEFAULT_TYPE):
async def show_users(update: Update, context: ContextTypes.DEFAULT_TYPE): async def show_users(update: Update, context: ContextTypes.DEFAULT_TYPE):
query = update.callback_query query = update.callback_query
await query.answer() await query.answer()
cfg = load_mita_config() try:
users = cfg.get("users", []) cfg = load_mita_config()
if not users: users = cfg.get("users", [])
await query.edit_message_text("👤 Нет пользователей.", reply_markup=back_button()) if not users:
return await query.edit_message_text("👤 Нет пользователей.", reply_markup=back_button())
return
raw = mita_cmd("get", "users") raw = mita_cmd("get", "users")
pc = load_panel_config() pc = load_panel_config()
warp_users = set(pc.get("warp_users", [])) warp_users = set(pc.get("warp_users", []))
today = datetime.now().date() today = datetime.now().date()
stats_map = {} stats_map = {}
for line in raw.splitlines(): for line in raw.splitlines():
line = line.strip() line = line.strip()
if not line or line.upper().startswith("USER"): if not line or line.upper().startswith("USER"):
continue continue
parts = line.split() parts = line.split()
if len(parts) < 8: if len(parts) < 8:
continue continue
try:
name = parts[0]
d1_bytes = _parse_traffic(parts[2]) + _parse_traffic(parts[3])
d7_bytes = _parse_traffic(parts[4]) + _parse_traffic(parts[5])
d30_bytes = _parse_traffic(parts[6]) + _parse_traffic(parts[7])
online = False
la_raw = parts[1]
if la_raw and la_raw.lower() not in ("never","-","n/a","никогда"):
try:
la_date = datetime.strptime(la_raw[:10], "%Y-%m-%d").date()
if (today - la_date).days == 0:
online = True
except Exception:
pass
stats_map[name] = {"online": online,
"day_mb": round(d1_bytes/1024/1024, 2),
"week_mb": round(d7_bytes/1024/1024, 2),
"month_mb": round(d30_bytes/1024/1024, 2)}
except Exception:
continue
lines = ["👥 *Пользователи*\n"]
user_buttons = []
for u in users:
name = u["name"]
s = stats_map.get(name, {})
w = "🟢" if name in warp_users else ""
o = "🟢" if s.get("online") else "🔴"
day = f"`{s.get('day_mb', 0):.1f} МБ`" if s.get("day_mb") else ""
mon = f"`{s.get('month_mb', 0):.1f} МБ`" if s.get("month_mb") else ""
ename = escape_md(name)
lines.append(f"{o} {ename} {w} д:{day} м:{mon}")
user_buttons.append([InlineKeyboardButton(
f"{'🟢 ' if s.get('online') else ''}{name}",
callback_data=f"user_{name}"
)])
user_buttons.extend([
[InlineKeyboardButton(" Создать", callback_data="create"),
InlineKeyboardButton("🗑 Удалить", callback_data="delete_menu")],
[InlineKeyboardButton("🔄 WARP", callback_data="warp_menu")],
[InlineKeyboardButton("« Назад", callback_data="main")],
])
text = "\n".join(lines)
if len(text) > 4000:
text = text[:3997] + ""
if len(user_buttons) > 96:
user_buttons = user_buttons[:96]
await query.edit_message_text(
text,
reply_markup=InlineKeyboardMarkup(user_buttons),
parse_mode="MarkdownV2"
)
except Exception as e:
_log.error("show_users failed: %s", e, exc_info=True)
try: try:
name = parts[0] await query.edit_message_text(
d1_bytes = _parse_traffic(parts[2]) + _parse_traffic(parts[3]) f"⚠ Ошибка загрузки пользователей:\n`{e}`",
d7_bytes = _parse_traffic(parts[4]) + _parse_traffic(parts[5]) reply_markup=back_button(),
d30_bytes = _parse_traffic(parts[6]) + _parse_traffic(parts[7]) parse_mode="MarkdownV2"
online = False )
la_raw = parts[1]
if la_raw and la_raw.lower() not in ("never","-","n/a","никогда"):
try:
la_date = datetime.strptime(la_raw[:10], "%Y-%m-%d").date()
if (today - la_date).days == 0:
online = True
except Exception:
pass
stats_map[name] = {"online": online,
"day_mb": round(d1_bytes/1024/1024, 2),
"week_mb": round(d7_bytes/1024/1024, 2),
"month_mb": round(d30_bytes/1024/1024, 2)}
except Exception: except Exception:
continue pass
except Exception as e:
lines = ["👥 *Пользователи*\n"] _log.error("show_users failed: %s", e)
user_buttons = [] await query.edit_message_text(
for u in users: f"⚠ Ошибка: {e}",
name = u["name"] reply_markup=back_button()
s = stats_map.get(name, {}) )
w = "🟢" if name in warp_users else ""
o = "🟢" if s.get("online") else "🔴"
day = f"{s.get('day_mb', 0):.1f} МБ" if s.get("day_mb") else ""
mon = f"{s.get('month_mb', 0):.1f} МБ" if s.get("month_mb") else ""
ename = escape_md(name)
lines.append(f"{o} {ename} {w} д:{day} м:{mon}")
user_buttons.append([InlineKeyboardButton(
f"{'🟢 ' if s.get('online') else ''}{name}",
callback_data=f"user_{name}"
)])
# Ограничение Telegram: 4096 символов на сообщение
text = "\n".join(lines)
if len(text) > 4000:
text = text[:3997] + ""
if len(user_buttons) > 96:
user_buttons = user_buttons[:96]
user_buttons.extend([
[InlineKeyboardButton(" Создать", callback_data="create"),
InlineKeyboardButton("🗑 Удалить", callback_data="delete_menu")],
[InlineKeyboardButton("🔄 WARP", callback_data="warp_menu")],
[InlineKeyboardButton("« Назад", callback_data="main")],
])
user_buttons.extend([
[InlineKeyboardButton(" Создать", callback_data="create"),
InlineKeyboardButton("🗑 Удалить", callback_data="delete_menu")],
[InlineKeyboardButton("🔄 WARP", callback_data="warp_menu")],
[InlineKeyboardButton("« Назад", callback_data="main")],
])
await query.edit_message_text(
text,
reply_markup=InlineKeyboardMarkup(user_buttons),
parse_mode="MarkdownV2"
)
# ── create ──────────────────────────────────────────────────────────────────── # ── create ────────────────────────────────────────────────────────────────────
@admin_only @admin_only