Добавление авторизации и фронтэнда

This commit is contained in:
2025-12-18 18:52:09 +03:00
parent 2c24f66de0
commit 756e941f99
55 changed files with 2314 additions and 577 deletions
+22 -4
View File
@@ -1,7 +1,12 @@
from .author import AuthorBase, AuthorCreate, AuthorUpdate, AuthorRead, AuthorList
from .book import BookBase, BookCreate, BookUpdate, BookRead, BookList
from .genre import GenreBase, GenreCreate, GenreUpdate, GenreRead, GenreList
"""Модуль DTO-моделей"""
from .author import AuthorBase, AuthorCreate, AuthorList, AuthorRead, AuthorUpdate
from .genre import GenreBase, GenreCreate, GenreList, GenreRead, GenreUpdate
from .book import BookBase, BookCreate, BookList, BookRead, BookUpdate
from .role import RoleBase, RoleCreate, RoleList, RoleRead, RoleUpdate
from .user import UserBase, UserCreate, UserLogin, UserRead, UserUpdate
from .token import Token, TokenData
from .combined import (AuthorWithBooks, GenreWithBooks, BookWithAuthors, BookWithGenres,
BookWithAuthorsAndGenres, BookFilteredList)
__all__ = [
"AuthorBase",
@@ -14,9 +19,22 @@ __all__ = [
"BookUpdate",
"BookRead",
"BookList",
"BookFilteredList",
"GenreBase",
"GenreCreate",
"GenreUpdate",
"GenreRead",
"GenreList",
"RoleBase",
"RoleCreate",
"RoleUpdate",
"RoleRead",
"RoleList",
"Token",
"TokenData",
"UserBase",
"UserCreate",
"UserRead",
"UserUpdate",
"UserLogin",
]
+10 -3
View File
@@ -1,9 +1,12 @@
from sqlmodel import SQLModel
"""Модуль DTO-моделей авторов"""
from typing import List
from pydantic import ConfigDict
from typing import Optional, List
from sqlmodel import SQLModel
class AuthorBase(SQLModel):
"""Базовая модель автора"""
name: str
model_config = ConfigDict( # pyright: ignore
@@ -12,17 +15,21 @@ class AuthorBase(SQLModel):
class AuthorCreate(AuthorBase):
"""Модель автора для создания"""
pass
class AuthorUpdate(SQLModel):
name: Optional[str] = None
"""Модель автора для обновления"""
name: str | None = None
class AuthorRead(AuthorBase):
"""Модель автора для чтения"""
id: int
class AuthorList(SQLModel):
"""Список авторов"""
authors: List[AuthorRead]
total: int
+14 -4
View File
@@ -1,9 +1,15 @@
from sqlmodel import SQLModel
"""Модуль DTO-моделей книг"""
from typing import List, TYPE_CHECKING
from pydantic import ConfigDict
from typing import Optional, List
from sqlmodel import SQLModel
if TYPE_CHECKING:
from .combined import BookWithAuthorsAndGenres
class BookBase(SQLModel):
"""Базовая модель книги"""
title: str
description: str
@@ -15,18 +21,22 @@ class BookBase(SQLModel):
class BookCreate(BookBase):
"""Модель книги для создания"""
pass
class BookUpdate(SQLModel):
title: Optional[str] = None
description: Optional[str] = None
"""Модель книги для обновления"""
title: str | None = None
description: str | None = None
class BookRead(BookBase):
"""Модель книги для чтения"""
id: int
class BookList(SQLModel):
"""Список книг"""
books: List[BookRead]
total: int
+53
View File
@@ -0,0 +1,53 @@
"""Модуль объединёных объектов"""
from typing import List
from sqlmodel import SQLModel, Field
from .author import AuthorRead
from .genre import GenreRead
from .book import BookRead
class AuthorWithBooks(SQLModel):
"""Модель автора с книгами"""
id: int
name: str
bio: str
books: List[BookRead] = Field(default_factory=list)
class GenreWithBooks(SQLModel):
"""Модель жанра с книгами"""
id: int
name: str
books: List[BookRead] = Field(default_factory=list)
class BookWithAuthors(SQLModel):
"""Модель книги с авторами"""
id: int
title: str
description: str
authors: List[AuthorRead] = Field(default_factory=list)
class BookWithGenres(SQLModel):
"""Модель книги с жанрами"""
id: int
title: str
description: str
genres: List[GenreRead] = Field(default_factory=list)
class BookWithAuthorsAndGenres(SQLModel):
"""Модель с авторами и жанрами"""
id: int
title: str
description: str
authors: List[AuthorRead] = Field(default_factory=list)
genres: List[GenreRead] = Field(default_factory=list)
class BookFilteredList(SQLModel):
"""Список книг с фильтрацией"""
books: List[BookWithAuthorsAndGenres]
total: int
+10 -3
View File
@@ -1,9 +1,12 @@
from sqlmodel import SQLModel
"""Модуль DTO-моделей жанров"""
from typing import List
from pydantic import ConfigDict
from typing import Optional, List
from sqlmodel import SQLModel
class GenreBase(SQLModel):
"""Базовая модель жанра"""
name: str
model_config = ConfigDict( # pyright: ignore
@@ -12,17 +15,21 @@ class GenreBase(SQLModel):
class GenreCreate(GenreBase):
"""Модель жанра для создания"""
pass
class GenreUpdate(SQLModel):
name: Optional[str] = None
"""Модель жанра для обновления"""
name: str | None = None
class GenreRead(GenreBase):
"""Модель жанра для чтения"""
id: int
class GenreList(SQLModel):
"""Списко жанров"""
genres: List[GenreRead]
total: int
+31
View File
@@ -0,0 +1,31 @@
"""Модуль DTO-моделей ролей"""
from typing import List
from sqlmodel import SQLModel
class RoleBase(SQLModel):
"""Базовая модель роли"""
name: str
description: str | None = None
class RoleCreate(RoleBase):
"""Модель роли для создания"""
pass
class RoleUpdate(SQLModel):
"""Модель роли для обновления"""
name: str | None = None
class RoleRead(RoleBase):
"""Модель роли для чтения"""
id: int
class RoleList(SQLModel):
"""Список ролей"""
roles: List[RoleRead]
total: int
+15
View File
@@ -0,0 +1,15 @@
"""Модуль DTO-моделей токенов"""
from sqlmodel import SQLModel
class Token(SQLModel):
"""Модель токена"""
access_token: str
token_type: str = "bearer"
refresh_token: str | None = None
class TokenData(SQLModel):
"""Модель содержимого токена"""
username: str | None = None
user_id: int | None = None
+61
View File
@@ -0,0 +1,61 @@
"""Модуль DTO-моделей пользователей"""
import re
from typing import List
from pydantic import ConfigDict, EmailStr, field_validator
from sqlmodel import Field, SQLModel
class UserBase(SQLModel):
"""Базовая модель пользователя"""
username: str = Field(min_length=3, max_length=50, index=True, unique=True)
email: EmailStr = Field(index=True, unique=True)
full_name: str | None = Field(default=None, max_length=100)
model_config = ConfigDict(
json_schema_extra={
"example": {
"username": "johndoe",
"email": "john@example.com",
"full_name": "John Doe",
}
}
)
class UserCreate(UserBase):
"""Модель пользователя для создания"""
password: str = Field(min_length=8, max_length=100)
@field_validator("password")
@classmethod
def validate_password(cls, v: str) -> str:
"""Валидация пароля"""
if not re.search(r"[A-Z]", v):
raise ValueError("Пароль должен содержать символы в верхнем регистре")
if not re.search(r"[a-z]", v):
raise ValueError("Пароль должен содержать символы в нижнем регистре")
if not re.search(r"\d", v):
raise ValueError("пароль должен содержать цифры")
return v
class UserLogin(SQLModel):
"""Модель аутентификации для пользователя"""
username: str
password: str
class UserRead(UserBase):
"""Модель пользователя для чтения"""
id: int
is_active: bool
is_verified: bool
roles: List[str] = []
class UserUpdate(SQLModel):
"""Модель пользователя для обновления"""
email: EmailStr | None = None
full_name: str | None = None
password: str | None = None