import os # Load environment variables from .env in the project root def _load_env(): # Find the project root (the directory containing config.py) root_dir = os.path.dirname(os.path.abspath(__file__)) dotenv_path = os.path.join(root_dir, ".env") if os.path.exists(dotenv_path): try: with open(dotenv_path, "r", encoding="utf-8") as f: for line in f: line = line.strip() if not line or line.startswith("#"): continue if "=" in line: key, val = line.split("=", 1) val = val.strip().strip('"').strip("'") # Не перетираем переменные, уже заданные в реальном окружении # (на проде токены приходят из env, .env — лишь фолбэк). os.environ.setdefault(key.strip(), val) except Exception as e: print(f"Warning: Failed to load .env file: {e}") _load_env() # VK API Configuration # In production, these should be loaded from environment variables or a secure .env file. VK_TOKEN = os.getenv("VK_TOKEN", "your_vk_community_token_here") GROUP_ID = int(os.getenv("VK_GROUP_ID", "0")) # Community ID (must be integer) # Operator / Admin configuration # ID of the user or chat where notifications about new leads and operator requests will be sent OPERATOR_PEER_ID = int(os.getenv("OPERATOR_PEER_ID", "12345678")) # Change to actual VK user ID of operator # Parse ADMIN_IDS as a list of integers from comma-separated env values admin_ids_raw = os.getenv("ADMIN_IDS") if admin_ids_raw: try: ADMIN_IDS = [int(x.strip()) for x in admin_ids_raw.split(",") if x.strip().isdigit()] except Exception: ADMIN_IDS = [OPERATOR_PEER_ID] else: ADMIN_IDS = [OPERATOR_PEER_ID] # ============================================================ # СУПЕР-АДМИН. Меняется ТОЛЬКО ЗДЕСЬ, в коде (не через .env, не через бота). # Супер-админ может добавлять/удалять обычных администраторов прямо из бота. # Чтобы сменить/добавить супер-админа — впишите сюда VK ID (числом): SUPER_ADMIN_IDS = [350793273] # ============================================================ # Ссылки на юридические документы (инлайн-кнопки в боте) OFFER_URL = os.getenv("OFFER_URL", "https://infocyber.pro/form/Dogovor_oferty_kibersport_versia_izmenennaya.pdf") POLICY_URL = os.getenv("POLICY_URL", "https://infocyber.pro/form/Политика%20ПД.pdf") # Несколько операторов: уведомления о заявках/откликах/вызовах уходят ВСЕМ из списка. # По умолчанию = один OPERATOR_PEER_ID. Задать через .env: OPERATOR_PEER_IDS=111,222,333 _op_ids_raw = os.getenv("OPERATOR_PEER_IDS") if _op_ids_raw: OPERATOR_PEER_IDS = [int(x.strip()) for x in _op_ids_raw.split(",") if x.strip().lstrip("-").isdigit()] if not OPERATOR_PEER_IDS: OPERATOR_PEER_IDS = [OPERATOR_PEER_ID] else: OPERATOR_PEER_IDS = [OPERATOR_PEER_ID] # Часы работы (для статуса оператора). Вне этого интервала — «ответим утром». WORK_HOUR_START = int(os.getenv("WORK_HOUR_START", "9")) WORK_HOUR_END = int(os.getenv("WORK_HOUR_END", "21")) # Разрешённый источник (Origin) для CORS веб-формы. '*' допустим только для локальной отладки. ALLOWED_ORIGIN = os.getenv("ALLOWED_ORIGIN", "https://infocyber.pro") # Промокоды на скидку. Пока ВЫКЛЮЧЕНЫ — включить можно, задав PROMO_ENABLED=true в .env. # Когда выключено: бот и форма не показывают промокод, в уведомлениях/письмах его нет. PROMO_ENABLED = os.getenv("PROMO_ENABLED", "false").strip().lower() in ("1", "true", "yes") # Email (SMTP) configuration для уведомлений о заявках SMTP_HOST = os.getenv("SMTP_HOST", "") SMTP_PORT = int(os.getenv("SMTP_PORT", "465")) SMTP_USER = os.getenv("SMTP_USER", "") SMTP_PASSWORD = os.getenv("SMTP_PASSWORD", "") MAIL_FROM = os.getenv("MAIL_FROM", "") or SMTP_USER # Куда отправлять уведомления о новых заявках (можно несколько через запятую) MAIL_TO = os.getenv("MAIL_TO", "group-zakaz@infocyber.pro") # Куда отправлять отклики на вакансии / набор в состав. # TODO: пока совпадает с MAIL_TO; возможно вынести на отдельный HR-адрес (напр. hr@infocyber.pro) — задать HR_MAIL_TO в .env. 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 тренировки." ) # Доступные услуги (направления) — используются для сидирования БД (services) SERVICES = { "1": { "name": "Counter-Strike 2 🔫", "price": "от 870 ₽ / занятие", "description": "Тренировки по CS2: aim, раскидки гранат, командная тактика. Разовое занятие 870 ₽, абонементы от 2 790 ₽." }, "2": { "name": "Dota 2 🎮", "price": "от 870 ₽ / занятие", "description": "Тренировки по Dota 2: разбор реплеев, позиционка, фарм и тимплей. Разовое занятие 870 ₽, абонементы от 2 790 ₽." }, "3": { "name": "World of Tanks 🛡️", "price": "от 870 ₽ / занятие", "description": "Тренировки по World of Tanks: позиционирование, сведение, тактика боёв. Разовое занятие 870 ₽, абонементы от 2 790 ₽." } }