import os def _load_dotenv(): """Load KEY=value lines from a .env beside this file into the environment, with NO variable expansion. Werkzeug password hashes contain '$', which shell-style interpolation corrupts. Vars already set (e.g. by systemd) win.""" path = os.path.join(os.path.dirname(os.path.abspath(__file__)), ".env") if not os.path.exists(path): return with open(path, encoding="utf-8") as fh: for raw in fh: line = raw.strip() if not line or line.startswith("#") or "=" not in line: continue key, val = line.split("=", 1) key, val = key.strip(), val.strip() if len(val) >= 2 and val[0] == val[-1] and val[0] in ("'", '"'): val = val[1:-1] os.environ.setdefault(key, val) _load_dotenv() class Config: # Build the SQLAlchemy URI from discrete env vars, or accept a full DATABASE_URL. DB_USER = os.environ.get("DB_USER", "jqc_features") DB_PASSWORD = os.environ.get("DB_PASSWORD", "") DB_HOST = os.environ.get("DB_HOST", "127.0.0.1") DB_PORT = os.environ.get("DB_PORT", "3306") DB_NAME = os.environ.get("DB_NAME", "jqc_features") SQLALCHEMY_DATABASE_URI = os.environ.get( "DATABASE_URL", f"mysql+pymysql://{DB_USER}:{DB_PASSWORD}@{DB_HOST}:{DB_PORT}/{DB_NAME}?charset=utf8mb4", ) SQLALCHEMY_TRACK_MODIFICATIONS = False SQLALCHEMY_ENGINE_OPTIONS = {"pool_pre_ping": True, "pool_recycle": 280} # Public contact button target shown in the closing CTA. DEMO_CONTACT_URL = os.environ.get("DEMO_CONTACT_URL", "mailto:info@ltservicesinc.com") # --- Admin / session --- SECRET_KEY = os.environ.get("SECRET_KEY", "dev-only-insecure-change-me") ADMIN_USERNAME = os.environ.get("ADMIN_USERNAME", "admin") ADMIN_PASSWORD_HASH = os.environ.get("ADMIN_PASSWORD_HASH", "") SESSION_COOKIE_HTTPONLY = True SESSION_COOKIE_SAMESITE = "Lax" SESSION_COOKIE_SECURE = os.environ.get("SESSION_COOKIE_SECURE", "1") == "1"