From 719631158d730194e45e1d5e23b92fa908900cd0 Mon Sep 17 00:00:00 2001 From: wowlikon Date: Fri, 19 Dec 2025 21:28:52 +0300 Subject: [PATCH] =?UTF-8?q?=D0=98=D1=81=D0=BF=D1=80=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=D0=B8=D0=B5=20=D0=B0=D0=B2=D1=82=D0=BE=D0=BC=D0=B8?= =?UTF-8?q?=D0=B3=D1=80=D0=B0=D1=86=D0=B8=D0=B8=20=D0=B8=20=D1=81=D0=BE?= =?UTF-8?q?=D0=B7=D0=B4=D0=B0=D0=BD=D0=B8=D1=8F=20=D0=B0=D0=B4=D0=BC=D0=B8?= =?UTF-8?q?=D0=BD=D0=B8=D1=81=D1=82=D1=80=D0=B0=D1=82=D0=BE=D1=80=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- library_service/auth.py | 20 ++++++---- library_service/main.py | 40 +++++++++++++------ library_service/settings.py | 76 ++++++++++++++++++++----------------- migrations/env.py | 3 +- 4 files changed, 84 insertions(+), 55 deletions(-) diff --git a/library_service/auth.py b/library_service/auth.py index 9fffee1..bfe1831 100644 --- a/library_service/auth.py +++ b/library_service/auth.py @@ -11,7 +11,7 @@ from sqlmodel import Session, select from library_service.models.db import Role, User from library_service.models.dto import TokenData -from library_service.settings import get_session +from library_service.settings import get_session, get_logger # Конфигурация из переменных окружения @@ -20,12 +20,16 @@ SECRET_KEY = os.getenv("SECRET_KEY", "your-secret-key-change-in-production") ACCESS_TOKEN_EXPIRE_MINUTES = int(os.getenv("ACCESS_TOKEN_EXPIRE_MINUTES", "30")) REFRESH_TOKEN_EXPIRE_DAYS = int(os.getenv("REFRESH_TOKEN_EXPIRE_DAYS", "7")) -# Хэширование паролей -pwd_context = CryptContext(schemes=["argon2"], deprecated="auto") + +# Получение логгера +logger = get_logger("uvicorn") # OAuth2 схема oauth2_scheme = OAuth2PasswordBearer(tokenUrl="/auth/token") +# Хэширование паролей +pwd_context = CryptContext(schemes=["argon2"], deprecated="auto") + def verify_password(plain_password: str, hashed_password: str) -> bool: """Проверка пароль по его хешу.""" @@ -161,7 +165,7 @@ def seed_roles(session: Session) -> dict[str, Role]: session.commit() session.refresh(role) roles[role_data["name"]] = role - print(f"[+] Created role: {role_data['name']}") + logger.info(f"[+] Created role: {role_data['name']}") return roles @@ -173,7 +177,7 @@ def seed_admin(session: Session, admin_role: Role) -> User | None: ).all() if existing_admins: - print(f"[*] Admin already exists: {existing_admins[0].username}") + logger.info(f"[*] Admin already exists: {existing_admins[0].username}") return None admin_username = os.getenv("DEFAULT_ADMIN_USERNAME", "admin") @@ -183,8 +187,8 @@ def seed_admin(session: Session, admin_role: Role) -> User | None: if not admin_password: import secrets admin_password = secrets.token_urlsafe(16) - print(f"[!] Generated admin password: {admin_password}") - print("[!] Please save this password and set DEFAULT_ADMIN_PASSWORD env var") + logger.warning(f"[!] Generated admin password: {admin_password}") + logger.warning("[!] Please save this password and set DEFAULT_ADMIN_PASSWORD env var") admin_user = User( username=admin_username, @@ -200,7 +204,7 @@ def seed_admin(session: Session, admin_role: Role) -> User | None: session.commit() session.refresh(admin_user) - print(f"[+] Created admin user: {admin_username}") + logger.info(f"[+] Created admin user: {admin_username}") return admin_user diff --git a/library_service/main.py b/library_service/main.py index eb42121..692b6fd 100644 --- a/library_service/main.py +++ b/library_service/main.py @@ -6,27 +6,43 @@ from alembic import command from alembic.config import Config from fastapi import FastAPI from fastapi.staticfiles import StaticFiles +from sqlmodel import Session +from .auth import run_seeds from .routers import api_router -from .settings import engine, get_app - -app = get_app() -alembic_cfg = Config("alembic.ini") +from .settings import engine, get_app, get_logger @asynccontextmanager async def lifespan(app: FastAPI): - """Жизененый цикл сервиса""" - print("[+] Initializing...") + """Жизненный цикл сервиса""" + logger = get_logger("uvicorn") + logger.info("[+] Initializing database...") - # Настройка базы данных - with engine.begin() as connection: - alembic_cfg.attributes["connection"] = connection - command.upgrade(alembic_cfg, "head") + try: + with engine.begin() as connection: + alembic_cfg = Config("alembic.ini") + alembic_cfg.attributes["configure_logging"] = False + alembic_cfg.attributes["connection"] = connection + command.upgrade(alembic_cfg, "head") + except Exception as e: + logger.error(f"[-] Migration failed: {e}") + raise e - print("[+] Starting...") + logger.info("[+] Running seeds...") + try: + with Session(engine) as session: + run_seeds(session) + logger.info("[+] Database setup completed.") + except Exception as e: + logger.error(f"[-] Seeding failed: {e}") + + logger.info("[+] Starting application...") yield # Обработка запросов - print("[+] Application shutdown") + logger.info("[+] Application shutdown") + + +app = get_app(lifespan) # Подключение маршрутов diff --git a/library_service/settings.py b/library_service/settings.py index a6585b2..7f8d038 100644 --- a/library_service/settings.py +++ b/library_service/settings.py @@ -1,5 +1,5 @@ """Модуль настроек проекта""" -import os +import os, logging from dotenv import load_dotenv from fastapi import FastAPI @@ -12,39 +12,42 @@ with open("pyproject.toml", 'r', encoding='utf-8') as f: config = load(f) -def get_app() -> FastAPI: - """Dependency, для получение экземплярра FastAPI application""" - return FastAPI( - title=config["tool"]["poetry"]["name"], - description=config["tool"]["poetry"]["description"], - version=config["tool"]["poetry"]["version"], - openapi_tags=[ - { - "name": "authentication", - "description": "Авторизация пользователя." - }, - { - "name": "authors", - "description": "Действия с авторами.", - }, - { - "name": "books", - "description": "Действия с книгами.", - }, - { - "name": "genres", - "description": "Действия с жанрами.", - }, - { - "name": "relations", - "description": "Действия с связями.", - }, - { - "name": "misc", - "description": "Прочие.", - }, - ], - ) +def get_app(lifespan=None) -> FastAPI: + """Dependency для получения экземпляра FastAPI application""" + if not hasattr(get_app, 'instance'): + get_app.instance = FastAPI( + title=config["tool"]["poetry"]["name"], + description=config["tool"]["poetry"]["description"], + version=config["tool"]["poetry"]["version"], + lifespan=lifespan, + openapi_tags=[ + { + "name": "authentication", + "description": "Авторизация пользователя." + }, + { + "name": "authors", + "description": "Действия с авторами.", + }, + { + "name": "books", + "description": "Действия с книгами.", + }, + { + "name": "genres", + "description": "Действия с жанрами.", + }, + { + "name": "relations", + "description": "Действия с связями.", + }, + { + "name": "misc", + "description": "Прочие.", + }, + ], + ) + return get_app.instance HOST = os.getenv("POSTGRES_HOST") @@ -64,3 +67,8 @@ def get_session(): """Dependency, для получение сессии БД""" with Session(engine) as session: yield session + + +def get_logger(name: str = "uvicorn"): + """Dependency, для получение логгера""" + return logging.getLogger(name) diff --git a/migrations/env.py b/migrations/env.py index bcc58f9..dee1f96 100644 --- a/migrations/env.py +++ b/migrations/env.py @@ -16,7 +16,8 @@ config.set_main_option("sqlalchemy.url", POSTGRES_DATABASE_URL) # Interpret the config file for Python logging. # This line sets up loggers basically. if config.config_file_name is not None: - fileConfig(config.config_file_name) + if config.attributes.get("configure_logging", True): + fileConfig(config.config_file_name) # add your model's MetaData object here # for 'autogenerate' support