Add configuration rules, refactor settings management, and enhance import functionality

- 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.
This commit is contained in:
2026-02-18 12:35:11 +03:00
parent 8697b9e30b
commit 5331fac334
25 changed files with 1032 additions and 397 deletions

View File

@@ -6,8 +6,9 @@ import config
from telegram import Update
from telegram.ext import CommandHandler, ContextTypes
from db.session import get_session
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:
@@ -16,18 +17,14 @@ async def start(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
user = update.effective_user
if not user:
return
full_name = (
" ".join(filter(None, [user.first_name or "", user.last_name or ""])).strip()
or "User"
)
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:
session = get_session(config.DATABASE_URL)
try:
with session_scope(config.DATABASE_URL) as session:
get_or_create_user(
session,
telegram_user_id=telegram_user_id,
@@ -36,8 +33,6 @@ async def start(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
first_name=first_name,
last_name=last_name,
)
finally:
session.close()
await asyncio.get_running_loop().run_in_executor(None, do_get_or_create)
@@ -53,24 +48,14 @@ async def set_phone(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
await update.message.reply_text("Команда /set_phone доступна только в личке.")
return
# Optional: restrict to allowed usernames; plan says "or without restrictions"
args = (context.args or [])
args = context.args or []
phone = " ".join(args).strip() if args else None
telegram_user_id = update.effective_user.id
def do_set_phone() -> str:
session = get_session(config.DATABASE_URL)
try:
full_name = (
" ".join(
filter(
None,
[
update.effective_user.first_name or "",
update.effective_user.last_name or "",
],
)
).strip()
or "User"
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,
@@ -86,8 +71,6 @@ async def set_phone(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
if phone:
return f"Телефон сохранён: {phone}"
return "Телефон очищен."
finally:
session.close()
result = await asyncio.get_running_loop().run_in_executor(None, do_set_phone)
await update.message.reply_text(result)