diff --git a/config.py b/config.py index 2700c64..c894460 100644 --- a/config.py +++ b/config.py @@ -88,6 +88,63 @@ HR_MAIL_TO = os.getenv("HR_MAIL_TO", "") or MAIL_TO # True — порт 465 (SSL), False — STARTTLS (обычно порт 587) SMTP_USE_SSL = os.getenv("SMTP_USE_SSL", "true").strip().lower() in ("1", "true", "yes") +# ============================================================ +# КИБЕРШКОЛА БАЗА — бренд, цены, ссылки, триггеры (по ТЗ) +# Всё редактируемое собрано здесь, чтобы менять без правки логики. +# ============================================================ +BRAND = "Кибершкола БАЗА" + +# --- Ссылки на оплату/запись (ПЛЕЙСХОЛДЕРЫ — заменить на реальные) --- +# UTM добавляются автоматически там, где ссылка ведёт наружу. +UTM_MAIN = "utm_source=vk&utm_medium=bot&utm_campaign=main_bot" +UTM_SUMMER = "utm_source=vk&utm_medium=bot&utm_campaign=summer_intensive" +LINKS = { + "trial": os.getenv("LINK_TRIAL", "https://infocyber.pro/"), # запись на пробное + "tariffs": os.getenv("LINK_TARIFFS", "https://infocyber.pro/"), # страница с тарифами + "group_4": os.getenv("LINK_GROUP_4", "https://infocyber.pro/"), # групповой абонемент 4 + "group_8": os.getenv("LINK_GROUP_8", "https://infocyber.pro/"), # групповой абонемент 8 + "individual_1": os.getenv("LINK_IND_1", "https://infocyber.pro/"), # индивидуальная 1 + "individual_4": os.getenv("LINK_IND_4", "https://infocyber.pro/"), # индивидуальные 4 + "individual_8": os.getenv("LINK_IND_8", "https://infocyber.pro/"), # индивидуальные 8 + "summer": os.getenv("LINK_SUMMER", "https://infocyber.pro/"), # оплата летнего интенсива +} + +# --- Триггеры запуска (регистронезависимо) --- +MAIN_TRIGGERS = ["начать", "тренировки", "занятия", "цена", "стоимость", "записаться", + "привет", "здравствуйте", "старт", "меню"] +SUMMER_TRIGGERS = ["лето", "интенсив", "летний интенсив", "интенсив cs2", "хочу на интенсив"] + +# --- Тексты (по ТЗ, редактируемые) --- +GREETING_BAZA = ( + "Привет! Это Кибершкола БАЗА 🎮\n\n" + "Мы проводим онлайн-тренировки по CS2, Dota 2 и World of Tanks для подростков 12+.\n" + "Помогу подобрать подходящий формат, посмотреть цены или записаться на тренировку." +) + +PRICES_TEXT = ( + "Стоимость тренировок в Кибершколе БАЗА:\n\n" + "🧑‍🤝‍🧑 Групповые тренировки:\n" + "• 4 занятия — 2 790 ₽\n" + "• 8 занятий — 4 990 ₽\n\n" + "👤 Индивидуальные тренировки:\n" + "• 1 занятие — 870 ₽\n" + "• 4 занятия — 3 290 ₽\n" + "• 8 занятий — 5 990 ₽\n\n" + "Все занятия проходят онлайн с тренером." +) + +INTENSIVE_PRICE = "1 990 ₽" +INTENSIVE_INFO = ( + "Привет! Вы написали кодовое слово «лето» — рассказываю про летний интенсив по CS2 🔥\n\n" + "Это 4 онлайн-тренировки по 90 минут с тренером.\n" + "На интенсиве участники будут:\n" + "— разбирать роли и командную игру;\n" + "— тренировать аим, дуэли и контрстрейфы;\n" + "— разбирать игровые моменты и демозаписи;\n" + "— изучать гранаты, мувмент и полезные игровые приёмы.\n\n" + f"Стоимость участия — {INTENSIVE_PRICE} за все 4 тренировки." +) + # Standard replies and patterns FAQ_ANSWERS = { "цены": ( diff --git a/database.py b/database.py index de00de6..7269407 100644 --- a/database.py +++ b/database.py @@ -30,7 +30,7 @@ class DatabaseManager: """) # Migration checks for existing databases - for col in ["consent_1", "consent_2", "consent_3", "call_time", "vac_data"]: + for col in ["consent_1", "consent_2", "consent_3", "call_time", "vac_data", "profile"]: try: cursor.execute(f"ALTER TABLE user_states ADD COLUMN {col} TEXT") except sqlite3.OperationalError: @@ -475,6 +475,53 @@ class DatabaseManager: ) conn.commit() + # --- Профиль воронки БАЗА (JSON в user_states.profile) --- + def get_profile(self, user_id: int) -> Dict[str, Any]: + """Профиль пользователя из воронки (роль/возраст/игра/уровень/формат/метки/…).""" + with self._get_connection() as conn: + cursor = conn.cursor() + cursor.execute("SELECT profile FROM user_states WHERE user_id = ?", (user_id,)) + row = cursor.fetchone() + if row and row[0]: + try: + return json.loads(row[0]) + except (ValueError, TypeError): + return {} + return {} + + def set_profile_field(self, user_id: int, key: str, value: Any): + """Обновить одно поле профиля (не спрашиваем повторно то, что уже есть).""" + data = self.get_profile(user_id) + data[key] = value + with self._get_connection() as conn: + cursor = conn.cursor() + cursor.execute( + "INSERT INTO user_states (user_id, profile) VALUES (?, ?) " + "ON CONFLICT(user_id) DO UPDATE SET profile = excluded.profile, last_updated = CURRENT_TIMESTAMP", + (user_id, json.dumps(data, ensure_ascii=False)) + ) + conn.commit() + + def add_metka(self, user_id: int, metka: str): + """Добавить метку пользователю (хранится списком в профиле, без повторов).""" + data = self.get_profile(user_id) + metki = data.get("metki", []) + if metka not in metki: + metki.append(metka) + data["metki"] = metki + self.set_profile_field(user_id, "metki", metki) + + def clear_profile(self, user_id: int): + """Полностью очистить профиль воронки.""" + with self._get_connection() as conn: + cursor = conn.cursor() + cursor.execute( + "INSERT INTO user_states (user_id, profile) VALUES (?, NULL) " + "ON CONFLICT(user_id) DO UPDATE SET profile = NULL, last_updated = CURRENT_TIMESTAMP", + (user_id,) + ) + conn.commit() + # --- Вакансии (направления игроков / должности сотрудников) --- def get_vacancy_options(self, track: str) -> list: """Активные опции для трека ('player'|'worker') как список (id, label)."""