From 4fd66e01063103607b29c3119d43062a55c8f7aa Mon Sep 17 00:00:00 2001 From: "MH.Dmitrii" Date: Fri, 17 Jul 2026 20:03:41 +0300 Subject: [PATCH] 0.1.3 --- src/migrations/env.py | 4 +- .../{83b4c2ae88d3_.py => 5e60c8fbc553_.py} | 47 ++++++++++++++-- src/migrations/versions/9b30685906fb_.py | 54 ------------------- src/models/database_models/__init__.py | 2 + src/models/database_models/files.py | 14 +++++ src/models/pydantic_models/model.py | 13 +++-- src/service/__init__.py | 1 + 7 files changed, 71 insertions(+), 64 deletions(-) rename src/migrations/versions/{83b4c2ae88d3_.py => 5e60c8fbc553_.py} (67%) delete mode 100644 src/migrations/versions/9b30685906fb_.py create mode 100644 src/models/database_models/__init__.py create mode 100644 src/models/database_models/files.py create mode 100644 src/service/__init__.py diff --git a/src/migrations/env.py b/src/migrations/env.py index 5a13e40..58a89af 100644 --- a/src/migrations/env.py +++ b/src/migrations/env.py @@ -1,8 +1,8 @@ from logging.config import fileConfig -from src.models.database_models.model import engine, Model -import src.models.database_models.model as models +from src.models.database_models import Model +from src.models.database_models.model import engine from sqlalchemy import engine_from_config from sqlalchemy import pool diff --git a/src/migrations/versions/83b4c2ae88d3_.py b/src/migrations/versions/5e60c8fbc553_.py similarity index 67% rename from src/migrations/versions/83b4c2ae88d3_.py rename to src/migrations/versions/5e60c8fbc553_.py index 1e2e9e2..e26773e 100644 --- a/src/migrations/versions/83b4c2ae88d3_.py +++ b/src/migrations/versions/5e60c8fbc553_.py @@ -1,8 +1,8 @@ """empty message -Revision ID: 83b4c2ae88d3 +Revision ID: 5e60c8fbc553 Revises: -Create Date: 2026-07-17 15:00:15.263996 +Create Date: 2026-07-17 20:02:01.237457 """ from typing import Sequence, Union @@ -11,9 +11,8 @@ from alembic import op import sqlalchemy as sa from sqlalchemy.sql import text - # revision identifiers, used by Alembic. -revision: str = '83b4c2ae88d3' +revision: str = '5e60c8fbc553' down_revision: Union[str, Sequence[str], None] = None branch_labels: Union[str, Sequence[str], None] = None depends_on: Union[str, Sequence[str], None] = None @@ -41,6 +40,16 @@ def upgrade() -> None: batch_op.create_index(batch_op.f('ix_permissions_id'), ['id'], unique=False) op.execute(text("INSERT INTO permissions (permission) VALUES ('admin');")) + op.create_table('reports', + sa.Column('id', sa.Integer(), nullable=False), + sa.Column('filename', sa.String(length=255), nullable=False), + sa.Column('created_at', sa.TIMESTAMP(), server_default=sa.text('(CURRENT_TIMESTAMP)'), nullable=False), + sa.PrimaryKeyConstraint('id', name=op.f('pk_reports')) + ) + with op.batch_alter_table('reports', schema=None) as batch_op: + batch_op.create_index(batch_op.f('ix_reports_filename'), ['filename'], unique=False) + batch_op.create_index(batch_op.f('ix_reports_id'), ['id'], unique=False) + op.create_table('users', sa.Column('id', sa.Uuid(), nullable=False), sa.Column('first_name', sa.String(length=64), nullable=False), @@ -64,6 +73,25 @@ def upgrade() -> None: sa.ForeignKeyConstraint(['permission_id'], ['permissions.id'], name=op.f('fk_group_permission_permission_id_permissions')), sa.PrimaryKeyConstraint('group_id', 'permission_id', name=op.f('pk_group_permission')) ) + op.create_table('refresh_tokens', + sa.Column('id', sa.Integer(), nullable=False), + sa.Column('user_id', sa.Uuid(), nullable=False), + sa.Column('token_hash', sa.String(length=255), nullable=False), + sa.Column('device_info', sa.String(length=255), nullable=False), + sa.Column('ip_address', sa.String(length=45), nullable=False), + sa.Column('is_revoked', sa.Boolean(), nullable=False), + sa.Column('expires_at', sa.TIMESTAMP(), nullable=False), + sa.Column('created_at', sa.TIMESTAMP(), server_default=sa.text('(CURRENT_TIMESTAMP)'), nullable=False), + sa.Column('replaced_by', sa.Integer(), nullable=True), + sa.ForeignKeyConstraint(['replaced_by'], ['refresh_tokens.id'], name=op.f('fk_refresh_tokens_replaced_by_refresh_tokens')), + sa.ForeignKeyConstraint(['user_id'], ['users.id'], name=op.f('fk_refresh_tokens_user_id_users'), ondelete='CASCADE'), + sa.PrimaryKeyConstraint('id', name=op.f('pk_refresh_tokens')), + sa.UniqueConstraint('token_hash', name=op.f('uq_refresh_tokens_token_hash')) + ) + with op.batch_alter_table('refresh_tokens', schema=None) as batch_op: + batch_op.create_index(batch_op.f('ix_refresh_tokens_id'), ['id'], unique=False) + batch_op.create_index(batch_op.f('ix_refresh_tokens_user_id'), ['user_id'], unique=False) + op.create_table('user_direct_permissions', sa.Column('user_id', sa.Uuid(), nullable=False), sa.Column('permission_id', sa.Integer(), nullable=False), @@ -78,7 +106,6 @@ def upgrade() -> None: sa.ForeignKeyConstraint(['user_id'], ['users.id'], name=op.f('fk_user_group_user_id_users')), sa.PrimaryKeyConstraint('user_id', 'permission_group_id', name=op.f('pk_user_group')) ) - # ### end Alembic commands ### @@ -87,6 +114,11 @@ def downgrade() -> None: # ### commands auto generated by Alembic - please adjust! ### op.drop_table('user_group') op.drop_table('user_direct_permissions') + with op.batch_alter_table('refresh_tokens', schema=None) as batch_op: + batch_op.drop_index(batch_op.f('ix_refresh_tokens_user_id')) + batch_op.drop_index(batch_op.f('ix_refresh_tokens_id')) + + op.drop_table('refresh_tokens') op.drop_table('group_permission') with op.batch_alter_table('users', schema=None) as batch_op: batch_op.drop_index(batch_op.f('ix_users_middle_name')) @@ -95,6 +127,11 @@ def downgrade() -> None: batch_op.drop_index(batch_op.f('ix_users_email')) op.drop_table('users') + with op.batch_alter_table('reports', schema=None) as batch_op: + batch_op.drop_index(batch_op.f('ix_reports_id')) + batch_op.drop_index(batch_op.f('ix_reports_filename')) + + op.drop_table('reports') with op.batch_alter_table('permissions', schema=None) as batch_op: batch_op.drop_index(batch_op.f('ix_permissions_id')) diff --git a/src/migrations/versions/9b30685906fb_.py b/src/migrations/versions/9b30685906fb_.py deleted file mode 100644 index 114363d..0000000 --- a/src/migrations/versions/9b30685906fb_.py +++ /dev/null @@ -1,54 +0,0 @@ -"""empty message - -Revision ID: 9b30685906fb -Revises: 83b4c2ae88d3 -Create Date: 2026-07-17 17:40:07.269967 - -""" -from typing import Sequence, Union - -from alembic import op -import sqlalchemy as sa - - -# revision identifiers, used by Alembic. -revision: str = '9b30685906fb' -down_revision: Union[str, Sequence[str], None] = '83b4c2ae88d3' -branch_labels: Union[str, Sequence[str], None] = None -depends_on: Union[str, Sequence[str], None] = None - - -def upgrade() -> None: - """Upgrade schema.""" - # ### commands auto generated by Alembic - please adjust! ### - op.create_table('refresh_tokens', - sa.Column('id', sa.Integer(), nullable=False), - sa.Column('user_id', sa.Uuid(), nullable=False), - sa.Column('token_hash', sa.String(length=255), nullable=False), - sa.Column('device_info', sa.String(length=255), nullable=False), - sa.Column('ip_address', sa.String(length=45), nullable=False), - sa.Column('is_revoked', sa.Boolean(), nullable=False), - sa.Column('expires_at', sa.TIMESTAMP(), nullable=False), - sa.Column('created_at', sa.TIMESTAMP(), server_default=sa.text('(CURRENT_TIMESTAMP)'), nullable=False), - sa.Column('replaced_by', sa.Integer(), nullable=True), - sa.ForeignKeyConstraint(['replaced_by'], ['refresh_tokens.id'], name=op.f('fk_refresh_tokens_replaced_by_refresh_tokens')), - sa.ForeignKeyConstraint(['user_id'], ['users.id'], name=op.f('fk_refresh_tokens_user_id_users'), ondelete='CASCADE'), - sa.PrimaryKeyConstraint('id', name=op.f('pk_refresh_tokens')), - sa.UniqueConstraint('token_hash', name=op.f('uq_refresh_tokens_token_hash')) - ) - with op.batch_alter_table('refresh_tokens', schema=None) as batch_op: - batch_op.create_index(batch_op.f('ix_refresh_tokens_id'), ['id'], unique=False) - batch_op.create_index(batch_op.f('ix_refresh_tokens_user_id'), ['user_id'], unique=False) - - # ### end Alembic commands ### - - -def downgrade() -> None: - """Downgrade schema.""" - # ### commands auto generated by Alembic - please adjust! ### - with op.batch_alter_table('refresh_tokens', schema=None) as batch_op: - batch_op.drop_index(batch_op.f('ix_refresh_tokens_user_id')) - batch_op.drop_index(batch_op.f('ix_refresh_tokens_id')) - - op.drop_table('refresh_tokens') - # ### end Alembic commands ### diff --git a/src/models/database_models/__init__.py b/src/models/database_models/__init__.py new file mode 100644 index 0000000..0b98307 --- /dev/null +++ b/src/models/database_models/__init__.py @@ -0,0 +1,2 @@ +from .files import Stored +from .model import Model, User, RefreshTokens, PermissionsGroups, Permissions \ No newline at end of file diff --git a/src/models/database_models/files.py b/src/models/database_models/files.py new file mode 100644 index 0000000..388859e --- /dev/null +++ b/src/models/database_models/files.py @@ -0,0 +1,14 @@ +from datetime import datetime +from sqlalchemy import TIMESTAMP, String, func +from sqlalchemy.orm import Mapped, mapped_column +from src.models.database_models.model import Model + +class Stored(Model): + __tablename__="reports" + + id:Mapped[int]=mapped_column(primary_key=True, index=True) + filename:Mapped[str]=mapped_column(String(255), index=True) + created_at:Mapped[datetime]=mapped_column(TIMESTAMP, server_default=func.now()) + + def __repr__(self) -> str: + return f'ID: {self.id}, Filename: {self.filename}' \ No newline at end of file diff --git a/src/models/pydantic_models/model.py b/src/models/pydantic_models/model.py index 2683030..7298bff 100644 --- a/src/models/pydantic_models/model.py +++ b/src/models/pydantic_models/model.py @@ -1,4 +1,3 @@ -from dataclasses import replace from datetime import datetime from typing import Annotated from pydantic import BaseModel, EmailStr, Field @@ -61,7 +60,7 @@ class PermissionsGroupsOut(Base): class RefreshTokens(Base): - id:int + user_id:Annotated[UUID, Field(..., description="foreign key for the user")] token_hash:Annotated[str, Field(..., description="token hash")] device_info:Annotated[str, Field(..., description="User device info")] @@ -69,4 +68,12 @@ class RefreshTokens(Base): is_revoked:Annotated[bool|None, Field(None, description="revoke token if logout was made")] expires_at:Annotated[datetime, Field(..., description="when token is going to be expired")] - \ No newline at end of file +class RefreshTokensOut(Base): + + id:int + user_id:Annotated[UUID, Field(..., description="foreign key for the user")] + token_hash:Annotated[str, Field(..., description="token hash")] + device_info:Annotated[str, Field(..., description="User device info")] + ip_address:Annotated[str, Field(..., description="ip v4/v6 of the user")] + is_revoked:Annotated[bool|None, Field(None, description="revoke token if logout was made")] + expires_at:Annotated[datetime, Field(..., description="when token is going to be expired")] diff --git a/src/service/__init__.py b/src/service/__init__.py new file mode 100644 index 0000000..f343b7a --- /dev/null +++ b/src/service/__init__.py @@ -0,0 +1 @@ +'''business logic''' \ No newline at end of file