Админ-панель в боте: кнопка «Админка» и разделы кнопками
- В главном меню у администраторов появляется кнопка «Админка ⚙️» (видна только в сообщениях админу; не-админа код всё равно не пускает). - Админ-панель с кнопками: Статистика, Управление услугами, Рассылка, В главное меню — вместо запоминания текстовых команд. - Доступ строго по config.ADMIN_IDS на сервере. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -71,8 +71,8 @@ def is_valid_name(text: str) -> bool:
|
|||||||
# КЛАВИАТУРЫ ДЛЯ ИНТЕРФЕЙСА (UX/UI ВКонтакте)
|
# КЛАВИАТУРЫ ДЛЯ ИНТЕРФЕЙСА (UX/UI ВКонтакте)
|
||||||
# ==========================================
|
# ==========================================
|
||||||
|
|
||||||
def get_main_keyboard() -> str:
|
def get_main_keyboard(is_admin: bool = False) -> str:
|
||||||
"""Главное меню бота."""
|
"""Главное меню бота. Для админа добавляется кнопка «Админка ⚙️»."""
|
||||||
keyboard = VkKeyboard(one_time=False)
|
keyboard = VkKeyboard(one_time=False)
|
||||||
# Кнопка начать опрос (зеленая)
|
# Кнопка начать опрос (зеленая)
|
||||||
keyboard.add_button("Заполнить заявку 📝", color=VkKeyboardColor.PRIMARY)
|
keyboard.add_button("Заполнить заявку 📝", color=VkKeyboardColor.PRIMARY)
|
||||||
@@ -83,6 +83,23 @@ def get_main_keyboard() -> str:
|
|||||||
# Кнопки FAQ и оператора
|
# Кнопки FAQ и оператора
|
||||||
keyboard.add_button("Частые вопросы ❓", color=VkKeyboardColor.SECONDARY)
|
keyboard.add_button("Частые вопросы ❓", color=VkKeyboardColor.SECONDARY)
|
||||||
keyboard.add_button("Позвать оператора 🧑💼", color=VkKeyboardColor.NEGATIVE)
|
keyboard.add_button("Позвать оператора 🧑💼", color=VkKeyboardColor.NEGATIVE)
|
||||||
|
# Кнопка админ-панели — только для администраторов (отдельной строкой)
|
||||||
|
if is_admin:
|
||||||
|
keyboard.add_line()
|
||||||
|
keyboard.add_button("Админка ⚙️", color=VkKeyboardColor.PRIMARY)
|
||||||
|
return keyboard.get_keyboard()
|
||||||
|
|
||||||
|
|
||||||
|
def get_admin_keyboard() -> str:
|
||||||
|
"""Клавиатура админ-панели с разделами."""
|
||||||
|
keyboard = VkKeyboard(one_time=False)
|
||||||
|
keyboard.add_button("Статистика 📊", color=VkKeyboardColor.SECONDARY)
|
||||||
|
keyboard.add_line()
|
||||||
|
keyboard.add_button("Управление услугами ⚙️", color=VkKeyboardColor.SECONDARY)
|
||||||
|
keyboard.add_line()
|
||||||
|
keyboard.add_button("Рассылка 📣", color=VkKeyboardColor.SECONDARY)
|
||||||
|
keyboard.add_line()
|
||||||
|
keyboard.add_button("В главное меню ↩️", color=VkKeyboardColor.PRIMARY)
|
||||||
return keyboard.get_keyboard()
|
return keyboard.get_keyboard()
|
||||||
|
|
||||||
|
|
||||||
@@ -343,6 +360,22 @@ class VKBotApplication:
|
|||||||
self._msg_times[user_id] = times
|
self._msg_times[user_id] = times
|
||||||
return len(times) > FLOOD_MAX_MSGS
|
return len(times) > FLOOD_MAX_MSGS
|
||||||
|
|
||||||
|
def _is_admin(self, user_id: int) -> bool:
|
||||||
|
"""Является ли пользователь администратором (по config.ADMIN_IDS)."""
|
||||||
|
return hasattr(config, "ADMIN_IDS") and user_id in config.ADMIN_IDS
|
||||||
|
|
||||||
|
def _send_admin_panel(self, user_id: int):
|
||||||
|
"""Главный экран админ-панели с кнопками разделов."""
|
||||||
|
self.send_message(
|
||||||
|
user_id,
|
||||||
|
"⚙️ Админ-панель ИКП\n\n"
|
||||||
|
"Выберите раздел на кнопках ниже:\n"
|
||||||
|
"• 📊 Статистика — заявки, отклики, диалоги\n"
|
||||||
|
"• ⚙️ Управление услугами — добавить/изменить/удалить\n"
|
||||||
|
"• 📣 Рассылка — сообщение подписчикам",
|
||||||
|
keyboard=get_admin_keyboard()
|
||||||
|
)
|
||||||
|
|
||||||
def _notify_allowed(self, user_id: int) -> bool:
|
def _notify_allowed(self, user_id: int) -> bool:
|
||||||
"""Антиспам: не чаще раза в NOTIFY_COOLDOWN_SEC уведомляем оператора об одном пользователе."""
|
"""Антиспам: не чаще раза в NOTIFY_COOLDOWN_SEC уведомляем оператора об одном пользователе."""
|
||||||
now = time.time()
|
now = time.time()
|
||||||
@@ -377,11 +410,24 @@ class VKBotApplication:
|
|||||||
user_data = db.get_user_data(user_id)
|
user_data = db.get_user_data(user_id)
|
||||||
state = user_data["state"]
|
state = user_data["state"]
|
||||||
|
|
||||||
# Глобальная обработка админ-команд (доступна только пользователям из ADMIN_IDS)
|
# Глобальная обработка админ-команд и кнопок (только для ADMIN_IDS)
|
||||||
if hasattr(config, "ADMIN_IDS") and user_id in config.ADMIN_IDS:
|
if self._is_admin(user_id):
|
||||||
if text_lower in ["админка", "/admin", "услуги"]:
|
if text_lower in ["админка", "админка ⚙️", "/admin"]:
|
||||||
|
self._send_admin_panel(user_id)
|
||||||
|
return
|
||||||
|
elif text_lower in ["статистика 📊", "стата", "статистика", "/stats"]:
|
||||||
|
self._handle_admin_stats(user_id)
|
||||||
|
return
|
||||||
|
elif text_lower in ["управление услугами ⚙️", "управление услугами", "услуги"]:
|
||||||
self._send_admin_menu(user_id)
|
self._send_admin_menu(user_id)
|
||||||
return
|
return
|
||||||
|
elif text_lower in ["рассылка 📣", "рассылка"]:
|
||||||
|
# Кнопка без текста — показываем инструкцию
|
||||||
|
self._handle_admin_broadcast(user_id, "рассылка")
|
||||||
|
return
|
||||||
|
elif text_lower.startswith("рассылка"):
|
||||||
|
self._handle_admin_broadcast(user_id, text_clean)
|
||||||
|
return
|
||||||
elif text_lower.startswith("ред "):
|
elif text_lower.startswith("ред "):
|
||||||
self._handle_admin_edit(user_id, text_clean)
|
self._handle_admin_edit(user_id, text_clean)
|
||||||
return
|
return
|
||||||
@@ -391,11 +437,11 @@ class VKBotApplication:
|
|||||||
elif text_lower.startswith("удал "):
|
elif text_lower.startswith("удал "):
|
||||||
self._handle_admin_delete(user_id, text_clean)
|
self._handle_admin_delete(user_id, text_clean)
|
||||||
return
|
return
|
||||||
elif text_lower in ["стата", "статистика", "/stats"]:
|
elif text_lower in ["в главное меню ↩️"]:
|
||||||
self._handle_admin_stats(user_id)
|
self.send_message(
|
||||||
return
|
user_id, "🏠 Главное меню.",
|
||||||
elif text_lower.startswith("рассылка"):
|
keyboard=get_main_keyboard(is_admin=True)
|
||||||
self._handle_admin_broadcast(user_id, text_clean)
|
)
|
||||||
return
|
return
|
||||||
|
|
||||||
# Глобальная отписка от рассылки (доступна в любом состоянии)
|
# Глобальная отписка от рассылки (доступна в любом состоянии)
|
||||||
@@ -542,11 +588,11 @@ class VKBotApplication:
|
|||||||
return
|
return
|
||||||
|
|
||||||
# 3. Возврат в главное меню
|
# 3. Возврат в главное меню
|
||||||
if text_lower in ["назад в меню ↩️", "меню", "назад"]:
|
if text_lower in ["назад в меню ↩️", "меню", "назад", "в главное меню ↩️"]:
|
||||||
self.send_message(
|
self.send_message(
|
||||||
user_id,
|
user_id,
|
||||||
"🏠 Вы вернулись в главное меню. Выберите интересующее действие:",
|
"🏠 Вы вернулись в главное меню. Выберите интересующее действие:",
|
||||||
keyboard=get_main_keyboard()
|
keyboard=get_main_keyboard(is_admin=self._is_admin(user_id))
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
|
|
||||||
@@ -576,7 +622,7 @@ class VKBotApplication:
|
|||||||
"Я помогу быстро оформить заявку на тренировки, рассказать об услугах или связать вас с командой. "
|
"Я помогу быстро оформить заявку на тренировки, рассказать об услугах или связать вас с командой. "
|
||||||
"Также у нас открыт набор игроков и сотрудников — загляните в раздел «Карьера в ИКП 💼».\n\n"
|
"Также у нас открыт набор игроков и сотрудников — загляните в раздел «Карьера в ИКП 💼».\n\n"
|
||||||
"Выберите действие на кнопках ниже 👇",
|
"Выберите действие на кнопках ниже 👇",
|
||||||
keyboard=get_main_keyboard(),
|
keyboard=get_main_keyboard(is_admin=self._is_admin(user_id)),
|
||||||
attachment=self.get_logo_attachment(user_id)
|
attachment=self.get_logo_attachment(user_id)
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
@@ -586,7 +632,7 @@ class VKBotApplication:
|
|||||||
user_id,
|
user_id,
|
||||||
"🤔 Я пока только учусь и не смог полностью распознать ваш запрос.\n\n"
|
"🤔 Я пока только учусь и не смог полностью распознать ваш запрос.\n\n"
|
||||||
"Пожалуйста, воспользуйтесь кнопками меню ниже или напишите 'оператор', чтобы я пригласил специалиста.",
|
"Пожалуйста, воспользуйтесь кнопками меню ниже или напишите 'оператор', чтобы я пригласил специалиста.",
|
||||||
keyboard=get_main_keyboard()
|
keyboard=get_main_keyboard(is_admin=self._is_admin(user_id))
|
||||||
)
|
)
|
||||||
|
|
||||||
def _send_returning_prompt(self, user_id: int, user_data: Dict[str, Any]):
|
def _send_returning_prompt(self, user_id: int, user_data: Dict[str, Any]):
|
||||||
|
|||||||
Reference in New Issue
Block a user