add User return schema

This commit is contained in:
IluaAir
2025-07-13 11:41:58 +03:00
parent d27aafb4f6
commit f3030593da
12 changed files with 102 additions and 64 deletions

View File

@@ -6,4 +6,3 @@ from src.core.settings import settings
router = APIRouter(prefix=settings.api.prefix)
router.include_router(router=v1_router)

View File

@@ -5,9 +5,10 @@ from src.schemas.users import UserRequest
from src.core.settings import settings
from src.services.auth import AuthService
router = APIRouter(prefix=settings.api.v1.auth, tags=['Auth'])
router = APIRouter(prefix=settings.api.v1.auth, tags=["Auth"])
@router.post(path='/signup')
@router.post(path="/signup")
async def registration(session: sessionDep, credential: UserRequest):
await AuthService(session).registration(credential)
auth = await AuthService(session).registration(credential)
return auth

View File

@@ -6,11 +6,8 @@ from src.repository.users import UsersRepo
class IUnitOfWork(Protocol):
user: UsersRepo
async def __aenter__(self) -> "IUnitOfWork":
...
async def __aenter__(self) -> "IUnitOfWork": ...
async def __aexit__(self, exc_type, exc_val, exc_tb) -> None:
...
async def __aexit__(self, exc_type, exc_val, exc_tb) -> None: ...
async def commit(self) -> None:
...
async def commit(self) -> None: ...

View File

@@ -24,10 +24,9 @@ class DbSettings(BaseModel):
class AccessToken(BaseSettings):
model_config = SettingsConfigDict(env_file='.env',
env_file_encoding='utf-8',
env_prefix="ACCESS_TOKEN_"
)
model_config = SettingsConfigDict(
env_file=".env", env_file_encoding="utf-8", env_prefix="ACCESS_TOKEN_"
)
expire_minutes: int = 15
secret_key: str
algorithm: str = "HS256"

View File

@@ -6,7 +6,7 @@ from sqlalchemy import pool
from alembic import context
from src.db.database import Base
from src.models import * # noqa
from src.models import * # noqa
# this is the Alembic Config object, which provides
# access to the values within the .ini file in use.
@@ -68,9 +68,7 @@ def run_migrations_online() -> None:
)
with connectable.connect() as connection:
context.configure(
connection=connection, target_metadata=target_metadata
)
context.configure(connection=connection, target_metadata=target_metadata)
with context.begin_transaction():
context.run_migrations()

View File

