- Introduced a new configuration file `.cursorrules` to define coding standards, error handling, testing requirements, and project-specific guidelines. - Refactored `config.py` to implement a `Settings` dataclass for better management of environment variables, improving testability and maintainability. - Updated the import duty schedule handler to utilize session management with `session_scope`, ensuring proper database session handling. - Enhanced the import service to streamline the duty schedule import process, improving code organization and readability. - Added new service layer functions to encapsulate business logic related to group duty pinning and duty schedule imports. - Updated README documentation to reflect the new configuration structure and improved import functionality.
97 lines
3.8 KiB
Python
97 lines
3.8 KiB
Python
"""Command handlers: /start, /help; /start registers user."""
|
||
|
||
import asyncio
|
||
|
||
import config
|
||
from telegram import Update
|
||
from telegram.ext import CommandHandler, ContextTypes
|
||
|
||
from db.session import session_scope
|
||
from db.repository import get_or_create_user, set_user_phone
|
||
from utils.user import build_full_name
|
||
|
||
|
||
async def start(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
|
||
if not update.message:
|
||
return
|
||
user = update.effective_user
|
||
if not user:
|
||
return
|
||
full_name = build_full_name(user.first_name, user.last_name)
|
||
telegram_user_id = user.id
|
||
username = user.username
|
||
first_name = user.first_name
|
||
last_name = user.last_name
|
||
|
||
def do_get_or_create() -> None:
|
||
with session_scope(config.DATABASE_URL) as session:
|
||
get_or_create_user(
|
||
session,
|
||
telegram_user_id=telegram_user_id,
|
||
full_name=full_name,
|
||
username=username,
|
||
first_name=first_name,
|
||
last_name=last_name,
|
||
)
|
||
|
||
await asyncio.get_running_loop().run_in_executor(None, do_get_or_create)
|
||
|
||
text = "Привет! Я бот календаря дежурств. Используй /help для списка команд."
|
||
await update.message.reply_text(text)
|
||
|
||
|
||
async def set_phone(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
|
||
"""Set or clear phone for the current user (private chat only)."""
|
||
if not update.message or not update.effective_user:
|
||
return
|
||
if update.effective_chat and update.effective_chat.type != "private":
|
||
await update.message.reply_text("Команда /set_phone доступна только в личке.")
|
||
return
|
||
# Optional: restrict to allowed usernames; plan says "or without restrictions"
|
||
args = context.args or []
|
||
phone = " ".join(args).strip() if args else None
|
||
telegram_user_id = update.effective_user.id
|
||
|
||
def do_set_phone() -> str:
|
||
with session_scope(config.DATABASE_URL) as session:
|
||
full_name = build_full_name(
|
||
update.effective_user.first_name, update.effective_user.last_name
|
||
)
|
||
get_or_create_user(
|
||
session,
|
||
telegram_user_id=telegram_user_id,
|
||
full_name=full_name,
|
||
username=update.effective_user.username,
|
||
first_name=update.effective_user.first_name,
|
||
last_name=update.effective_user.last_name,
|
||
)
|
||
user = set_user_phone(session, telegram_user_id, phone or None)
|
||
if user is None:
|
||
return "Ошибка сохранения."
|
||
if phone:
|
||
return f"Телефон сохранён: {phone}"
|
||
return "Телефон очищен."
|
||
|
||
result = await asyncio.get_running_loop().run_in_executor(None, do_set_phone)
|
||
await update.message.reply_text(result)
|
||
|
||
|
||
async def help_cmd(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
|
||
if not update.message or not update.effective_user:
|
||
return
|
||
lines = [
|
||
"Доступные команды:",
|
||
"/start — Начать",
|
||
"/help — Показать эту справку",
|
||
"/set_phone — Указать или очистить телефон для отображения в дежурстве",
|
||
"/pin_duty — В группе: закрепить сообщение о дежурстве (нужны права админа у бота)",
|
||
]
|
||
if config.is_admin(update.effective_user.username or ""):
|
||
lines.append("/import_duty_schedule — Импорт расписания дежурств (JSON)")
|
||
await update.message.reply_text("\n".join(lines))
|
||
|
||
|
||
start_handler = CommandHandler("start", start)
|
||
help_handler = CommandHandler("help", help_cmd)
|
||
set_phone_handler = CommandHandler("set_phone", set_phone)
|