- Added functionality to pin duty messages in group chats, including scheduling updates and handling bot add/remove events. - Introduced a new `GroupDutyPin` model to store pinned message details and a `phone` field in the `User` model for user contact information. - Implemented commands for users to set or clear their phone numbers in private chats. - Enhanced the repository with functions to manage group duty pins and user phone data. - Updated handlers to register new commands and manage duty pin updates effectively.
60 lines
2.3 KiB
Python
60 lines
2.3 KiB
Python
"""Load configuration from environment. Fail fast if BOT_TOKEN is missing."""
|
|
|
|
import os
|
|
|
|
from dotenv import load_dotenv
|
|
|
|
load_dotenv()
|
|
|
|
BOT_TOKEN = os.getenv("BOT_TOKEN")
|
|
if not BOT_TOKEN:
|
|
raise SystemExit(
|
|
"BOT_TOKEN is not set. Copy .env.example to .env and set your token from @BotFather."
|
|
)
|
|
|
|
DATABASE_URL = os.getenv("DATABASE_URL", "sqlite:///data/duty_teller.db")
|
|
MINI_APP_BASE_URL = os.getenv("MINI_APP_BASE_URL", "").rstrip("/")
|
|
HTTP_PORT = int(os.getenv("HTTP_PORT", "8080"))
|
|
|
|
# Miniapp access: comma-separated Telegram usernames (no @). Empty = no one allowed.
|
|
_raw_allowed = os.getenv("ALLOWED_USERNAMES", "").strip()
|
|
ALLOWED_USERNAMES = {
|
|
s.strip().lstrip("@").lower() for s in _raw_allowed.split(",") if s.strip()
|
|
}
|
|
|
|
_raw_admin = os.getenv("ADMIN_USERNAMES", "").strip()
|
|
ADMIN_USERNAMES = {
|
|
s.strip().lstrip("@").lower() for s in _raw_admin.split(",") if s.strip()
|
|
}
|
|
|
|
# Dev only: set to 1 to allow /api/duties without Telegram initData (insecure, no user check).
|
|
MINI_APP_SKIP_AUTH = os.getenv("MINI_APP_SKIP_AUTH", "").strip() in ("1", "true", "yes")
|
|
|
|
# Optional replay protection: reject initData older than this many seconds. 0 = disabled (default).
|
|
INIT_DATA_MAX_AGE_SECONDS = int(os.getenv("INIT_DATA_MAX_AGE_SECONDS", "0"))
|
|
|
|
# CORS: comma-separated origins, or empty/"*" for allow all. For production, set to MINI_APP_BASE_URL or specific origins.
|
|
_raw_cors = os.getenv("CORS_ORIGINS", "").strip()
|
|
CORS_ORIGINS = (
|
|
[_o.strip() for _o in _raw_cors.split(",") if _o.strip()]
|
|
if _raw_cors and _raw_cors != "*"
|
|
else ["*"]
|
|
)
|
|
|
|
# Optional: URL of a public ICS calendar (e.g. holidays). Empty = no external calendar; /api/calendar-events returns [].
|
|
EXTERNAL_CALENDAR_ICS_URL = os.getenv("EXTERNAL_CALENDAR_ICS_URL", "").strip()
|
|
|
|
# Timezone for displaying duty times in the pinned group message (e.g. Europe/Moscow).
|
|
DUTY_DISPLAY_TZ = os.getenv("DUTY_DISPLAY_TZ", "Europe/Moscow").strip() or "Europe/Moscow"
|
|
|
|
|
|
def is_admin(username: str) -> bool:
|
|
"""True if the given Telegram username (no @, any case) is in ADMIN_USERNAMES."""
|
|
return (username or "").strip().lower() in ADMIN_USERNAMES
|
|
|
|
|
|
def can_access_miniapp(username: str) -> bool:
|
|
"""True if username is in ALLOWED_USERNAMES or ADMIN_USERNAMES."""
|
|
u = (username or "").strip().lower()
|
|
return u in ALLOWED_USERNAMES or u in ADMIN_USERNAMES
|