Compare commits
No commits in common. "c0ee89f175b562c64481515b5da26c4972237974" and "c6e82f292d6f5570e971f73a220e891e9c968391" have entirely different histories.
c0ee89f175
...
c6e82f292d
@ -4,4 +4,3 @@ DB_PASSWORD=db_password
|
||||
DB_HOST=localhost
|
||||
DB_PORT=5432
|
||||
DB_ECHO=True
|
||||
SECRET_KEY=1234567890abcdefghigklmnopqrstuvwxyz
|
||||
|
@ -1,7 +0,0 @@
|
||||
"""
|
||||
Проект: Lkeep
|
||||
Автор: Иван Ашихмин
|
||||
Год: 2025
|
||||
Специально для проекта "Код на салфетке"
|
||||
https://pressanybutton.ru/category/servis-na-fastapi/
|
||||
"""
|
@ -1,7 +0,0 @@
|
||||
"""
|
||||
Проект: Lkeep
|
||||
Автор: Иван Ашихмин
|
||||
Год: 2025
|
||||
Специально для проекта "Код на салфетке"
|
||||
https://pressanybutton.ru/category/servis-na-fastapi/
|
||||
"""
|
@ -1,28 +0,0 @@
|
||||
from passlib.context import CryptContext
|
||||
|
||||
from lkeep.core.settings import settings
|
||||
|
||||
|
||||
class AuthHandler:
|
||||
"""
|
||||
Обрабатывает аутентификационные запросы и обеспечивает безопасность пользовательских данных.
|
||||
|
||||
:ivar secret: Секретный ключ, используемый для дополнительной безопасности при генерации хешей.
|
||||
:type secret: str
|
||||
:ivar pwd_context: Контекст для использования bcrypt-алгоритма хеширования паролей.
|
||||
:type pwd_context: CryptContext
|
||||
"""
|
||||
|
||||
secret = settings.secret_key.get_secret_value()
|
||||
pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
|
||||
|
||||
async def get_password_hash(self, password: str) -> str:
|
||||
"""
|
||||
Генерирует хэш-значение пароля для безопасного сохранения и сравнения.
|
||||
|
||||
:param password: Пароль пользователя, который нужно зашифровать.
|
||||
:type password: str
|
||||
:returns: Хешированный вариант пароля.
|
||||
:rtype: str
|
||||
"""
|
||||
return self.pwd_context.hash(password)
|
@ -1,56 +0,0 @@
|
||||
"""
|
||||
Проект: Lkeep
|
||||
Автор: Иван Ашихмин
|
||||
Год: 2025
|
||||
Специально для проекта "Код на салфетке"
|
||||
https://pressanybutton.ru/category/servis-na-fastapi/
|
||||
"""
|
||||
|
||||
from fastapi import Depends, HTTPException
|
||||
from sqlalchemy import insert
|
||||
from sqlalchemy.exc import IntegrityError
|
||||
|
||||
from lkeep.apps.auth.schemas import CreateUser, UserReturnData
|
||||
from lkeep.core.core_dependency.db_dependency import DBDependency
|
||||
from lkeep.database.models import User
|
||||
|
||||
|
||||
class UserManager:
|
||||
"""
|
||||
Класс для управления пользователями.
|
||||
"""
|
||||
|
||||
def __init__(self, model: type[User] = User, db: DBDependency = Depends(DBDependency)) -> None:
|
||||
"""
|
||||
Инициализирует экземпляр класса.
|
||||
|
||||
:param model: Модель, используемая для работы с данными.
|
||||
:type model: Type[User]
|
||||
:param db: Зависимость от базы данных. По умолчанию используется Depends(DBDependency).
|
||||
:type db: DBDependency
|
||||
"""
|
||||
self.db = db
|
||||
self.model = model
|
||||
|
||||
async def create_user(self, user: CreateUser) -> UserReturnData:
|
||||
"""
|
||||
Создает нового пользователя в базе данных.
|
||||
|
||||
:param user: Объект с данными для создания пользователя.
|
||||
:type user: CreateUser
|
||||
:returns: Данные созданного пользователя.
|
||||
:rtype: UserReturnData
|
||||
:raises HTTPException: Если пользователь уже существует.
|
||||
"""
|
||||
async with self.db.db_session as session:
|
||||
query = insert(self.model).values(**user.model_dump()).returning(self.model)
|
||||
|
||||
try:
|
||||
result = await session.execute(query)
|
||||
except IntegrityError:
|
||||
raise HTTPException(status_code=400, detail="User already exists.")
|
||||
|
||||
await session.commit()
|
||||
|
||||
user_data = await result.scalar_one()
|
||||
return UserReturnData(**user_data.__dict__)
|
@ -1,79 +0,0 @@
|
||||
"""
|
||||
Проект: Lkeep
|
||||
Автор: Иван Ашихмин
|
||||
Год: 2025
|
||||
Специально для проекта "Код на салфетке"
|
||||
https://pressanybutton.ru/category/servis-na-fastapi/
|
||||
"""
|
||||
|
||||
import datetime
|
||||
import uuid
|
||||
|
||||
from pydantic import BaseModel, EmailStr
|
||||
|
||||
|
||||
class GetUserByID(BaseModel):
|
||||
"""
|
||||
Класс для получения пользователя по его уникальному идентификатору (ID).
|
||||
|
||||
:ivar id: Уникальный идентификатор пользователя, может быть представлен как объект типа uuid.UUID или строкой.
|
||||
:type id: uuid.UUID | str
|
||||
"""
|
||||
|
||||
id: uuid.UUID | str
|
||||
|
||||
|
||||
class GetUserByEmail(BaseModel):
|
||||
"""
|
||||
Класс для поиска пользователя по электронной почте.
|
||||
|
||||
:ivar email: Электронная почта пользователя.
|
||||
:type email: EmailStr
|
||||
"""
|
||||
|
||||
email: EmailStr
|
||||
|
||||
|
||||
class RegisterUser(GetUserByEmail):
|
||||
"""
|
||||
Класс для регистрации пользователя, наследующий класс GetUserByEmail.
|
||||
|
||||
:ivar password: Пароль пользователя.
|
||||
:type password: str
|
||||
"""
|
||||
|
||||
password: str
|
||||
|
||||
|
||||
class CreateUser(GetUserByEmail):
|
||||
"""
|
||||
Класс для создания пользователя.
|
||||
|
||||
:ivar hashed_password: Хэшированный пароль пользователя.
|
||||
:type hashed_password: str
|
||||
"""
|
||||
|
||||
hashed_password: str
|
||||
|
||||
|
||||
class UserReturnData(GetUserByID, GetUserByEmail):
|
||||
"""
|
||||
Класс для представления данных пользователя, возвращаемых из API.
|
||||
|
||||
:ivar is_active: Статус активности пользователя.
|
||||
:type is_active: bool
|
||||
:ivar is_verified: Статус верификации пользователя.
|
||||
:type is_verified: bool
|
||||
:ivar is_superuser: Флаг, указывающий на наличие привилегий суперпользователя.
|
||||
:type is_superuser: bool
|
||||
:ivar created_at: Временная метка создания записи о пользователе.
|
||||
:type created_at: datetime.datetime
|
||||
:ivar updated_at: Временная метка последнего обновления записи о пользователе.
|
||||
:type updated_at: datetime.datetime
|
||||
"""
|
||||
|
||||
is_active: bool
|
||||
is_verified: bool
|
||||
is_superuser: bool
|
||||
created_at: datetime.datetime
|
||||
updated_at: datetime.datetime
|
@ -1,18 +1,21 @@
|
||||
from sqlalchemy.ext.asyncio import AsyncSession, async_sessionmaker, create_async_engine
|
||||
|
||||
from lkeep.core.settings import settings
|
||||
|
||||
|
||||
class DBDependency:
|
||||
"""
|
||||
Класс для управления зависимостями базы данных, используя SQLAlchemy.
|
||||
"""
|
||||
|
||||
def __init__(self) -> None:
|
||||
def __init__(self, db_url: str, db_echo: bool) -> None:
|
||||
"""
|
||||
Инициализирует экземпляр класса, отвечающего за взаимодействие с асинхронной базой данных.
|
||||
|
||||
:param db_url: URL для подключения к базе данных.
|
||||
:type db_url: str
|
||||
:param db_echo: Флаг, определяющий вывод подробных логов при взаимодействии с базой данных.
|
||||
:type db_echo: bool
|
||||
"""
|
||||
self._engine = create_async_engine(url=settings.db_settings.db_url, echo=settings.db_settings.db_echo)
|
||||
self._engine = create_async_engine(url=db_url, echo=db_echo)
|
||||
self._session_factory = async_sessionmaker(bind=self._engine, expire_on_commit=False, autocommit=False)
|
||||
|
||||
@property
|
||||
|
@ -54,14 +54,9 @@ class Settings(BaseSettings):
|
||||
|
||||
:ivar db_settings: Экземпляр класса DBSettings, содержащий настройки базы данных.
|
||||
:type db_settings: DBSettings
|
||||
:ivar secret_key: Секретный ключ для шифрования
|
||||
:type secret_key: SecretStr
|
||||
"""
|
||||
|
||||
db_settings: DBSettings = DBSettings()
|
||||
secret_key: SecretStr
|
||||
|
||||
model_config = SettingsConfigDict(env_file=".env", env_file_encoding="utf8", extra="ignore")
|
||||
|
||||
|
||||
settings = Settings()
|
||||
|
56
poetry.lock
generated
56
poetry.lock
generated
@ -118,41 +118,6 @@ docs = ["Sphinx (>=8.1.3,<8.2.0)", "sphinx-rtd-theme (>=1.2.2)"]
|
||||
gssauth = ["gssapi", "sspilib"]
|
||||
test = ["distro (>=1.9.0,<1.10.0)", "flake8 (>=6.1,<7.0)", "flake8-pyi (>=24.1.0,<24.2.0)", "gssapi", "k5test", "mypy (>=1.8.0,<1.9.0)", "sspilib", "uvloop (>=0.15.3)"]
|
||||
|
||||
[[package]]
|
||||
name = "bcrypt"
|
||||
version = "4.0.1"
|
||||
description = "Modern password hashing for your software and your servers"
|
||||
optional = false
|
||||
python-versions = ">=3.6"
|
||||
groups = ["main"]
|
||||
files = [
|
||||
{file = "bcrypt-4.0.1-cp36-abi3-macosx_10_10_universal2.whl", hash = "sha256:b1023030aec778185a6c16cf70f359cbb6e0c289fd564a7cfa29e727a1c38f8f"},
|
||||
{file = "bcrypt-4.0.1-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:08d2947c490093a11416df18043c27abe3921558d2c03e2076ccb28a116cb6d0"},
|
||||
{file = "bcrypt-4.0.1-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0eaa47d4661c326bfc9d08d16debbc4edf78778e6aaba29c1bc7ce67214d4410"},
|
||||
{file = "bcrypt-4.0.1-cp36-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ae88eca3024bb34bb3430f964beab71226e761f51b912de5133470b649d82344"},
|
||||
{file = "bcrypt-4.0.1-cp36-abi3-manylinux_2_24_x86_64.whl", hash = "sha256:a522427293d77e1c29e303fc282e2d71864579527a04ddcfda6d4f8396c6c36a"},
|
||||
{file = "bcrypt-4.0.1-cp36-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:fbdaec13c5105f0c4e5c52614d04f0bca5f5af007910daa8b6b12095edaa67b3"},
|
||||
{file = "bcrypt-4.0.1-cp36-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:ca3204d00d3cb2dfed07f2d74a25f12fc12f73e606fcaa6975d1f7ae69cacbb2"},
|
||||
{file = "bcrypt-4.0.1-cp36-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:089098effa1bc35dc055366740a067a2fc76987e8ec75349eb9484061c54f535"},
|
||||
{file = "bcrypt-4.0.1-cp36-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:e9a51bbfe7e9802b5f3508687758b564069ba937748ad7b9e890086290d2f79e"},
|
||||
{file = "bcrypt-4.0.1-cp36-abi3-win32.whl", hash = "sha256:2caffdae059e06ac23fce178d31b4a702f2a3264c20bfb5ff541b338194d8fab"},
|
||||
{file = "bcrypt-4.0.1-cp36-abi3-win_amd64.whl", hash = "sha256:8a68f4341daf7522fe8d73874de8906f3a339048ba406be6ddc1b3ccb16fc0d9"},
|
||||
{file = "bcrypt-4.0.1-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bf4fa8b2ca74381bb5442c089350f09a3f17797829d958fad058d6e44d9eb83c"},
|
||||
{file = "bcrypt-4.0.1-pp37-pypy37_pp73-manylinux_2_24_x86_64.whl", hash = "sha256:67a97e1c405b24f19d08890e7ae0c4f7ce1e56a712a016746c8b2d7732d65d4b"},
|
||||
{file = "bcrypt-4.0.1-pp37-pypy37_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:b3b85202d95dd568efcb35b53936c5e3b3600c7cdcc6115ba461df3a8e89f38d"},
|
||||
{file = "bcrypt-4.0.1-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cbb03eec97496166b704ed663a53680ab57c5084b2fc98ef23291987b525cb7d"},
|
||||
{file = "bcrypt-4.0.1-pp38-pypy38_pp73-manylinux_2_24_x86_64.whl", hash = "sha256:5ad4d32a28b80c5fa6671ccfb43676e8c1cc232887759d1cd7b6f56ea4355215"},
|
||||
{file = "bcrypt-4.0.1-pp38-pypy38_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:b57adba8a1444faf784394de3436233728a1ecaeb6e07e8c22c8848f179b893c"},
|
||||
{file = "bcrypt-4.0.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:705b2cea8a9ed3d55b4491887ceadb0106acf7c6387699fca771af56b1cdeeda"},
|
||||
{file = "bcrypt-4.0.1-pp39-pypy39_pp73-manylinux_2_24_x86_64.whl", hash = "sha256:2b3ac11cf45161628f1f3733263e63194f22664bf4d0c0f3ab34099c02134665"},
|
||||
{file = "bcrypt-4.0.1-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:3100851841186c25f127731b9fa11909ab7b1df6fc4b9f8353f4f1fd952fbf71"},
|
||||
{file = "bcrypt-4.0.1.tar.gz", hash = "sha256:27d375903ac8261cfe4047f6709d16f7d18d39b1ec92aaf72af989552a650ebd"},
|
||||
]
|
||||
|
||||
[package.extras]
|
||||
tests = ["pytest (>=3.2.1,!=3.3.0)"]
|
||||
typecheck = ["mypy"]
|
||||
|
||||
[[package]]
|
||||
name = "certifi"
|
||||
version = "2024.12.14"
|
||||
@ -709,24 +674,6 @@ files = [
|
||||
{file = "nodeenv-1.9.1.tar.gz", hash = "sha256:6ec12890a2dab7946721edbfbcd91f3319c6ccc9aec47be7c7e6b7011ee6645f"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "passlib"
|
||||
version = "1.7.4"
|
||||
description = "comprehensive password hashing framework supporting over 30 schemes"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
groups = ["main"]
|
||||
files = [
|
||||
{file = "passlib-1.7.4-py2.py3-none-any.whl", hash = "sha256:aa6bca462b8d8bda89c70b382f0c298a20b5560af6cbfa2dce410c0a2fb669f1"},
|
||||
{file = "passlib-1.7.4.tar.gz", hash = "sha256:defd50f72b65c5402ab2c573830a6978e5f202ad0d984793c8dde2c4152ebe04"},
|
||||
]
|
||||
|
||||
[package.extras]
|
||||
argon2 = ["argon2-cffi (>=18.2.0)"]
|
||||
bcrypt = ["bcrypt (>=3.1.0)"]
|
||||
build-docs = ["cloud-sptheme (>=1.10.1)", "sphinx (>=1.6)", "sphinxcontrib-fulltoc (>=1.2.0)"]
|
||||
totp = ["cryptography"]
|
||||
|
||||
[[package]]
|
||||
name = "platformdirs"
|
||||
version = "4.3.6"
|
||||
@ -777,7 +724,6 @@ files = [
|
||||
|
||||
[package.dependencies]
|
||||
annotated-types = ">=0.6.0"
|
||||
email-validator = {version = ">=2.0.0", optional = true, markers = "extra == \"email\""}
|
||||
pydantic-core = "2.27.2"
|
||||
typing-extensions = ">=4.12.2"
|
||||
|
||||
@ -1480,4 +1426,4 @@ files = [
|
||||
[metadata]
|
||||
lock-version = "2.1"
|
||||
python-versions = ">=3.12"
|
||||
content-hash = "3d4c2b89136e414e183f596de6faca17a5c9d78e0b2788ad4cb4fd598e486faa"
|
||||
content-hash = "b171a7f89cc3ee2207778b1e189fbb1821fccda26de00d0181156d0e183a5b75"
|
||||
|
@ -16,9 +16,6 @@ dependencies = [
|
||||
"pydantic-settings (>=2.7.1,<3.0.0)",
|
||||
"alembic (>=1.14.0,<2.0.0)",
|
||||
"ruff (>=0.9.0,<0.10.0)",
|
||||
"pydantic[email] (>=2.10.5,<3.0.0)",
|
||||
"passlib (>=1.7.4,<2.0.0)",
|
||||
"bcrypt (==4.0.1)",
|
||||
]
|
||||
|
||||
[build-system]
|
||||
|
Loading…
x
Reference in New Issue
Block a user