base logic
This commit is contained in:
39
poetry.lock
generated
39
poetry.lock
generated
@@ -101,6 +101,43 @@ files = [
|
|||||||
{file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"},
|
{file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"},
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "dnspython"
|
||||||
|
version = "2.7.0"
|
||||||
|
description = "DNS toolkit"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.9"
|
||||||
|
groups = ["main"]
|
||||||
|
files = [
|
||||||
|
{file = "dnspython-2.7.0-py3-none-any.whl", hash = "sha256:b4c34b7d10b51bcc3a5071e7b8dee77939f1e878477eeecc965e9835f63c6c86"},
|
||||||
|
{file = "dnspython-2.7.0.tar.gz", hash = "sha256:ce9c432eda0dc91cf618a5cedf1a4e142651196bbcd2c80e89ed5a907e5cfaf1"},
|
||||||
|
]
|
||||||
|
|
||||||
|
[package.extras]
|
||||||
|
dev = ["black (>=23.1.0)", "coverage (>=7.0)", "flake8 (>=7)", "hypercorn (>=0.16.0)", "mypy (>=1.8)", "pylint (>=3)", "pytest (>=7.4)", "pytest-cov (>=4.1.0)", "quart-trio (>=0.11.0)", "sphinx (>=7.2.0)", "sphinx-rtd-theme (>=2.0.0)", "twine (>=4.0.0)", "wheel (>=0.42.0)"]
|
||||||
|
dnssec = ["cryptography (>=43)"]
|
||||||
|
doh = ["h2 (>=4.1.0)", "httpcore (>=1.0.0)", "httpx (>=0.26.0)"]
|
||||||
|
doq = ["aioquic (>=1.0.0)"]
|
||||||
|
idna = ["idna (>=3.7)"]
|
||||||
|
trio = ["trio (>=0.23)"]
|
||||||
|
wmi = ["wmi (>=1.5.1)"]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "email-validator"
|
||||||
|
version = "2.2.0"
|
||||||
|
description = "A robust email address syntax and deliverability validation library."
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.8"
|
||||||
|
groups = ["main"]
|
||||||
|
files = [
|
||||||
|
{file = "email_validator-2.2.0-py3-none-any.whl", hash = "sha256:561977c2d73ce3611850a06fa56b414621e0c8faa9d66f2611407d87465da631"},
|
||||||
|
{file = "email_validator-2.2.0.tar.gz", hash = "sha256:cb690f344c617a714f22e66ae771445a1ceb46821152df8e165c5f9a364582b7"},
|
||||||
|
]
|
||||||
|
|
||||||
|
[package.dependencies]
|
||||||
|
dnspython = ">=2.0.0"
|
||||||
|
idna = ">=2.0.0"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "fastapi"
|
name = "fastapi"
|
||||||
version = "0.115.14"
|
version = "0.115.14"
|
||||||
@@ -721,4 +758,4 @@ standard = ["colorama (>=0.4) ; sys_platform == \"win32\"", "httptools (>=0.6.3)
|
|||||||
[metadata]
|
[metadata]
|
||||||
lock-version = "2.1"
|
lock-version = "2.1"
|
||||||
python-versions = ">=3.12"
|
python-versions = ">=3.12"
|
||||||
content-hash = "e9bc371ef3ba3a59fce2dbc0416fbb5be92bbccf98f36bd661ed55318975f3a1"
|
content-hash = "78991183ad2dfe443ab27c24820d79f492bb74ef261393364004ba457a42ba65"
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ dependencies = [
|
|||||||
"fastapi (>=0.115.14,<0.116.0)",
|
"fastapi (>=0.115.14,<0.116.0)",
|
||||||
"pyjwt (>=2.10.1,<3.0.0)",
|
"pyjwt (>=2.10.1,<3.0.0)",
|
||||||
"passlib (>=1.7.4,<2.0.0)",
|
"passlib (>=1.7.4,<2.0.0)",
|
||||||
|
"email-validator (>=2.2.0,<3.0.0)",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
from fastapi import APIRouter
|
from fastapi import APIRouter
|
||||||
from src.api.users import router as users_router
|
|
||||||
from src.api.tasks import router as tasks_router
|
|
||||||
|
|
||||||
router = APIRouter()
|
from src.api.v1 import router as v1_router
|
||||||
|
from src.core.settings import settings
|
||||||
|
|
||||||
|
router = APIRouter(prefix=settings.api.prefix)
|
||||||
|
|
||||||
|
router.include_router(router=v1_router)
|
||||||
|
|
||||||
router.include_router(router=users_router)
|
|
||||||
router.include_router(router=tasks_router)
|
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ from typing import Annotated, AsyncGenerator
|
|||||||
from fastapi import Depends
|
from fastapi import Depends
|
||||||
from sqlalchemy.ext.asyncio import AsyncSession
|
from sqlalchemy.ext.asyncio import AsyncSession
|
||||||
|
|
||||||
from src.db.database import async_session_maker
|
from src.core.database import async_session_maker
|
||||||
|
|
||||||
|
|
||||||
async def get_db() -> AsyncGenerator[AsyncSession, None]:
|
async def get_db() -> AsyncGenerator[AsyncSession, None]:
|
||||||
@@ -11,6 +11,6 @@ async def get_db() -> AsyncGenerator[AsyncSession, None]:
|
|||||||
yield db
|
yield db
|
||||||
|
|
||||||
|
|
||||||
DBDep = Annotated[AsyncSession, Depends(get_db)]
|
sessionDep = Annotated[AsyncSession, Depends(get_db)]
|
||||||
|
|
||||||
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
from fastapi import APIRouter
|
|
||||||
|
|
||||||
router = APIRouter(prefix="/users", tags=["Users"])
|
|
||||||
11
src/api/v1/__init__.py
Normal file
11
src/api/v1/__init__.py
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
from fastapi import APIRouter
|
||||||
|
from src.api.v1.auth import router as auth_router
|
||||||
|
from src.api.v1.users import router as users_router
|
||||||
|
from src.api.v1.tasks import router as tasks_router
|
||||||
|
from src.core.settings import settings
|
||||||
|
|
||||||
|
router = APIRouter(prefix=settings.api.v1.prefix)
|
||||||
|
|
||||||
|
router.include_router(router=auth_router)
|
||||||
|
router.include_router(router=users_router)
|
||||||
|
router.include_router(router=tasks_router)
|
||||||
13
src/api/v1/auth.py
Normal file
13
src/api/v1/auth.py
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
from fastapi import APIRouter
|
||||||
|
|
||||||
|
from src.api.dependacies.db_dep import sessionDep
|
||||||
|
from src.schemas.users import UserCreate
|
||||||
|
from src.core.settings import settings
|
||||||
|
from src.services.auth import AuthService
|
||||||
|
|
||||||
|
router = APIRouter(prefix=settings.api.v1.auth, tags=['Auth'])
|
||||||
|
|
||||||
|
|
||||||
|
@router.post(path='/signup')
|
||||||
|
async def registration(session: sessionDep, credential: UserCreate):
|
||||||
|
await AuthService(session).registration(credential)
|
||||||
5
src/api/v1/users.py
Normal file
5
src/api/v1/users.py
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
from fastapi import APIRouter
|
||||||
|
|
||||||
|
from src.core.settings import settings
|
||||||
|
|
||||||
|
router = APIRouter(prefix=settings.api.v1.users, tags=["Users"])
|
||||||
@@ -4,7 +4,7 @@ from sqlalchemy import TIMESTAMP, func
|
|||||||
from sqlalchemy.ext.asyncio import create_async_engine, async_sessionmaker
|
from sqlalchemy.ext.asyncio import create_async_engine, async_sessionmaker
|
||||||
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column
|
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column
|
||||||
|
|
||||||
from src.settings import settings
|
from src.core.settings import settings
|
||||||
|
|
||||||
engine = create_async_engine(settings.db.url, echo=True)
|
engine = create_async_engine(settings.db.url, echo=True)
|
||||||
|
|
||||||
@@ -7,6 +7,17 @@ BASE_DIR = Path(__file__).parent
|
|||||||
DB_PATH = BASE_DIR / "db/taskncoffee.db"
|
DB_PATH = BASE_DIR / "db/taskncoffee.db"
|
||||||
|
|
||||||
|
|
||||||
|
class ApiV1Prefix(BaseModel):
|
||||||
|
prefix: str = "/v1"
|
||||||
|
auth: str = "/auth"
|
||||||
|
users: str = "/users"
|
||||||
|
|
||||||
|
|
||||||
|
class ApiPrefix(BaseModel):
|
||||||
|
prefix: str = "/api"
|
||||||
|
v1: ApiV1Prefix = ApiV1Prefix()
|
||||||
|
|
||||||
|
|
||||||
class DbSettings(BaseModel):
|
class DbSettings(BaseModel):
|
||||||
url: str = f"sqlite+aiosqlite:///{DB_PATH}"
|
url: str = f"sqlite+aiosqlite:///{DB_PATH}"
|
||||||
|
|
||||||
@@ -22,7 +33,7 @@ class AccessToken(BaseSettings):
|
|||||||
|
|
||||||
|
|
||||||
class Settings(BaseSettings):
|
class Settings(BaseSettings):
|
||||||
model_config = SettingsConfigDict(env_file='.env', env_file_encoding='utf-8')
|
api: ApiPrefix = ApiPrefix()
|
||||||
db: DbSettings = DbSettings()
|
db: DbSettings = DbSettings()
|
||||||
access_token: AccessToken = AccessToken()
|
access_token: AccessToken = AccessToken()
|
||||||
|
|
||||||
@@ -11,4 +11,4 @@ app = FastAPI()
|
|||||||
app.include_router(router=router)
|
app.include_router(router=router)
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
uvicorn.run("src.main:app", port=5000, log_level="info", reload=True)
|
uvicorn.run("src.main:app", port=8000, log_level="info", reload=True)
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ from typing import Optional, TYPE_CHECKING
|
|||||||
from sqlalchemy import ForeignKey, Text, Date, Enum, String
|
from sqlalchemy import ForeignKey, Text, Date, Enum, String
|
||||||
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
||||||
|
|
||||||
from src.db.database import Base
|
from src.core.database import Base
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from src.models.users import UsersORM
|
from src.models.users import UsersORM
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
from typing import Optional, TYPE_CHECKING
|
from typing import Optional, TYPE_CHECKING
|
||||||
|
|
||||||
from sqlalchemy import String, BigInteger, Integer, Boolean, VARCHAR
|
from sqlalchemy import String, BigInteger, Integer, Boolean
|
||||||
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
||||||
|
|
||||||
from src.db.database import Base
|
from src.core.database import Base
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from src.models.tasks import TasksORM
|
from src.models.tasks import TasksORM
|
||||||
|
|||||||
0
src/repository/__init__.py
Normal file
0
src/repository/__init__.py
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
from pydantic import BaseModel, EmailStr
|
||||||
|
|
||||||
|
|
||||||
|
class UserRead(BaseModel):
|
||||||
|
username: str
|
||||||
|
email: EmailStr | None
|
||||||
|
is_active: bool
|
||||||
|
is_superuser: bool
|
||||||
|
|
||||||
|
|
||||||
|
class UserCreate(BaseModel):
|
||||||
|
username: str
|
||||||
|
email: EmailStr | None = None
|
||||||
|
password: str
|
||||||
|
|
||||||
|
|||||||
0
src/services/__init__.py
Normal file
0
src/services/__init__.py
Normal file
11
src/services/auth.py
Normal file
11
src/services/auth.py
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
from src.schemas.users import UserCreate
|
||||||
|
from src.services.base import BaseService
|
||||||
|
|
||||||
|
|
||||||
|
class AuthService(BaseService):
|
||||||
|
|
||||||
|
|
||||||
|
async def registration(self, data: UserCreate):
|
||||||
|
...
|
||||||
|
|
||||||
|
|
||||||
9
src/services/base.py
Normal file
9
src/services/base.py
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
from src.utils.db_manager import DBManager
|
||||||
|
|
||||||
|
|
||||||
|
class BaseService:
|
||||||
|
session: DBManager | None
|
||||||
|
|
||||||
|
def __init__(self, session: DBManager):
|
||||||
|
self.session = session
|
||||||
|
|
||||||
9
src/utils/auth_manager.py
Normal file
9
src/utils/auth_manager.py
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
from passlib.context import CryptContext
|
||||||
|
|
||||||
|
|
||||||
|
class AuthManger:
|
||||||
|
pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def verify_password(cls, plain_password, hashed_password):
|
||||||
|
return cls.pwd_context.verify(plain_password, hashed_password)
|
||||||
12
src/utils/db_manager.py
Normal file
12
src/utils/db_manager.py
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
|
||||||
|
|
||||||
|
class DBManager:
|
||||||
|
def __init__(self, session_factory):
|
||||||
|
self.session_factory = session_factory
|
||||||
|
|
||||||
|
async def __aenter__(self):
|
||||||
|
self.session = self.session_factory()
|
||||||
|
|
||||||
|
async def __aexit__(self, exc_type, exc_val, exc_tb):
|
||||||
|
await self.session.rollback()
|
||||||
|
await self.session.close()
|
||||||
Reference in New Issue
Block a user