From a31758192dcf253ae4b6c0ed58d4847b1a817519 Mon Sep 17 00:00:00 2001 From: TheNoxium Date: Mon, 9 Jun 2025 02:10:46 +0500 Subject: [PATCH 1/5] fix: model --- api/api/schemas/account/account.py | 5 +++-- api/api/schemas/account/account_keyring.py | 5 +++-- api/api/schemas/endpoints/account.py | 9 +++++---- api/api/schemas/endpoints/account_keyring.py | 5 +++-- api/api/schemas/endpoints/auth.py | 8 ++++---- api/api/schemas/events/list_events.py | 4 ++-- api/api/schemas/process/node_link.py | 2 +- 7 files changed, 21 insertions(+), 17 deletions(-) diff --git a/api/api/schemas/account/account.py b/api/api/schemas/account/account.py index 1ceb3b0..3455e58 100644 --- a/api/api/schemas/account/account.py +++ b/api/api/schemas/account/account.py @@ -1,11 +1,12 @@ import datetime from datetime import datetime from typing import Optional -from pydantic import BaseModel, EmailStr, Field +from pydantic import EmailStr, Field from api.db.tables.account import AccountRole,AccountStatus +from api.schemas.base import Base -class User(BaseModel): +class User(Base): id: Optional[int] = None name: str = Field(..., max_length=100) login: str = Field(..., max_length=100) diff --git a/api/api/schemas/account/account_keyring.py b/api/api/schemas/account/account_keyring.py index b504797..48cb8b9 100644 --- a/api/api/schemas/account/account_keyring.py +++ b/api/api/schemas/account/account_keyring.py @@ -1,11 +1,12 @@ import datetime from typing import Optional -from pydantic import BaseModel, Field +from pydantic import Field from datetime import datetime from api.db.tables.account import KeyType,KeyStatus +from api.schemas.base import Base -class AccountKeyring(BaseModel): +class AccountKeyring(Base): owner_id: int key_type: KeyType key_id: Optional[str] = Field(None, max_length=40) diff --git a/api/api/schemas/endpoints/account.py b/api/api/schemas/endpoints/account.py index c91a9a2..ffe7b93 100644 --- a/api/api/schemas/endpoints/account.py +++ b/api/api/schemas/endpoints/account.py @@ -1,12 +1,13 @@ from typing import Optional, List from datetime import datetime -from pydantic import BaseModel, EmailStr, Field, TypeAdapter +from pydantic import EmailStr, Field, TypeAdapter from api.db.tables.account import AccountRole,AccountStatus +from api.schemas.base import Base -class UserUpdate(BaseModel): +class UserUpdate(Base): id: Optional[int] = None name: Optional[str] = Field(None, max_length=100) login: Optional[str] = Field(None, max_length=100) @@ -18,7 +19,7 @@ class UserUpdate(BaseModel): created_at: Optional[datetime] = None status: Optional[AccountStatus] = None -class AllUser(BaseModel): +class AllUser(Base): id: int name: str login: str @@ -29,7 +30,7 @@ class AllUser(BaseModel): status: AccountStatus -class AllUserResponse(BaseModel): +class AllUserResponse(Base): users: List[AllUser] amount_count: int amount_pages: int diff --git a/api/api/schemas/endpoints/account_keyring.py b/api/api/schemas/endpoints/account_keyring.py index 5e646dc..548bdf9 100644 --- a/api/api/schemas/endpoints/account_keyring.py +++ b/api/api/schemas/endpoints/account_keyring.py @@ -1,11 +1,12 @@ import datetime from typing import Optional -from pydantic import BaseModel, Field +from pydantic import Field from datetime import datetime from api.db.tables.account import KeyType,KeyStatus +from api.schemas.base import Base -class AccountKeyringUpdate(BaseModel): +class AccountKeyringUpdate(Base): owner_id: Optional[int] = None key_type: Optional[KeyType] = None key_id: Optional[str] = Field(None, max_length=40) diff --git a/api/api/schemas/endpoints/auth.py b/api/api/schemas/endpoints/auth.py index 15e5c3a..997c144 100644 --- a/api/api/schemas/endpoints/auth.py +++ b/api/api/schemas/endpoints/auth.py @@ -1,14 +1,14 @@ -from api.schemas.base import BaseModel +from api.schemas.base import Base # Таблица для получения информации из запроса -class Auth(BaseModel): +class Auth(Base): login: str password: str -class Refresh(BaseModel,): +class Refresh(Base): refresh_token: str -class Access(BaseModel): +class Access(Base): access_token: str diff --git a/api/api/schemas/events/list_events.py b/api/api/schemas/events/list_events.py index e5144ae..2df94c7 100644 --- a/api/api/schemas/events/list_events.py +++ b/api/api/schemas/events/list_events.py @@ -3,7 +3,7 @@ from typing import Dict, Any from datetime import datetime from enum import Enum -from api.schemas.base import BaseModel +from api.schemas.base import Base class State(Enum): @@ -17,7 +17,7 @@ class Status(Enum): DELETED = "Deleted" -class ListEvent(BaseModel): +class ListEvent(Base): id: int name: str = Field(..., max_length=40) title: str = Field(..., max_length=64) diff --git a/api/api/schemas/process/node_link.py b/api/api/schemas/process/node_link.py index 92d5513..f67a9f9 100644 --- a/api/api/schemas/process/node_link.py +++ b/api/api/schemas/process/node_link.py @@ -1,4 +1,4 @@ -from pydantic import Field, conint +from pydantic import Field from typing import Dict, Any from datetime import datetime from enum import Enum From c1d315d6e978b0d8c4218150921256dd081b6c1c Mon Sep 17 00:00:00 2001 From: Vladislav Date: Mon, 9 Jun 2025 11:51:13 +0500 Subject: [PATCH 2/5] feat: add bearer schema and get_current_user function --- api/api/schemas/base.py | 4 ++++ api/api/services/auth.py | 11 +++++++++-- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/api/api/schemas/base.py b/api/api/schemas/base.py index 5fcc034..6ca542b 100644 --- a/api/api/schemas/base.py +++ b/api/api/schemas/base.py @@ -1,7 +1,11 @@ +from fastapi.security import HTTPBearer from pydantic import BaseModel, ConfigDict from pydantic.alias_generators import to_camel +bearer_schema = HTTPBearer() # схема для авторизации в swagger + + class Base(BaseModel): model_config = ConfigDict( from_attributes=True, diff --git a/api/api/services/auth.py b/api/api/services/auth.py index e0b1b6f..761949a 100644 --- a/api/api/services/auth.py +++ b/api/api/services/auth.py @@ -1,3 +1,4 @@ +from fastapi import Request, HTTPException from typing import Optional from sqlalchemy.ext.asyncio import AsyncConnection from api.db.logic.auth import get_user @@ -9,11 +10,17 @@ from api.db.tables.account import AccountStatus from api.utils.hasher import Hasher +async def get_current_user(request: Request) -> Optional[User]: + if not hasattr(request.state, "current_user"): + return HTTPException(status_code=401, detail="Unauthorized") + return request.state.current_user + + async def authenticate_user(connection: AsyncConnection, username: str, password: str) -> Optional[User]: sql_user, sql_password = await get_user(connection, username) - if not sql_user or sql_user.status != AccountStatus.ACTIVE : - return None + if not sql_user or sql_user.status != AccountStatus.ACTIVE: + return None hasher = Hasher() if not hasher.verify_data(password, sql_password.key_value): return None From 2e4e9d11135552391e2217a86ddab04cb5178b66 Mon Sep 17 00:00:00 2001 From: Vladislav Date: Mon, 9 Jun 2025 12:10:40 +0500 Subject: [PATCH 3/5] feat: add bearer schema to all endpoints with auth --- api/api/endpoints/account.py | 40 +++++++++++++++--------------------- api/api/endpoints/keyring.py | 25 ++++++++++------------ api/api/endpoints/profile.py | 13 ++++++------ 3 files changed, 34 insertions(+), 44 deletions(-) diff --git a/api/api/endpoints/account.py b/api/api/endpoints/account.py index 2497766..8d996cc 100644 --- a/api/api/endpoints/account.py +++ b/api/api/endpoints/account.py @@ -2,7 +2,6 @@ from fastapi import ( APIRouter, Depends, HTTPException, - Request, status, ) @@ -15,8 +14,9 @@ from api.db.logic.account import get_user_by_id, update_user_by_id, create_user, from api.schemas.account.account import User from api.db.tables.account import AccountStatus +from api.schemas.base import bearer_schema from api.schemas.endpoints.account import UserUpdate,AllUserResponse - +from api.services.auth import get_current_user from api.services.user_role_validation import db_user_role_validation from api.services.update_data_validation import update_user_data_changes @@ -28,17 +28,15 @@ api_router = APIRouter( tags=["User accountModel"], ) -@api_router.get("",response_model=AllUserResponse) +@api_router.get("",dependencies=[Depends(bearer_schema)],response_model=AllUserResponse) async def get_all_account( - - request: Request, - page: int , - limit: int , - connection: AsyncConnection = Depends(get_connection_dep) + page: int = 1, + limit: int = 10, + connection: AsyncConnection = Depends(get_connection_dep), + current_user = Depends(get_current_user) ): - current_user = request.state.current_user authorize_user = await db_user_role_validation(connection, current_user) user_list = await get_user_accaunt_page(connection,page,limit) @@ -51,9 +49,8 @@ async def get_all_account( return user_list -@api_router.get("/{user_id}", response_model=User) -async def get_account(user_id: int, request: Request, connection: AsyncConnection = Depends(get_connection_dep)): - current_user = request.state.current_user +@api_router.get("/{user_id}",dependencies=[Depends(bearer_schema)], response_model=User) +async def get_account(user_id: int, connection: AsyncConnection = Depends(get_connection_dep), current_user = Depends(get_current_user)): authorize_user = await db_user_role_validation(connection, current_user) user = await get_user_by_id(connection, user_id) @@ -65,14 +62,13 @@ async def get_account(user_id: int, request: Request, connection: AsyncConnectio -@api_router.post("", response_model=User) +@api_router.post("", dependencies=[Depends(bearer_schema)],response_model=User) async def create_account( user: UserUpdate, - request: Request, - connection: AsyncConnection = Depends(get_connection_dep) + connection: AsyncConnection = Depends(get_connection_dep), + current_user = Depends(get_current_user) ): - current_user = request.state.current_user authorize_user = await db_user_role_validation(connection, current_user) @@ -90,11 +86,10 @@ async def create_account( ) -@api_router.put("/{user_id}", response_model=User) +@api_router.put("/{user_id}",dependencies=[Depends(bearer_schema)], response_model=User) async def update_account( - user_id: int, request: Request, user_update: UserUpdate, connection: AsyncConnection = Depends(get_connection_dep) + user_id: int, user_update: UserUpdate, connection: AsyncConnection = Depends(get_connection_dep), current_user = Depends(get_current_user) ): - current_user = request.state.current_user authorize_user = await db_user_role_validation(connection, current_user) @@ -116,15 +111,14 @@ async def update_account( return user -@api_router.delete("/{user_id}", response_model=User) +@api_router.delete("/{user_id}", dependencies=[Depends(bearer_schema)],response_model=User) async def delete_account( user_id: int, - request: Request, - connection: AsyncConnection = Depends(get_connection_dep) + connection: AsyncConnection = Depends(get_connection_dep), + current_user = Depends(get_current_user) ): - current_user = request.state.current_user authorize_user = await db_user_role_validation(connection, current_user) diff --git a/api/api/endpoints/keyring.py b/api/api/endpoints/keyring.py index 7d0917c..aa989b3 100644 --- a/api/api/endpoints/keyring.py +++ b/api/api/endpoints/keyring.py @@ -4,7 +4,6 @@ from fastapi import ( Depends, Form, HTTPException, - Request, Response, status, ) @@ -19,9 +18,11 @@ from api.db.logic.keyring import get_key_by_id,create_key,update_key_by_id from api.db.tables.account import KeyStatus +from api.schemas.base import bearer_schema from api.schemas.endpoints.account_keyring import AccountKeyringUpdate from api.schemas.account.account_keyring import AccountKeyring +from api.services.auth import get_current_user from api.services.user_role_validation import db_user_role_validation from api.services.update_data_validation import update_key_data_changes @@ -33,14 +34,13 @@ api_router = APIRouter( ) -@api_router.get("/{user_id}/{key_id}", response_model=AccountKeyring) +@api_router.get("/{user_id}/{key_id}",dependencies=[Depends(bearer_schema)], response_model=AccountKeyring) async def get_keyring( key_id: str, - request: Request, - connection: AsyncConnection = Depends(get_connection_dep) + connection: AsyncConnection = Depends(get_connection_dep), + current_user = Depends(get_current_user) ): - current_user = request.state.current_user authorize_user = await db_user_role_validation(connection, current_user) @@ -52,15 +52,14 @@ async def get_keyring( return keyring -@api_router.post("/{user_id}/{key_id}", response_model=AccountKeyring) +@api_router.post("/{user_id}/{key_id}", dependencies=[Depends(bearer_schema)], response_model=AccountKeyring) async def create_keyring( user_id: int, key_id: str, - request: Request, key: AccountKeyringUpdate, connection: AsyncConnection = Depends(get_connection_dep), + current_user = Depends(get_current_user) ): - current_user = request.state.current_user authorize_user = await db_user_role_validation(connection, current_user) @@ -76,15 +75,14 @@ async def create_keyring( ) -@api_router.put("/{user_id}/{key_id}", response_model=AccountKeyring) +@api_router.put("/{user_id}/{key_id}", dependencies=[Depends(bearer_schema)],response_model=AccountKeyring) async def update_keyring( user_id: int, key_id: str, - request: Request, keyring_update: AccountKeyringUpdate, connection: AsyncConnection = Depends(get_connection_dep), + current_user = Depends(get_current_user) ): - current_user = request.state.current_user authorize_user = await db_user_role_validation(connection, current_user) @@ -106,11 +104,10 @@ async def update_keyring( return keyring -@api_router.delete("/{user_id}/{key_id}", response_model=AccountKeyring) +@api_router.delete("/{user_id}/{key_id}",dependencies=[Depends(bearer_schema)], response_model=AccountKeyring) async def delete_keyring( - user_id: int, key_id: str, request: Request, connection: AsyncConnection = Depends(get_connection_dep) + user_id: int, key_id: str, connection: AsyncConnection = Depends(get_connection_dep), current_user = Depends(get_current_user) ): - current_user = request.state.current_user authorize_user = await db_user_role_validation(connection, current_user) diff --git a/api/api/endpoints/profile.py b/api/api/endpoints/profile.py index e4abc66..383815c 100644 --- a/api/api/endpoints/profile.py +++ b/api/api/endpoints/profile.py @@ -14,6 +14,8 @@ from sqlalchemy.ext.asyncio import AsyncConnection from api.db.connection.session import get_connection_dep from api.db.logic.account import get_user_by_id, update_user_by_id,get_user_by_login +from api.schemas.base import bearer_schema +from api.services.auth import get_current_user from api.services.update_data_validation import update_user_data_changes from api.schemas.endpoints.account import UserUpdate @@ -26,13 +28,11 @@ api_router = APIRouter( ) -@api_router.get("",response_model=User) +@api_router.get("",dependencies=[Depends(bearer_schema)],response_model=User) async def get_profile( - request: Request, connection: AsyncConnection = Depends(get_connection_dep), + current_user = Depends(get_current_user) ): - # Извлекаем текущего пользователя из request.state - current_user = request.state.current_user user = await get_user_by_login(connection, current_user) @@ -42,13 +42,12 @@ async def get_profile( return user -@api_router.put("",response_model=User) +@api_router.put("", dependencies=[Depends(bearer_schema)],response_model=User) async def update_profile( - request: Request, user_updata: UserUpdate, connection: AsyncConnection = Depends(get_connection_dep), + current_user = Depends(get_current_user) ): - current_user = request.state.current_user user = await get_user_by_login(connection, current_user) if user is None: From 787dc0e8f87ff9c0aaee88a94ace39c80b677c73 Mon Sep 17 00:00:00 2001 From: Vladislav Date: Mon, 9 Jun 2025 12:12:48 +0500 Subject: [PATCH 4/5] refactor: refactor api project with ruff --- api/api/db/logic/account.py | 26 ++++--- api/api/db/logic/keyring.py | 2 - api/api/db/tables/account.py | 26 +++---- api/api/endpoints/account.py | 75 +++++++++----------- api/api/endpoints/auth.py | 3 +- api/api/endpoints/keyring.py | 40 +++++------ api/api/endpoints/profile.py | 13 ++-- api/api/schemas/account/account.py | 3 +- api/api/schemas/account/account_keyring.py | 3 +- api/api/schemas/base.py | 2 +- api/api/schemas/endpoints/account.py | 4 +- api/api/schemas/endpoints/account_keyring.py | 3 +- api/api/schemas/endpoints/auth.py | 2 + api/api/services/update_data_validation.py | 4 +- api/api/services/user_role_validation.py | 6 +- 15 files changed, 100 insertions(+), 112 deletions(-) diff --git a/api/api/db/logic/account.py b/api/api/db/logic/account.py index 65ccef7..5f16ac4 100644 --- a/api/api/db/logic/account.py +++ b/api/api/db/logic/account.py @@ -18,17 +18,19 @@ async def get_user_accaunt_page(connection: AsyncConnection, page, limit) -> Opt Получает список ползовелей заданных значениями page, limit. """ - first_user = page*limit-(limit) + first_user = page * limit - (limit) query = ( - select(account_table.c.id, - account_table.c.name, - account_table.c.login, - account_table.c.email, - account_table.c.bind_tenant_id, - account_table.c.role, - account_table.c.created_at, - account_table.c.status) + select( + account_table.c.id, + account_table.c.name, + account_table.c.login, + account_table.c.email, + account_table.c.bind_tenant_id, + account_table.c.role, + account_table.c.created_at, + account_table.c.status, + ) .order_by(account_table.c.id) .offset(first_user) .limit(limit) @@ -45,11 +47,7 @@ async def get_user_accaunt_page(connection: AsyncConnection, page, limit) -> Opt validated_users = all_user_adapter.validate_python(users_data) - return AllUserResponse( - users=validated_users, - amount_count=total_count, - amount_pages=total_pages - ) + return AllUserResponse(users=validated_users, amount_count=total_count, amount_pages=total_pages) async def get_user_by_id(connection: AsyncConnection, id: int) -> Optional[User]: diff --git a/api/api/db/logic/keyring.py b/api/api/db/logic/keyring.py index f663c2f..91469a6 100644 --- a/api/api/db/logic/keyring.py +++ b/api/api/db/logic/keyring.py @@ -10,8 +10,6 @@ from api.db.tables.account import account_keyring_table from api.schemas.account.account_keyring import AccountKeyring - - async def get_key_by_id(connection: AsyncConnection, key_id: str) -> Optional[AccountKeyring]: """ Получает key по key_id. diff --git a/api/api/db/tables/account.py b/api/api/db/tables/account.py index fcf2cc3..ed4fa8f 100644 --- a/api/api/db/tables/account.py +++ b/api/api/db/tables/account.py @@ -7,17 +7,18 @@ from api.db.sql_types import UnsignedInt from api.db import metadata -class AccountRole(str,Enum): - OWNER = 'OWNER' - ADMIN = 'ADMIN' - EDITOR = 'EDITOR' - VIEWER = 'VIEWER' +class AccountRole(str, Enum): + OWNER = "OWNER" + ADMIN = "ADMIN" + EDITOR = "EDITOR" + VIEWER = "VIEWER" -class AccountStatus(str,Enum): - ACTIVE = 'ACTIVE' - DISABLED = 'DISABLED' - BLOCKED = 'BLOCKED' - DELETED = 'DELETED' + +class AccountStatus(str, Enum): + ACTIVE = "ACTIVE" + DISABLED = "DISABLED" + BLOCKED = "BLOCKED" + DELETED = "DELETED" account_table = Table( @@ -38,13 +39,14 @@ account_table = Table( ) -class KeyType(str,Enum): +class KeyType(str, Enum): PASSWORD = "PASSWORD" ACCESS_TOKEN = "ACCESS_TOKEN" REFRESH_TOKEN = "REFRESH_TOKEN" API_KEY = "API_KEY" -class KeyStatus(str,Enum): + +class KeyStatus(str, Enum): ACTIVE = "ACTIVE" EXPIRED = "EXPIRED" DELETED = "DELETED" diff --git a/api/api/endpoints/account.py b/api/api/endpoints/account.py index 8d996cc..99ecf83 100644 --- a/api/api/endpoints/account.py +++ b/api/api/endpoints/account.py @@ -10,47 +10,51 @@ from sqlalchemy.ext.asyncio import AsyncConnection from api.db.connection.session import get_connection_dep -from api.db.logic.account import get_user_by_id, update_user_by_id, create_user,get_user_by_login,get_user_accaunt_page +from api.db.logic.account import ( + get_user_by_id, + update_user_by_id, + create_user, + get_user_by_login, + get_user_accaunt_page, +) from api.schemas.account.account import User from api.db.tables.account import AccountStatus from api.schemas.base import bearer_schema -from api.schemas.endpoints.account import UserUpdate,AllUserResponse +from api.schemas.endpoints.account import UserUpdate, AllUserResponse from api.services.auth import get_current_user from api.services.user_role_validation import db_user_role_validation from api.services.update_data_validation import update_user_data_changes - api_router = APIRouter( prefix="/account", tags=["User accountModel"], ) -@api_router.get("",dependencies=[Depends(bearer_schema)],response_model=AllUserResponse) + +@api_router.get("", dependencies=[Depends(bearer_schema)], response_model=AllUserResponse) async def get_all_account( - page: int = 1, - limit: int = 10, - connection: AsyncConnection = Depends(get_connection_dep), - current_user = Depends(get_current_user) - ): - - + page: int = 1, + limit: int = 10, + connection: AsyncConnection = Depends(get_connection_dep), + current_user=Depends(get_current_user), +): authorize_user = await db_user_role_validation(connection, current_user) - user_list = await get_user_accaunt_page(connection,page,limit) + user_list = await get_user_accaunt_page(connection, page, limit) if user_list is None: - raise HTTPException( - status_code=status.HTTP_404_NOT_FOUND, - detail="Accounts not found") + raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Accounts not found") return user_list -@api_router.get("/{user_id}",dependencies=[Depends(bearer_schema)], response_model=User) -async def get_account(user_id: int, connection: AsyncConnection = Depends(get_connection_dep), current_user = Depends(get_current_user)): +@api_router.get("/{user_id}", dependencies=[Depends(bearer_schema)], response_model=User) +async def get_account( + user_id: int, connection: AsyncConnection = Depends(get_connection_dep), current_user=Depends(get_current_user) +): authorize_user = await db_user_role_validation(connection, current_user) user = await get_user_by_id(connection, user_id) @@ -61,22 +65,16 @@ async def get_account(user_id: int, connection: AsyncConnection = Depends(get_co return user - -@api_router.post("", dependencies=[Depends(bearer_schema)],response_model=User) +@api_router.post("", dependencies=[Depends(bearer_schema)], response_model=User) async def create_account( - user: UserUpdate, - connection: AsyncConnection = Depends(get_connection_dep), - current_user = Depends(get_current_user) - ): - - + user: UserUpdate, connection: AsyncConnection = Depends(get_connection_dep), current_user=Depends(get_current_user) +): authorize_user = await db_user_role_validation(connection, current_user) user_validation = await get_user_by_login(connection, user.login) if user_validation is None: - - await create_user(connection,user,authorize_user.id) + await create_user(connection, user, authorize_user.id) user_new = await get_user_by_login(connection, user.login) return user_new @@ -86,11 +84,13 @@ async def create_account( ) -@api_router.put("/{user_id}",dependencies=[Depends(bearer_schema)], response_model=User) +@api_router.put("/{user_id}", dependencies=[Depends(bearer_schema)], response_model=User) async def update_account( - user_id: int, user_update: UserUpdate, connection: AsyncConnection = Depends(get_connection_dep), current_user = Depends(get_current_user) + user_id: int, + user_update: UserUpdate, + connection: AsyncConnection = Depends(get_connection_dep), + current_user=Depends(get_current_user), ): - authorize_user = await db_user_role_validation(connection, current_user) user = await get_user_by_id(connection, user_id) @@ -106,20 +106,15 @@ async def update_account( await update_user_by_id(connection, update_values, user) - user = await get_user_by_id(connection, user_id) return user -@api_router.delete("/{user_id}", dependencies=[Depends(bearer_schema)],response_model=User) + +@api_router.delete("/{user_id}", dependencies=[Depends(bearer_schema)], response_model=User) async def delete_account( - user_id: int, - connection: AsyncConnection = Depends(get_connection_dep), - current_user = Depends(get_current_user) - ): - - - + user_id: int, connection: AsyncConnection = Depends(get_connection_dep), current_user=Depends(get_current_user) +): authorize_user = await db_user_role_validation(connection, current_user) user = await get_user_by_id(connection, user_id) @@ -133,10 +128,8 @@ async def delete_account( if update_values is None: return user - await update_user_by_id(connection, update_values, user) - user = await get_user_by_id(connection, user_id) return user diff --git a/api/api/endpoints/auth.py b/api/api/endpoints/auth.py index a4f5806..bd0cfe8 100644 --- a/api/api/endpoints/auth.py +++ b/api/api/endpoints/auth.py @@ -86,8 +86,7 @@ async def login_for_access_token( return Access(access_token=access_token) - -@api_router.post("/refresh",response_model=Access) +@api_router.post("/refresh", response_model=Access) async def refresh( request: Request, connection: AsyncConnection = Depends(get_connection_dep), Authorize: AuthJWT = Depends() ): diff --git a/api/api/endpoints/keyring.py b/api/api/endpoints/keyring.py index aa989b3..3f09f61 100644 --- a/api/api/endpoints/keyring.py +++ b/api/api/endpoints/keyring.py @@ -13,8 +13,7 @@ from sqlalchemy.ext.asyncio import AsyncConnection from api.db.connection.session import get_connection_dep -from api.db.logic.keyring import get_key_by_id,create_key,update_key_by_id - +from api.db.logic.keyring import get_key_by_id, create_key, update_key_by_id from api.db.tables.account import KeyStatus @@ -34,14 +33,10 @@ api_router = APIRouter( ) -@api_router.get("/{user_id}/{key_id}",dependencies=[Depends(bearer_schema)], response_model=AccountKeyring) +@api_router.get("/{user_id}/{key_id}", dependencies=[Depends(bearer_schema)], response_model=AccountKeyring) async def get_keyring( - key_id: str, - connection: AsyncConnection = Depends(get_connection_dep), - current_user = Depends(get_current_user) - ): - - + key_id: str, connection: AsyncConnection = Depends(get_connection_dep), current_user=Depends(get_current_user) +): authorize_user = await db_user_role_validation(connection, current_user) keyring = await get_key_by_id(connection, key_id) @@ -58,15 +53,18 @@ async def create_keyring( key_id: str, key: AccountKeyringUpdate, connection: AsyncConnection = Depends(get_connection_dep), - current_user = Depends(get_current_user) + current_user=Depends(get_current_user), ): - authorize_user = await db_user_role_validation(connection, current_user) keyring = await get_key_by_id(connection, key_id) if keyring is None: - keyring_new = await create_key(connection,key, key_id, ) + keyring_new = await create_key( + connection, + key, + key_id, + ) return keyring_new else: @@ -75,15 +73,14 @@ async def create_keyring( ) -@api_router.put("/{user_id}/{key_id}", dependencies=[Depends(bearer_schema)],response_model=AccountKeyring) +@api_router.put("/{user_id}/{key_id}", dependencies=[Depends(bearer_schema)], response_model=AccountKeyring) async def update_keyring( user_id: int, key_id: str, keyring_update: AccountKeyringUpdate, connection: AsyncConnection = Depends(get_connection_dep), - current_user = Depends(get_current_user) + current_user=Depends(get_current_user), ): - authorize_user = await db_user_role_validation(connection, current_user) keyring = await get_key_by_id(connection, key_id) @@ -99,16 +96,18 @@ async def update_keyring( await update_key_by_id(connection, update_values, keyring) - keyring = await get_key_by_id(connection, key_id) return keyring -@api_router.delete("/{user_id}/{key_id}",dependencies=[Depends(bearer_schema)], response_model=AccountKeyring) -async def delete_keyring( - user_id: int, key_id: str, connection: AsyncConnection = Depends(get_connection_dep), current_user = Depends(get_current_user) -): +@api_router.delete("/{user_id}/{key_id}", dependencies=[Depends(bearer_schema)], response_model=AccountKeyring) +async def delete_keyring( + user_id: int, + key_id: str, + connection: AsyncConnection = Depends(get_connection_dep), + current_user=Depends(get_current_user), +): authorize_user = await db_user_role_validation(connection, current_user) keyring = await get_key_by_id(connection, key_id) @@ -124,7 +123,6 @@ async def delete_keyring( await update_key_by_id(connection, update_values, keyring) - keyring = await get_key_by_id(connection, key_id) return keyring diff --git a/api/api/endpoints/profile.py b/api/api/endpoints/profile.py index 383815c..8f13a98 100644 --- a/api/api/endpoints/profile.py +++ b/api/api/endpoints/profile.py @@ -13,7 +13,7 @@ from fastapi import ( from sqlalchemy.ext.asyncio import AsyncConnection from api.db.connection.session import get_connection_dep -from api.db.logic.account import get_user_by_id, update_user_by_id,get_user_by_login +from api.db.logic.account import get_user_by_id, update_user_by_id, get_user_by_login from api.schemas.base import bearer_schema from api.services.auth import get_current_user from api.services.update_data_validation import update_user_data_changes @@ -28,12 +28,10 @@ api_router = APIRouter( ) -@api_router.get("",dependencies=[Depends(bearer_schema)],response_model=User) +@api_router.get("", dependencies=[Depends(bearer_schema)], response_model=User) async def get_profile( - connection: AsyncConnection = Depends(get_connection_dep), - current_user = Depends(get_current_user) + connection: AsyncConnection = Depends(get_connection_dep), current_user=Depends(get_current_user) ): - user = await get_user_by_login(connection, current_user) if user is None: @@ -42,13 +40,12 @@ async def get_profile( return user -@api_router.put("", dependencies=[Depends(bearer_schema)],response_model=User) +@api_router.put("", dependencies=[Depends(bearer_schema)], response_model=User) async def update_profile( user_updata: UserUpdate, connection: AsyncConnection = Depends(get_connection_dep), - current_user = Depends(get_current_user) + current_user=Depends(get_current_user), ): - user = await get_user_by_login(connection, current_user) if user is None: raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Account not found") diff --git a/api/api/schemas/account/account.py b/api/api/schemas/account/account.py index 3455e58..28635d5 100644 --- a/api/api/schemas/account/account.py +++ b/api/api/schemas/account/account.py @@ -2,10 +2,11 @@ import datetime from datetime import datetime from typing import Optional from pydantic import EmailStr, Field -from api.db.tables.account import AccountRole,AccountStatus +from api.db.tables.account import AccountRole, AccountStatus from api.schemas.base import Base + class User(Base): id: Optional[int] = None name: str = Field(..., max_length=100) diff --git a/api/api/schemas/account/account_keyring.py b/api/api/schemas/account/account_keyring.py index 48cb8b9..2827f94 100644 --- a/api/api/schemas/account/account_keyring.py +++ b/api/api/schemas/account/account_keyring.py @@ -2,10 +2,11 @@ import datetime from typing import Optional from pydantic import Field from datetime import datetime -from api.db.tables.account import KeyType,KeyStatus +from api.db.tables.account import KeyType, KeyStatus from api.schemas.base import Base + class AccountKeyring(Base): owner_id: int key_type: KeyType diff --git a/api/api/schemas/base.py b/api/api/schemas/base.py index 6ca542b..f16e682 100644 --- a/api/api/schemas/base.py +++ b/api/api/schemas/base.py @@ -3,7 +3,7 @@ from pydantic import BaseModel, ConfigDict from pydantic.alias_generators import to_camel -bearer_schema = HTTPBearer() # схема для авторизации в swagger +bearer_schema = HTTPBearer() # схема для авторизации в swagger class Base(BaseModel): diff --git a/api/api/schemas/endpoints/account.py b/api/api/schemas/endpoints/account.py index ffe7b93..37ceeea 100644 --- a/api/api/schemas/endpoints/account.py +++ b/api/api/schemas/endpoints/account.py @@ -2,7 +2,7 @@ from typing import Optional, List from datetime import datetime from pydantic import EmailStr, Field, TypeAdapter -from api.db.tables.account import AccountRole,AccountStatus +from api.db.tables.account import AccountRole, AccountStatus from api.schemas.base import Base @@ -19,6 +19,7 @@ class UserUpdate(Base): created_at: Optional[datetime] = None status: Optional[AccountStatus] = None + class AllUser(Base): id: int name: str @@ -35,4 +36,5 @@ class AllUserResponse(Base): amount_count: int amount_pages: int + all_user_adapter = TypeAdapter(List[AllUser]) diff --git a/api/api/schemas/endpoints/account_keyring.py b/api/api/schemas/endpoints/account_keyring.py index 548bdf9..b5f5193 100644 --- a/api/api/schemas/endpoints/account_keyring.py +++ b/api/api/schemas/endpoints/account_keyring.py @@ -2,10 +2,11 @@ import datetime from typing import Optional from pydantic import Field from datetime import datetime -from api.db.tables.account import KeyType,KeyStatus +from api.db.tables.account import KeyType, KeyStatus from api.schemas.base import Base + class AccountKeyringUpdate(Base): owner_id: Optional[int] = None key_type: Optional[KeyType] = None diff --git a/api/api/schemas/endpoints/auth.py b/api/api/schemas/endpoints/auth.py index 997c144..7c8659c 100644 --- a/api/api/schemas/endpoints/auth.py +++ b/api/api/schemas/endpoints/auth.py @@ -7,8 +7,10 @@ class Auth(Base): login: str password: str + class Refresh(Base): refresh_token: str + class Access(Base): access_token: str diff --git a/api/api/services/update_data_validation.py b/api/api/services/update_data_validation.py index e1ce7c6..349a0a9 100644 --- a/api/api/services/update_data_validation.py +++ b/api/api/services/update_data_validation.py @@ -1,9 +1,9 @@ from enum import Enum from typing import Optional from api.schemas.endpoints.account import UserUpdate -from api.db.tables.account import KeyType,KeyStatus +from api.db.tables.account import KeyType, KeyStatus from api.schemas.endpoints.account_keyring import AccountKeyringUpdate -from api.db.tables.account import AccountRole,AccountStatus +from api.db.tables.account import AccountRole, AccountStatus def update_user_data_changes(update_data: UserUpdate, user) -> Optional[dict]: diff --git a/api/api/services/user_role_validation.py b/api/api/services/user_role_validation.py index 3d33bcc..93670ef 100644 --- a/api/api/services/user_role_validation.py +++ b/api/api/services/user_role_validation.py @@ -6,12 +6,8 @@ from api.db.logic.account import get_user_by_login from api.db.tables.account import AccountRole - async def db_user_role_validation(connection, current_user): - authorize_user = await get_user_by_login(connection, current_user) if authorize_user.role not in {AccountRole.OWNER, AccountRole.ADMIN}: - raise HTTPException( - status_code=status.HTTP_403_FORBIDDEN, - detail="You do not have enough permissions") + raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="You do not have enough permissions") return authorize_user From abd87b46b32da328b2138f013a7d97d48bd37b20 Mon Sep 17 00:00:00 2001 From: Vladislav Date: Mon, 9 Jun 2025 13:03:33 +0500 Subject: [PATCH 5/5] refactor(tables): change enum, str to StrEnum --- api/api/db/tables/account.py | 10 ++++++---- api/api/db/tables/events.py | 16 +++++++++------- api/api/db/tables/process.py | 30 ++++++++++++++++-------------- 3 files changed, 31 insertions(+), 25 deletions(-) diff --git a/api/api/db/tables/account.py b/api/api/db/tables/account.py index ed4fa8f..84c689e 100644 --- a/api/api/db/tables/account.py +++ b/api/api/db/tables/account.py @@ -1,3 +1,5 @@ +import enum + from sqlalchemy import Table, Column, String, Enum as SQLAEnum, JSON, ForeignKey, DateTime, Index from sqlalchemy.sql import func @@ -7,14 +9,14 @@ from api.db.sql_types import UnsignedInt from api.db import metadata -class AccountRole(str, Enum): +class AccountRole(enum.StrEnum): OWNER = "OWNER" ADMIN = "ADMIN" EDITOR = "EDITOR" VIEWER = "VIEWER" -class AccountStatus(str, Enum): +class AccountStatus(enum.StrEnum): ACTIVE = "ACTIVE" DISABLED = "DISABLED" BLOCKED = "BLOCKED" @@ -39,14 +41,14 @@ account_table = Table( ) -class KeyType(str, Enum): +class KeyType(enum.StrEnum): PASSWORD = "PASSWORD" ACCESS_TOKEN = "ACCESS_TOKEN" REFRESH_TOKEN = "REFRESH_TOKEN" API_KEY = "API_KEY" -class KeyStatus(str, Enum): +class KeyStatus(enum.StrEnum): ACTIVE = "ACTIVE" EXPIRED = "EXPIRED" DELETED = "DELETED" diff --git a/api/api/db/tables/events.py b/api/api/db/tables/events.py index c4d8ab2..fba2e58 100644 --- a/api/api/db/tables/events.py +++ b/api/api/db/tables/events.py @@ -1,3 +1,5 @@ +import enum + from sqlalchemy import Table, Column, Integer, String, Enum as SQLAEnum, JSON, ForeignKey, DateTime, Index from sqlalchemy.sql import func from enum import Enum, auto @@ -7,15 +9,15 @@ from api.db.sql_types import UnsignedInt from api.db import metadata -class EventState(str, Enum): - AUTO = auto() - DESCRIPTED = auto() +class EventState(enum.StrEnum): + AUTO = "AUTO" + DESCRIPTED = "DESCRIPTED" -class EventStatus(str, Enum): - ACTIVE = auto() - DISABLED = auto() - DELETED = auto() +class EventStatus(enum.StrEnum): + ACTIVE = "ACTIVE" + DISABLED = "DISABLED" + DELETED = "DELETED" list_events_table = Table( diff --git a/api/api/db/tables/process.py b/api/api/db/tables/process.py index e2f8c68..379663c 100644 --- a/api/api/db/tables/process.py +++ b/api/api/db/tables/process.py @@ -1,3 +1,5 @@ +import enum + from sqlalchemy import ( Table, Column, @@ -19,11 +21,11 @@ from api.db.sql_types import UnsignedInt from api.db import metadata -class ProcessStatus(str, Enum): - ACTIVE = auto() - STOPPING = auto() - STOPPED = auto() - DELETED = auto() +class ProcessStatus(enum.StrEnum): + ACTIVE = "ACTIVE" + STOPPING = "STOPPING" + STOPPED = "STOPPED" + DELETED = "DELETED" process_schema_table = Table( @@ -57,10 +59,10 @@ process_version_archive_table = Table( ) -class NodeStatus(str, Enum): - ACTIVE = auto() - DISABLED = auto() - DELETED = auto() +class NodeStatus(enum.StrEnum): + ACTIVE = "ACTIVE" + DISABLED = "DISABLED" + DELETED = "DELETED" class NodeType(Enum): @@ -83,11 +85,11 @@ ps_node_table = Table( ) -class NodeLinkStatus(str, Enum): - ACTIVE = auto() - STOPPING = auto() - STOPPED = auto() - DELETED = auto() +class NodeLinkStatus(enum.StrEnum): + ACTIVE = "ACTIVE" + STOPPING = "STOPPING" + STOPPED = "STOPPED" + DELETED = "DELETED" node_link_table = Table(