Чистка «лишнего»: остатки ИКП→БАЗА, мёртвый код, новый логотип
- Пользовательские сообщения и подписи с «ИКП» переименованы в «Кибершкола БАЗА» (права админа, стартовый пинг, отправитель писем, докстроки). - Удалён мёртвый код: метод _notify_allowed + связанные _last_notify/NOTIFY_COOLDOWN_SEC (нигде не вызывались), осиротевшие комментарии-заголовки от удалённой карьеры, лишние пустые строки. - Удалена скрытая фича «Наши соцсети» (нет в ТЗ, вела на старые ИКП-ссылки) + её клавиатура. - Обновлён логотип приветствия (help_img/Logo.jpg). Не тронуто намеренно: веб-форма (form/server.py) — отдельный компонент; слой БД. pytest 31 passed. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -38,8 +38,6 @@ db = DatabaseManager()
|
||||
# Анти-флуд: максимум сообщений от одного пользователя за окно времени
|
||||
FLOOD_MAX_MSGS = 12
|
||||
FLOOD_WINDOW_SEC = 10
|
||||
# Кулдаун между уведомлениями оператора о заявке/отклике от одного пользователя (сек)
|
||||
NOTIFY_COOLDOWN_SEC = 120
|
||||
# Временный бан при повторном флуде: после BAN_STRIKES срабатываний за BAN_WINDOW_SEC — бан на BAN_SEC
|
||||
BAN_STRIKES = 3
|
||||
BAN_WINDOW_SEC = 60
|
||||
@@ -101,7 +99,6 @@ class VKBotApplication:
|
||||
self._flood_warned: Dict[int, float] = {} # user_id -> когда предупредили о флуде
|
||||
self._flood_strikes: Dict[int, list] = defaultdict(list) # user_id -> метки срабатываний флуда
|
||||
self._banned_until: Dict[int, float] = {} # user_id -> до какого времени забанен
|
||||
self._last_notify: Dict[int, float] = {} # user_id -> время последнего уведомления оператора
|
||||
self._last_antiflood_cleanup: float = 0.0 # когда последний раз чистили словари анти-флуда
|
||||
# Кэш рантайм-админов (из БД), чтобы не бить в SQLite на каждое сообщение
|
||||
self._admins_cache: Optional[set] = None
|
||||
@@ -301,7 +298,7 @@ class VKBotApplication:
|
||||
self._admins_cache = None # инвалидируем кэш админов
|
||||
self.send_message(user_id, f"✅ Пользователь vk.com/id{new_id} теперь администратор.")
|
||||
try:
|
||||
self.send_message(new_id, "🛡 Вам выданы права администратора бота ИКП. "
|
||||
self.send_message(new_id, "🛡 Вам выданы права администратора бота Кибершколы БАЗА. "
|
||||
"Откройте меню — появится кнопка «Админка ⚙️».")
|
||||
except Exception:
|
||||
pass
|
||||
@@ -345,16 +342,6 @@ class VKBotApplication:
|
||||
del self._banned_until[uid]
|
||||
for uid in [u for u, t in self._flood_warned.items() if now - t > FLOOD_WINDOW_SEC]:
|
||||
del self._flood_warned[uid]
|
||||
for uid in [u for u, t in self._last_notify.items() if now - t > NOTIFY_COOLDOWN_SEC]:
|
||||
del self._last_notify[uid]
|
||||
|
||||
def _notify_allowed(self, user_id: int) -> bool:
|
||||
"""Антиспам: не чаще раза в NOTIFY_COOLDOWN_SEC уведомляем оператора об одном пользователе."""
|
||||
now = time.time()
|
||||
if now - self._last_notify.get(user_id, 0) < NOTIFY_COOLDOWN_SEC:
|
||||
return False
|
||||
self._last_notify[user_id] = now
|
||||
return True
|
||||
|
||||
def handle_message(self, user_id: int, text: str, attachments: Optional[list] = None):
|
||||
"""Маршрутизатор входящих сообщений на основе состояний пользователя."""
|
||||
@@ -607,15 +594,6 @@ class VKBotApplication:
|
||||
self._baza_ask_question(user_id)
|
||||
return
|
||||
|
||||
# 5. Площадки — кнопки-ссылки
|
||||
if text_lower in ["наши соцсети 🔗", "наши соцсети", "соцсети", "площадки", "ссылки"]:
|
||||
self.send_message(
|
||||
user_id,
|
||||
"🔗 Мы на площадках Кибершколы БАЗА — заходите и подписывайтесь 👇",
|
||||
keyboard=get_socials_keyboard()
|
||||
)
|
||||
return
|
||||
|
||||
# 6. Возврат в главное меню
|
||||
if text_lower in ["назад в меню ↩️", "меню", "назад", "в главное меню ↩️", "главное меню"]:
|
||||
self.send_message(
|
||||
@@ -1189,26 +1167,6 @@ class VKBotApplication:
|
||||
f"до {getattr(config, 'WORK_HOUR_END', 21)}:00) — ответим утром.")
|
||||
self.send_message(user_id, client_text, keyboard=get_operator_keyboard())
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
def _upload_photo(self, peer_id: int, image_path: str) -> Optional[Dict[str, str]]:
|
||||
"""Загружает фото в VK для прикрепления к сообщению. Возвращает {'attachment','raw'} или None."""
|
||||
@@ -1236,9 +1194,8 @@ class VKBotApplication:
|
||||
return None
|
||||
|
||||
|
||||
|
||||
def get_logo_attachment(self, peer_id: int) -> Optional[str]:
|
||||
"""Attachment-строка с логотипом ИКП для прикрепления к приветствию."""
|
||||
"""Attachment-строка с логотипом Кибершколы БАЗА для прикрепления к приветствию."""
|
||||
import os
|
||||
logo_path = os.path.join(os.path.dirname(__file__), "help_img", "Logo.jpg")
|
||||
info = self._upload_photo(peer_id, logo_path)
|
||||
@@ -1264,15 +1221,6 @@ class VKBotApplication:
|
||||
logger.error(f"Не удалось предзагрузить медиа: {e}")
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
def _handle_operator_chat(self, user_id: int, text: str, text_lower: str):
|
||||
"""Поведение бота в режиме активного диалога с живым человеком."""
|
||||
# Пользователь хочет выйти из диалога с оператором
|
||||
@@ -1291,34 +1239,6 @@ class VKBotApplication:
|
||||
logger.info(f"[OPERATOR MODE] Message from {user_id} bypasses bot: {text}")
|
||||
self._forward_to_operator(user_id, text)
|
||||
|
||||
# ------------------------------------------
|
||||
# СЦЕНАРИИ ПЕРЕДАЧИ ОПЕРАТОРУ И СВЯЗИ
|
||||
# ------------------------------------------
|
||||
|
||||
# ------------------------------------------
|
||||
# РАЗДЕЛ "КАРЬЕРА В ИКП" (НАЙМ ИГРОКОВ И СОТРУДНИКОВ)
|
||||
# ------------------------------------------
|
||||
|
||||
|
||||
|
||||
|
||||
# ----- Ветка игрока -----
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# ----- Ветка сотрудника -----
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
def _forward_to_operator(self, user_id: int, text: str):
|
||||
"""Пересылка сообщений от клиента всем операторам."""
|
||||
self._notify_operators(f"💬 Сообщение от vk.com/id{user_id}:\n{text}")
|
||||
@@ -1455,9 +1375,6 @@ class VKBotApplication:
|
||||
self._send_admin_panel(user_id)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
def _handle_admin_stats(self, user_id: int):
|
||||
"""Формирует и отправляет админу сводную статистику по заявкам и диалогам."""
|
||||
ls = db.get_lead_stats()
|
||||
@@ -1554,7 +1471,6 @@ class VKBotApplication:
|
||||
self._send_faq_admin(user_id)
|
||||
|
||||
|
||||
|
||||
def _handle_admin_broadcast(self, user_id: int, text: str):
|
||||
"""Рассылка по подписчикам: 'рассылка <текст>' → предпросмотр → 'рассылка подтвердить' → отправка."""
|
||||
# Отрезаем ключевое слово 'рассылка'
|
||||
@@ -1670,7 +1586,7 @@ class VKBotApplication:
|
||||
from datetime import datetime
|
||||
ts = datetime.now().strftime("%d.%m.%Y %H:%M")
|
||||
for admin_id in getattr(config, "ADMIN_IDS", []):
|
||||
self.send_message(admin_id, f"✅ Бот ИКП запущен и на связи ({ts}).")
|
||||
self.send_message(admin_id, f"✅ Бот Кибершколы БАЗА запущен и на связи ({ts}).")
|
||||
except Exception as e:
|
||||
logger.error(f"Не удалось отправить старт-пинг: {e}")
|
||||
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 99 KiB After Width: | Height: | Size: 1.2 MiB |
@@ -192,22 +192,6 @@ def get_cancel_admin_keyboard() -> str:
|
||||
return keyboard.get_keyboard()
|
||||
|
||||
|
||||
def get_socials_keyboard() -> str:
|
||||
"""Клавиатура с кнопками-ссылками на площадки ИКП (открываются в один тап)."""
|
||||
keyboard = VkKeyboard(one_time=False)
|
||||
keyboard.add_openlink_button("VK Live 📺", "https://live.vkvideo.ru/ikp")
|
||||
keyboard.add_line()
|
||||
keyboard.add_openlink_button("Telegram ✈️", "https://t.me/ikp_team")
|
||||
keyboard.add_openlink_button("Lolka 🎮", "https://vk.com/away.php?to=https%3A%2F%2Flolka.gg%2FlNfM3F9DD&utf=1")
|
||||
keyboard.add_line()
|
||||
keyboard.add_openlink_button("ВКонтакте 🌐", "https://vk.com/ikpro")
|
||||
keyboard.add_line()
|
||||
keyboard.add_openlink_button("Наш сайт 🔗", "https://infocyber.pro/")
|
||||
keyboard.add_line()
|
||||
keyboard.add_button("Назад в меню ↩️", color=VkKeyboardColor.SECONDARY)
|
||||
return keyboard.get_keyboard()
|
||||
|
||||
|
||||
def get_operator_keyboard() -> str:
|
||||
"""Клавиатура при активном диалоге с оператором."""
|
||||
keyboard = VkKeyboard(one_time=False)
|
||||
|
||||
@@ -41,7 +41,7 @@ def send_email(subject: str, body: str, mail_to: Optional[str] = None) -> bool:
|
||||
|
||||
msg = MIMEText(body, "plain", "utf-8")
|
||||
msg["Subject"] = Header(subject, "utf-8")
|
||||
msg["From"] = formataddr((str(Header("Бот ИКП", "utf-8")), mail_from))
|
||||
msg["From"] = formataddr((str(Header("Бот БАЗА", "utf-8")), mail_from))
|
||||
msg["To"] = mail_to
|
||||
|
||||
try:
|
||||
|
||||
Reference in New Issue
Block a user