Расширение фронтэнда

This commit is contained in:
2025-12-22 01:38:52 +03:00
parent 5096b45243
commit 9d25d2e5de
35 changed files with 4901 additions and 288 deletions
+63 -8
View File
@@ -2,15 +2,15 @@
from datetime import timedelta
from typing import Annotated
from fastapi import APIRouter, Depends, HTTPException, status
from fastapi import APIRouter, Body, Depends, HTTPException, status
from fastapi.security import OAuth2PasswordRequestForm
from sqlmodel import Session, select
from library_service.models.db import Role, User
from library_service.models.dto import Token, UserCreate, UserRead, UserUpdate, UserList, RoleRead, RoleList
from library_service.settings import get_session
from library_service.auth import (ACCESS_TOKEN_EXPIRE_MINUTES, RequireAdmin,
RequireAuth, authenticate_user, get_password_hash,
from library_service.auth import (ACCESS_TOKEN_EXPIRE_MINUTES, RequireAdmin, RequireAuth,
authenticate_user, get_password_hash, decode_token,
create_access_token, create_refresh_token)
router = APIRouter(prefix="/auth", tags=["authentication"])
@@ -49,7 +49,7 @@ def register(user_data: UserCreate, session: Session = Depends(get_session)):
hashed_password=get_password_hash(user_data.password)
)
default_role = session.exec(select(Role).where(Role.name == "user")).first()
default_role = session.exec(select(Role).where(Role.name == "member")).first()
if default_role:
db_user.roles.append(default_role)
@@ -93,13 +93,62 @@ def login(
)
@router.post(
"/refresh",
response_model=Token,
summary="Обновление токена",
description="Получение новой пары токенов (Access + Refresh) используя действующий Refresh токен",
)
def refresh_token(
refresh_token: str = Body(..., embed=True),
session: Session = Depends(get_session),
):
"""Эндпоинт для обновления токенов."""
try:
token_data = decode_token(refresh_token, expected_type="refresh")
except HTTPException:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Invalid refresh token",
headers={"WWW-Authenticate": "Bearer"},
)
user = session.get(User, token_data.user_id)
if not user:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="User not found",
)
if not user.is_active:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="User is inactive",
)
access_token_expires = timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES)
new_access_token = create_access_token(
data={"sub": user.username, "user_id": user.id},
expires_delta=access_token_expires,
)
new_refresh_token = create_refresh_token(
data={"sub": user.username, "user_id": user.id}
)
return Token(
access_token=new_access_token,
refresh_token=new_refresh_token,
token_type="bearer",
)
@router.get(
"/me",
response_model=UserRead,
summary="Текущий пользователь",
description="Получить информацию о текущем авторизованном пользователе",
)
def read_users_me(current_user: RequireAuth):
def get_my_profile(current_user: RequireAuth):
"""Эндпоинт получения информации о себе"""
return UserRead(
**current_user.model_dump(), roles=[role.name for role in current_user.roles]
@@ -142,14 +191,17 @@ def update_user_me(
)
def read_users(
admin: RequireAdmin,
session: Session = Depends(get_session),
skip: int = 0,
limit: int = 100,
session: Session = Depends(get_session),
):
"""Эндпоинт получения списка всех пользователей"""
users = session.exec(select(User).offset(skip).limit(limit)).all()
return UserList(
users=[UserRead(**user.model_dump()) for user in users],
users=[
UserRead(**user.model_dump(), roles=[r.name for r in user.roles])
for user in users
],
total=len(users),
)
@@ -243,11 +295,14 @@ def remove_role_from_user(
description="Возвращает список ролей",
)
def get_roles(
auth: RequireAuth,
session: Session = Depends(get_session),
):
"""Эндпоинт получения списа ролей"""
user_roles = [role.name for role in auth.roles]
exclude = {"payroll"} if "admin" in user_roles else set()
roles = session.exec(select(Role)).all()
return RoleList(
roles=[RoleRead(**role.model_dump()) for role in roles],
roles=[RoleRead(**role.model_dump(exclude=exclude)) for role in roles],
total=len(roles),
)
+3 -2
View File
@@ -67,7 +67,7 @@ def filter_books(
@router.post(
"/",
response_model=Book,
response_model=BookRead,
summary="Создать книгу",
description="Добавляет книгу в систему",
)
@@ -149,6 +149,7 @@ def update_book(
db_book.title = book.title or db_book.title
db_book.description = book.description or db_book.description
db_book.status = book.status or db_book.status
session.commit()
session.refresh(db_book)
return db_book
@@ -170,7 +171,7 @@ def delete_book(
if not book:
raise HTTPException(status_code=404, detail="Book not found")
book_read = BookRead(
id=(book.id or 0), title=book.title, description=book.description
id=(book.id or 0), title=book.title, description=book.description, status=book.status
)
session.delete(book)
session.commit()
+46 -4
View File
@@ -36,12 +36,36 @@ async def root(request: Request):
return templates.TemplateResponse(request, "index.html")
@router.get("/genre/create", include_in_schema=False)
async def create_genre(request: Request):
"""Эндпоинт страницы создания жанра"""
return templates.TemplateResponse(request, "create_genre.html")
@router.get("/genre/{genre_id}/edit", include_in_schema=False)
async def edit_genre(request: Request, genre_id: int):
"""Эндпоинт страницы редактирования жанра"""
return templates.TemplateResponse(request, "edit_genre.html")
@router.get("/authors", include_in_schema=False)
async def authors(request: Request):
"""Эндпоинт страницы выбора автора"""
return templates.TemplateResponse(request, "authors.html")
@router.get("/author/create", include_in_schema=False)
async def create_author(request: Request):
"""Эндпоинт страницы создания автора"""
return templates.TemplateResponse(request, "create_author.html")
@router.get("/author/{author_id}/edit", include_in_schema=False)
async def edit_author(request: Request, author_id: int):
"""Эндпоинт страницы редактирования автора"""
return templates.TemplateResponse(request, "edit_author.html")
@router.get("/author/{author_id}", include_in_schema=False)
async def author(request: Request, author_id: int):
"""Эндпоинт страницы автора"""
@@ -54,16 +78,28 @@ async def books(request: Request):
return templates.TemplateResponse(request, "books.html")
@router.get("/book/create", include_in_schema=False)
async def create_book(request: Request):
"""Эндпоинт страницы создания книги"""
return templates.TemplateResponse(request, "create_book.html")
@router.get("/book/{book_id}/edit", include_in_schema=False)
async def edit_book(request: Request, book_id: int):
"""Эндпоинт страницы редактирования книги"""
return templates.TemplateResponse(request, "edit_book.html")
@router.get("/book/{book_id}", include_in_schema=False)
async def book(request: Request, book_id: int):
"""Эндпоинт страницы книги"""
return templates.TemplateResponse(request, "book.html")
@router.get("/auth", include_in_schema=False)
async def auth(request: Request):
"""Эндпоинт страницы авторизации"""
return templates.TemplateResponse(request, "auth.html")
@router.get("/auth", include_in_schema=False)
async def auth(request: Request):
"""Эндпоинт страницы авторизации"""
return templates.TemplateResponse(request, "auth.html")
@router.get("/profile", include_in_schema=False)
@@ -72,6 +108,12 @@ async def profile(request: Request):
return templates.TemplateResponse(request, "profile.html")
@router.get("/users", include_in_schema=False)
async def users(request: Request):
"""Эндпоинт страницы управления пользователями"""
return templates.TemplateResponse(request, "users.html")
@router.get("/api", include_in_schema=False)
async def api(request: Request, app=Depends(lambda: get_app())):
"""Страница с сылками на документацию API"""