import time from typing import Optional from sqlalchemy import select from sqlalchemy.ext.asyncio import AsyncSession from app.models.models import BotSetting, BotFeature, BotResponseTemplate, BotCategory class SettingsCache: _cache: dict = {} _features: dict = {} _templates: dict = {} _categories: list = [] _last_update: float = 0 TTL = 300 # 5 minutes @classmethod async def refresh(cls, db: AsyncSession): now = time.time() if now - cls._last_update < cls.TTL and cls._cache: return result = await db.execute(select(BotSetting)) cls._cache = {row.key: row.value for row in result.scalars().all()} result = await db.execute(select(BotFeature).where(BotFeature.enabled == True)) cls._features = {row.feature_key: row for row in result.scalars().all()} result = await db.execute(select(BotFeature)) all_features = {row.feature_key: row for row in result.scalars().all()} result = await db.execute(select(BotResponseTemplate)) cls._templates = {row.template_key: row.template_text for row in result.scalars().all()} result = await db.execute( select(BotCategory).where(BotCategory.active == True).order_by(BotCategory.sort_order) ) cls._categories = result.scalars().all() cls._last_update = now @classmethod def get(cls, key: str, default: str = "") -> str: return cls._cache.get(key, default) @classmethod def get_int(cls, key: str, default: int = 0) -> int: val = cls._cache.get(key, str(default)) try: return int(val) except (ValueError, TypeError): return default @classmethod def get_list(cls, key: str, default: list = None) -> list: val = cls._cache.get(key, "") if not val: return default or [] return [x.strip() for x in val.split(",")] @classmethod def get_all(cls) -> dict: return dict(cls._cache) @classmethod def is_feature_enabled(cls, feature_key: str) -> bool: return feature_key in cls._features @classmethod def get_enabled_features(cls) -> dict: return dict(cls._features) @classmethod def get_template(cls, key: str, default: str = "") -> str: return cls._templates.get(key, default) @classmethod def get_all_templates(cls) -> dict: return dict(cls._templates) @classmethod def get_categories(cls) -> list: return list(cls._categories) @classmethod def get_bot_token(cls) -> str: return cls._cache.get("bot_token", "") @classmethod def get_assistant_name(cls) -> str: return cls._cache.get("assistant_name", "София") @classmethod def is_work_hours(cls) -> bool: import datetime import pytz tz_name = cls._cache.get("timezone", "Europe/Moscow") try: tz = pytz.timezone(tz_name) except Exception: tz = pytz.timezone("Europe/Moscow") now = datetime.datetime.now(tz) work_days = cls.get_list("work_days", ["1", "2", "3", "4", "5"]) weekday = str(now.isoweekday()) if weekday not in work_days: return False start = cls.get_int("work_hours_start", 9) end = cls.get_int("work_hours_end", 18) return start <= now.hour < end @classmethod def get_work_hours_str(cls) -> str: start = cls.get_int("work_hours_start", 9) end = cls.get_int("work_hours_end", 18) return f"{start}:00-{end}:00" @classmethod def get_phones(cls) -> list: phones = [] p1 = cls._cache.get("phone_1", "") p2 = cls._cache.get("phone_2", "") if p1: phones.append(p1) if p2: phones.append(p2) return phones @classmethod def get_email(cls) -> str: return cls._cache.get("support_email", "")