@@ -5,6 +5,7 @@ Revises:
Create Date: 2025-07-06 00:02:09.254907
"""
from typing import Sequence, Union
from alembic import op
@@ -12,7 +13,7 @@ import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision: str = 'a2fdd0ec4a96'
revision: str = "a2fdd0ec4a96"
down_revision: Union[str, None] = None
branch_labels: Union[str, Sequence[str], None] = None
depends_on: Union[str, Sequence[str], None] = None
@@ -21,34 +22,61 @@ depends_on: Union[str, Sequence[str], None] = None
def upgrade() -> None:
"""Upgrade schema."""
# ### commands auto generated by Alembic - please adjust! ###
op.create_table('users',
sa.Column('id', sa.Integer(), nullable=False),
sa.Column('username', sa.String(length=30), nullable=False),
sa.Column('hashed_password', sa.String(length=255), nullable=False),
sa.Column('email', sa.String(length=255), nullable=True),
sa.Column('telegram_id', sa.BigInteger(), nullable=True),
sa.Column('avatar_path', sa.String(length=255), nullable=True),
sa.Column('is_active', sa.Boolean(), nullable=False),
sa.Column('is_superuser', sa.Boolean(), nullable=False),
sa.Column('created_at', sa.TIMESTAMP(timezone=True), server_default=sa.text('(CURRENT_TIMESTAMP)'), nullable=False),
sa.PrimaryKeyConstraint('id'),
sa.UniqueConstraint('email')
op.create_table(
"users",
sa.Column("id", sa.Integer(), nullable=False),
sa.Column("username", sa.String(length=30), nullable=False),
sa.Column("hashed_password", sa.String(length=255), nullable=False),
sa.Column("email", sa.String(length=255), nullable=True),
sa.Column("telegram_id", sa.BigInteger(), nullable=True),
sa.Column("avatar_path", sa.String(length=255), nullable=True),
sa.Column("is_active", sa.Boolean(), nullable=False),
sa.Column("is_superuser", sa.Boolean(), nullable=False),
sa.Column(
"created_at",
sa.TIMESTAMP(timezone=True),
server_default=sa.text("(CURRENT_TIMESTAMP)"),
nullable=False,
),
sa.PrimaryKeyConstraint("id"),
sa.UniqueConstraint("email"),
)
op.create_index(op.f('ix_users_username'), 'users', ['username'], unique=True)
op.create_table('tasks',
sa.Column('id', sa.Integer(), autoincrement=True, nullable=False),
sa.Column('user_id', sa.Integer(), nullable=False),
sa.Column('title', sa.String(length=100), nullable=False),
sa.Column('description', sa.Text(), nullable=True),
sa.Column('due_date', sa.Date(), nullable=True),
sa.Column("status", sa.Enum("open", "closed", "in_progress", "todo", name="status_enum"), nullable=False),
sa.CheckConstraint("status IN ('open', 'closed', 'in_progress', 'todo')", name="ck_status_enum"),
sa.Column("priority", sa.Enum("low", "medium", "high", "critical", name="priority_enum"), nullable=False),
sa.CheckConstraint("priority in ('low', 'medium', 'high', 'critical')", name="ck_priority_enum"),
sa.Column('time_spent', sa.Integer(), nullable=False),
sa.Column('created_at', sa.TIMESTAMP(timezone=True), server_default=sa.text('(CURRENT_TIMESTAMP)'), nullable=False),
sa.ForeignKeyConstraint(['user_id'], ['users.id'], ),
sa.PrimaryKeyConstraint('id')
op.create_index(op.f("ix_users_username"), "users", ["username"], unique=True)
op.create_table(
"tasks",
sa.Column("id", sa.Integer(), autoincrement=True, nullable=False),
sa.Column("user_id", sa.Integer(), nullable=False),
sa.Column("title", sa.String(length=100), nullable=False),
sa.Column("description", sa.Text(), nullable=True),
sa.Column("due_date", sa.Date(), nullable=True),
sa.Column(
"status",
sa.Enum("open", "closed", "in_progress", "todo", name="status_enum"),
nullable=False,
),
sa.CheckConstraint(
"status IN ('open', 'closed', 'in_progress', 'todo')", name="ck_status_enum"
),
sa.Column(
"priority",
sa.Enum("low", "medium", "high", "critical", name="priority_enum"),
nullable=False,
),
sa.CheckConstraint(
"priority in ('low', 'medium', 'high', 'critical')", name="ck_priority_enum"
),
sa.Column("time_spent", sa.Integer(), nullable=False),
sa.Column(
"created_at",
sa.TIMESTAMP(timezone=True),
server_default=sa.text("(CURRENT_TIMESTAMP)"),
nullable=False,
),
sa.ForeignKeyConstraint(
["user_id"],
["users.id"],
),
sa.PrimaryKeyConstraint("id"),
)
# ### end Alembic commands ###
@@ -56,7 +84,7 @@ def upgrade() -> None:
def downgrade() -> None:
"""Downgrade schema."""
# ### commands auto generated by Alembic - please adjust! ###
op.drop_table('tasks')
op.drop_index(op.f('ix_users_username'), table_name='users')
op.drop_table('users')
op.drop_table("tasks")
op.drop_index(op.f("ix_users_username"), table_name="users")
op.drop_table("users")
# ### end Alembic commands ###

View File

@@ -14,7 +14,6 @@ priority_enum = Enum("low", "medium", "high", "critical", name="priority_enum")
class TasksORM(Base):
__tablename__ = "tasks"
id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True)
user_id: Mapped[int] = mapped_column(ForeignKey("users.id"))

View File

@@ -16,7 +16,9 @@ class UsersORM(Base):
String(30), nullable=False, unique=True, index=True
)
hashed_password: Mapped[str] = mapped_column(String(255), nullable=False)
email: Mapped[Optional[str]] = mapped_column(String(255), unique=True, nullable=True)
email: Mapped[Optional[str]] = mapped_column(
String(255), unique=True, nullable=True
)
telegram_id: Mapped[Optional[int]] = mapped_column(BigInteger, nullable=True)
avatar_path: Mapped[Optional[str]] = mapped_column(String(255), nullable=True)
is_active: Mapped[bool] = mapped_column(Boolean, nullable=False, default=True)

View File

@@ -11,7 +11,7 @@ class BaseRepo:
self.session = session
async def create_one(self, data: BaseModel):
print(self.session)
statement = insert(self.model).values(data.model_dump()).returning(self.model)
result = await self.session.execute(statement)
return result
obj = result.scalar_one()
return obj

View File

@@ -6,11 +6,12 @@ from src.schemas.validators import ensure_password
class User(BaseModel):
id: int
email: EmailStr | None
username: str
is_active: bool
is_superuser: bool
model_config = ConfigDict(from_attributes=True)
model_config = ConfigDict(from_attributes=True, extra="ignore")
class UserWithHashedPass(User):
@@ -21,3 +22,11 @@ class UserRequest(BaseModel):
username: str
email: EmailStr | None = None
password: Annotated[str, BeforeValidator(ensure_password)]
class UserAdd(BaseModel):
email: EmailStr | None
username: str
is_active: bool
is_superuser: bool
hashed_password: str

View File

@@ -1,19 +1,19 @@
from src.schemas.users import UserWithHashedPass, UserRequest
from src.schemas.users import UserRequest, User, UserAdd
from src.services.base import BaseService
from src.utils.auth_manager import AuthManger
class AuthService(BaseService):
async def registration(self, cred: UserRequest):
async def registration(self, cred: UserRequest) -> User:
hashed_pass = AuthManger.get_password_hash(cred.password)
user_to_insert = UserWithHashedPass(
user_to_insert = UserAdd(
username=cred.username,
email=cred.email,
hashed_password=hashed_pass,
is_active=True,
is_superuser=False
is_superuser=False,
)
result = await self.session.user.create_one(user_to_insert)
print(result)
await self.session.commit()
return result
return User.model_validate(result)

View File

@@ -23,7 +23,13 @@ class AuthManger:
if expires_delta:
expire = datetime.now(timezone.utc) + expires_delta
else:
expire = datetime.now(timezone.utc) + timedelta(minutes=settings.access_token.expire_minutes)
expire = datetime.now(timezone.utc) + timedelta(
minutes=settings.access_token.expire_minutes
)
to_encode.update({"exp": expire})
encoded_jwt = jwt.encode(to_encode, settings.access_token.secret_key, algorithm=settings.access_token.algorithm)
encoded_jwt = jwt.encode(
to_encode,
settings.access_token.secret_key,
algorithm=settings.access_token.algorithm,
)
return encoded_jwt