mirror of
https://github.com/wowlikon/LiB.git
synced 2026-02-04 04:31:09 +00:00
Исправление автомиграции и создания администратора
This commit is contained in:
+12
-8
@@ -11,7 +11,7 @@ from sqlmodel import Session, select
|
|||||||
|
|
||||||
from library_service.models.db import Role, User
|
from library_service.models.db import Role, User
|
||||||
from library_service.models.dto import TokenData
|
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"))
|
ACCESS_TOKEN_EXPIRE_MINUTES = int(os.getenv("ACCESS_TOKEN_EXPIRE_MINUTES", "30"))
|
||||||
REFRESH_TOKEN_EXPIRE_DAYS = int(os.getenv("REFRESH_TOKEN_EXPIRE_DAYS", "7"))
|
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 схема
|
||||||
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="/auth/token")
|
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="/auth/token")
|
||||||
|
|
||||||
|
# Хэширование паролей
|
||||||
|
pwd_context = CryptContext(schemes=["argon2"], deprecated="auto")
|
||||||
|
|
||||||
|
|
||||||
def verify_password(plain_password: str, hashed_password: str) -> bool:
|
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.commit()
|
||||||
session.refresh(role)
|
session.refresh(role)
|
||||||
roles[role_data["name"]] = role
|
roles[role_data["name"]] = role
|
||||||
print(f"[+] Created role: {role_data['name']}")
|
logger.info(f"[+] Created role: {role_data['name']}")
|
||||||
|
|
||||||
return roles
|
return roles
|
||||||
|
|
||||||
@@ -173,7 +177,7 @@ def seed_admin(session: Session, admin_role: Role) -> User | None:
|
|||||||
).all()
|
).all()
|
||||||
|
|
||||||
if existing_admins:
|
if existing_admins:
|
||||||
print(f"[*] Admin already exists: {existing_admins[0].username}")
|
logger.info(f"[*] Admin already exists: {existing_admins[0].username}")
|
||||||
return None
|
return None
|
||||||
|
|
||||||
admin_username = os.getenv("DEFAULT_ADMIN_USERNAME", "admin")
|
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:
|
if not admin_password:
|
||||||
import secrets
|
import secrets
|
||||||
admin_password = secrets.token_urlsafe(16)
|
admin_password = secrets.token_urlsafe(16)
|
||||||
print(f"[!] Generated admin password: {admin_password}")
|
logger.warning(f"[!] Generated admin password: {admin_password}")
|
||||||
print("[!] Please save this password and set DEFAULT_ADMIN_PASSWORD env var")
|
logger.warning("[!] Please save this password and set DEFAULT_ADMIN_PASSWORD env var")
|
||||||
|
|
||||||
admin_user = User(
|
admin_user = User(
|
||||||
username=admin_username,
|
username=admin_username,
|
||||||
@@ -200,7 +204,7 @@ def seed_admin(session: Session, admin_role: Role) -> User | None:
|
|||||||
session.commit()
|
session.commit()
|
||||||
session.refresh(admin_user)
|
session.refresh(admin_user)
|
||||||
|
|
||||||
print(f"[+] Created admin user: {admin_username}")
|
logger.info(f"[+] Created admin user: {admin_username}")
|
||||||
return admin_user
|
return admin_user
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+25
-9
@@ -6,27 +6,43 @@ from alembic import command
|
|||||||
from alembic.config import Config
|
from alembic.config import Config
|
||||||
from fastapi import FastAPI
|
from fastapi import FastAPI
|
||||||
from fastapi.staticfiles import StaticFiles
|
from fastapi.staticfiles import StaticFiles
|
||||||
|
from sqlmodel import Session
|
||||||
|
|
||||||
|
from .auth import run_seeds
|
||||||
from .routers import api_router
|
from .routers import api_router
|
||||||
from .settings import engine, get_app
|
from .settings import engine, get_app, get_logger
|
||||||
|
|
||||||
app = get_app()
|
|
||||||
alembic_cfg = Config("alembic.ini")
|
|
||||||
|
|
||||||
|
|
||||||
@asynccontextmanager
|
@asynccontextmanager
|
||||||
async def lifespan(app: FastAPI):
|
async def lifespan(app: FastAPI):
|
||||||
"""Жизененый цикл сервиса"""
|
"""Жизненный цикл сервиса"""
|
||||||
print("[+] Initializing...")
|
logger = get_logger("uvicorn")
|
||||||
|
logger.info("[+] Initializing database...")
|
||||||
|
|
||||||
# Настройка базы данных
|
try:
|
||||||
with engine.begin() as connection:
|
with engine.begin() as connection:
|
||||||
|
alembic_cfg = Config("alembic.ini")
|
||||||
|
alembic_cfg.attributes["configure_logging"] = False
|
||||||
alembic_cfg.attributes["connection"] = connection
|
alembic_cfg.attributes["connection"] = connection
|
||||||
command.upgrade(alembic_cfg, "head")
|
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 # Обработка запросов
|
yield # Обработка запросов
|
||||||
print("[+] Application shutdown")
|
logger.info("[+] Application shutdown")
|
||||||
|
|
||||||
|
|
||||||
|
app = get_app(lifespan)
|
||||||
|
|
||||||
|
|
||||||
# Подключение маршрутов
|
# Подключение маршрутов
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
"""Модуль настроек проекта"""
|
"""Модуль настроек проекта"""
|
||||||
import os
|
import os, logging
|
||||||
|
|
||||||
from dotenv import load_dotenv
|
from dotenv import load_dotenv
|
||||||
from fastapi import FastAPI
|
from fastapi import FastAPI
|
||||||
@@ -12,12 +12,14 @@ with open("pyproject.toml", 'r', encoding='utf-8') as f:
|
|||||||
config = load(f)
|
config = load(f)
|
||||||
|
|
||||||
|
|
||||||
def get_app() -> FastAPI:
|
def get_app(lifespan=None) -> FastAPI:
|
||||||
"""Dependency, для получение экземплярра FastAPI application"""
|
"""Dependency для получения экземпляра FastAPI application"""
|
||||||
return FastAPI(
|
if not hasattr(get_app, 'instance'):
|
||||||
|
get_app.instance = FastAPI(
|
||||||
title=config["tool"]["poetry"]["name"],
|
title=config["tool"]["poetry"]["name"],
|
||||||
description=config["tool"]["poetry"]["description"],
|
description=config["tool"]["poetry"]["description"],
|
||||||
version=config["tool"]["poetry"]["version"],
|
version=config["tool"]["poetry"]["version"],
|
||||||
|
lifespan=lifespan,
|
||||||
openapi_tags=[
|
openapi_tags=[
|
||||||
{
|
{
|
||||||
"name": "authentication",
|
"name": "authentication",
|
||||||
@@ -45,6 +47,7 @@ def get_app() -> FastAPI:
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
return get_app.instance
|
||||||
|
|
||||||
|
|
||||||
HOST = os.getenv("POSTGRES_HOST")
|
HOST = os.getenv("POSTGRES_HOST")
|
||||||
@@ -64,3 +67,8 @@ def get_session():
|
|||||||
"""Dependency, для получение сессии БД"""
|
"""Dependency, для получение сессии БД"""
|
||||||
with Session(engine) as session:
|
with Session(engine) as session:
|
||||||
yield session
|
yield session
|
||||||
|
|
||||||
|
|
||||||
|
def get_logger(name: str = "uvicorn"):
|
||||||
|
"""Dependency, для получение логгера"""
|
||||||
|
return logging.getLogger(name)
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ config.set_main_option("sqlalchemy.url", POSTGRES_DATABASE_URL)
|
|||||||
# Interpret the config file for Python logging.
|
# Interpret the config file for Python logging.
|
||||||
# This line sets up loggers basically.
|
# This line sets up loggers basically.
|
||||||
if config.config_file_name is not None:
|
if config.config_file_name is not None:
|
||||||
|
if config.attributes.get("configure_logging", True):
|
||||||
fileConfig(config.config_file_name)
|
fileConfig(config.config_file_name)
|
||||||
|
|
||||||
# add your model's MetaData object here
|
# add your model's MetaData object here
|
||||||
|
|||||||
Reference in New Issue
Block a user