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("'") os.environ[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") # Standard replies and patterns FAQ_ANSWERS = { "цены": ( "💰 Тарифы ИКП на тренировки (направления: CS2, Dota 2, World of Tanks):\n\n" "• Разовая тренировка — 870 ₽\n" "• Абонемент на 4 занятия (групповой) — 2 790 ₽\n" "• Абонемент на 8 занятий (групповой) — 4 990 ₽\n" "• Абонемент на 4 занятия (индивидуальный) — 3 290 ₽\n" "• Абонемент на 8 занятий (индивидуальный) — 5 990 ₽\n\n" "Оставьте заявку через меню — менеджер подберёт оптимальный формат и направление!" ), "контакты": ( "📞 Связаться с ИКП:\n" "• Email (поддержка): support@infocyber.pro\n" "• Заявки: group-zakaz@infocyber.pro\n" "• Telegram: @ikp_team\n" "• Сайт: https://infocyber.pro/" ), "услуги": ( "⚙️ ИКП — тренировки по киберспортивным дисциплинам:\n\n" "1. Counter-Strike 2 — aim, раскидки гранат, командная тактика\n" "2. Dota 2 — разбор реплеев, позиционка, фарм и тимплей\n" "3. World of Tanks — позиционирование, сведение, тактика боёв\n\n" "Форматы: разовые занятия, групповые и индивидуальные абонементы (4 и 8 занятий)." ), "о компании": ( "🏢 ИКП — Игра. Киберспорт. Профессионалы.\n\n" "Мощная экосистема для взрывного роста игроков: лучшие тренеры и глубокая data-аналитика. " "Организация основана 1 сентября 2025 года.\n\n" "Мы на площадках:\n" "• ВКонтакте: https://vk.com/ikpro\n" "• VK Live (трансляции): https://live.vkvideo.ru/ikp\n" "• Telegram: https://t.me/ikp_team\n" "• Discord: https://discord.gg/z92mAw7KEe" ) } # Доступные услуги (направления) для выбора в форме заявки 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 ₽." } }