Merge pull request 'VORKOUT-7' (#9) from VORKOUT-7 into master
Reviewed-on: #9 Reviewed-by: cyrussmeat <dr.cyrill@gmail.com>
This commit is contained in:
		@@ -1,18 +1,58 @@
 | 
			
		||||
from typing import Optional
 | 
			
		||||
import math
 | 
			
		||||
 | 
			
		||||
from datetime import datetime, timezone
 | 
			
		||||
 | 
			
		||||
from sqlalchemy import insert, select
 | 
			
		||||
from sqlalchemy import insert, select, func
 | 
			
		||||
from sqlalchemy.ext.asyncio import AsyncConnection
 | 
			
		||||
from enum import Enum
 | 
			
		||||
 | 
			
		||||
from api.db.tables.account import account_table
 | 
			
		||||
 | 
			
		||||
from api.schemas.account.account import User
 | 
			
		||||
from api.schemas.endpoints.account import UserUpdate, Role, Status
 | 
			
		||||
from api.schemas.endpoints.account import AllUserResponse, all_user_adapter
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
async def get_user_id(connection: AsyncConnection, id: int) -> Optional[User]:
 | 
			
		||||
async def get_user_accaunt_page(connection: AsyncConnection, page, limit) -> Optional[User]:
 | 
			
		||||
    """
 | 
			
		||||
    Получает список ползовелей заданных значениями  page, 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)
 | 
			
		||||
        .order_by(account_table.c.id)
 | 
			
		||||
        .offset(first_user)
 | 
			
		||||
        .limit(limit)
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    count_query = select(func.count()).select_from(account_table)
 | 
			
		||||
 | 
			
		||||
    result = await connection.execute(query)
 | 
			
		||||
    count_result = await connection.execute(count_query)
 | 
			
		||||
 | 
			
		||||
    users_data = result.mappings().all()
 | 
			
		||||
    total_count = count_result.scalar()
 | 
			
		||||
    total_pages = math.ceil(total_count / limit)
 | 
			
		||||
 | 
			
		||||
    validated_users = all_user_adapter.validate_python(users_data)
 | 
			
		||||
 | 
			
		||||
    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]:
 | 
			
		||||
    """
 | 
			
		||||
    Получает юзера по id.
 | 
			
		||||
    """
 | 
			
		||||
@@ -36,7 +76,7 @@ async def get_user_id(connection: AsyncConnection, id: int) -> Optional[User]:
 | 
			
		||||
    return User.model_validate(user_data)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
async def get_user_login(connection: AsyncConnection, login: str) -> Optional[User]:
 | 
			
		||||
async def get_user_by_login(connection: AsyncConnection, login: str) -> Optional[User]:
 | 
			
		||||
    """
 | 
			
		||||
    Получает юзера по login.
 | 
			
		||||
    """
 | 
			
		||||
@@ -60,7 +100,7 @@ async def get_user_login(connection: AsyncConnection, login: str) -> Optional[Us
 | 
			
		||||
    return User.model_validate(user_data)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
async def update_user_id(connection: AsyncConnection, update_values, user) -> Optional[User]:
 | 
			
		||||
async def update_user_by_id(connection: AsyncConnection, update_values, user) -> Optional[User]:
 | 
			
		||||
    """
 | 
			
		||||
    Вносит изменеия в нужное поле таблицы account_table.
 | 
			
		||||
    """
 | 
			
		||||
 
 | 
			
		||||
@@ -8,10 +8,11 @@ from sqlalchemy.ext.asyncio import AsyncConnection
 | 
			
		||||
from api.db.tables.account import account_keyring_table
 | 
			
		||||
 | 
			
		||||
from api.schemas.account.account_keyring import AccountKeyring
 | 
			
		||||
from api.schemas.endpoints.account_keyring import AccountKeyringUpdate, StatusKey, TypeKey
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
async def get_key_id(connection: AsyncConnection, key_id: str) -> Optional[AccountKeyring]:
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
async def get_key_by_id(connection: AsyncConnection, key_id: str) -> Optional[AccountKeyring]:
 | 
			
		||||
    """
 | 
			
		||||
    Получает key по key_id.
 | 
			
		||||
    """
 | 
			
		||||
@@ -35,7 +36,7 @@ async def get_key_id(connection: AsyncConnection, key_id: str) -> Optional[Accou
 | 
			
		||||
    return AccountKeyring.model_validate(user_data)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
async def update_key_id(connection: AsyncConnection, update_values, key) -> Optional[AccountKeyring]:
 | 
			
		||||
async def update_key_by_id(connection: AsyncConnection, update_values, key) -> Optional[AccountKeyring]:
 | 
			
		||||
    """
 | 
			
		||||
    Вносит изменеия в нужное поле таблицы account_keyring_table.
 | 
			
		||||
    """
 | 
			
		||||
 
 | 
			
		||||
@@ -1,24 +1,23 @@
 | 
			
		||||
from sqlalchemy import Table, Column, String, Enum as SQLAEnum, JSON, ForeignKey, DateTime, Index
 | 
			
		||||
from sqlalchemy.sql import func
 | 
			
		||||
 | 
			
		||||
from enum import Enum, auto
 | 
			
		||||
from enum import Enum
 | 
			
		||||
 | 
			
		||||
from api.db.sql_types import UnsignedInt
 | 
			
		||||
from api.db import metadata
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class AccountRole(str, Enum):
 | 
			
		||||
    OWNER = auto()
 | 
			
		||||
    ADMIN = auto()
 | 
			
		||||
    EDITOR = auto()
 | 
			
		||||
    VIEWER = auto()
 | 
			
		||||
class AccountRole(str,Enum):
 | 
			
		||||
    OWNER = 'OWNER'
 | 
			
		||||
    ADMIN = 'ADMIN'
 | 
			
		||||
    EDITOR = 'EDITOR'
 | 
			
		||||
    VIEWER = 'VIEWER'
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class AccountStatus(str, Enum):
 | 
			
		||||
    ACTIVE = auto()
 | 
			
		||||
    DISABLED = auto()
 | 
			
		||||
    BLOCKED = auto()
 | 
			
		||||
    DELETED = auto()
 | 
			
		||||
class AccountStatus(str,Enum):
 | 
			
		||||
    ACTIVE = 'ACTIVE'
 | 
			
		||||
    DISABLED = 'DISABLED'
 | 
			
		||||
    BLOCKED = 'BLOCKED'
 | 
			
		||||
    DELETED = 'DELETED'
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
account_table = Table(
 | 
			
		||||
@@ -39,17 +38,16 @@ account_table = Table(
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class KeyType(str, Enum):
 | 
			
		||||
    PASSWORD = auto()
 | 
			
		||||
    ACCESS_TOKEN = auto()
 | 
			
		||||
    REFRESH_TOKEN = auto()
 | 
			
		||||
    API_KEY = auto()
 | 
			
		||||
class KeyType(str,Enum):
 | 
			
		||||
    PASSWORD = "PASSWORD"
 | 
			
		||||
    ACCESS_TOKEN = "ACCESS_TOKEN"
 | 
			
		||||
    REFRESH_TOKEN = "REFRESH_TOKEN"
 | 
			
		||||
    API_KEY = "API_KEY"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class KeyStatus(str, Enum):
 | 
			
		||||
    ACTIVE = auto()
 | 
			
		||||
    EXPIRED = auto()
 | 
			
		||||
    DELETED = auto()
 | 
			
		||||
class KeyStatus(str,Enum):
 | 
			
		||||
    ACTIVE = "ACTIVE"
 | 
			
		||||
    EXPIRED = "EXPIRED"
 | 
			
		||||
    DELETED = "DELETED"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
account_keyring_table = Table(
 | 
			
		||||
 
 | 
			
		||||
@@ -1,11 +1,8 @@
 | 
			
		||||
from fastapi import (
 | 
			
		||||
    APIRouter,
 | 
			
		||||
    Body,
 | 
			
		||||
    Depends,
 | 
			
		||||
    Form,
 | 
			
		||||
    HTTPException,
 | 
			
		||||
    Request,
 | 
			
		||||
    Response,
 | 
			
		||||
    status,
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
@@ -14,28 +11,52 @@ from sqlalchemy.ext.asyncio import AsyncConnection
 | 
			
		||||
 | 
			
		||||
from api.db.connection.session import get_connection_dep
 | 
			
		||||
 | 
			
		||||
from api.db.logic.account import get_user_id, update_user_id, create_user, get_user_login
 | 
			
		||||
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, Status
 | 
			
		||||
from api.schemas.endpoints.account import UserUpdate
 | 
			
		||||
from api.schemas.account.account import User
 | 
			
		||||
from api.db.tables.account import AccountStatus
 | 
			
		||||
from api.schemas.endpoints.account import UserUpdate,AllUserResponse
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
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("",response_model=AllUserResponse)
 | 
			
		||||
async def get_all_account(
 | 
			
		||||
 | 
			
		||||
@api_router.get("/{user_id}")
 | 
			
		||||
                    request: Request,
 | 
			
		||||
                    page: int ,
 | 
			
		||||
                    limit: int ,
 | 
			
		||||
                    connection: AsyncConnection = Depends(get_connection_dep)
 | 
			
		||||
                    ):
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    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)
 | 
			
		||||
 | 
			
		||||
    if user_list is None:
 | 
			
		||||
        raise HTTPException(
 | 
			
		||||
            status_code=status.HTTP_404_NOT_FOUND,
 | 
			
		||||
            detail="Accounts not found")
 | 
			
		||||
 | 
			
		||||
    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
 | 
			
		||||
    authorize_user = await db_user_role_validation(connection, current_user)
 | 
			
		||||
 | 
			
		||||
    user = await get_user_id(connection, user_id)
 | 
			
		||||
    user = await get_user_by_id(connection, user_id)
 | 
			
		||||
 | 
			
		||||
    if user is None:
 | 
			
		||||
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Account not found")
 | 
			
		||||
@@ -43,17 +64,24 @@ async def get_account(user_id: int, request: Request, connection: AsyncConnectio
 | 
			
		||||
    return user
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@api_router.post("")
 | 
			
		||||
async def create_account(user: UserUpdate, request: Request, connection: AsyncConnection = Depends(get_connection_dep)):
 | 
			
		||||
 | 
			
		||||
@api_router.post("", response_model=User)
 | 
			
		||||
async def create_account(
 | 
			
		||||
                        user: UserUpdate,
 | 
			
		||||
                        request: Request,
 | 
			
		||||
                        connection: AsyncConnection = Depends(get_connection_dep)
 | 
			
		||||
                    ):
 | 
			
		||||
 | 
			
		||||
    current_user = request.state.current_user
 | 
			
		||||
 | 
			
		||||
    authorize_user = await db_user_role_validation(connection, current_user)
 | 
			
		||||
 | 
			
		||||
    user_validation = await get_user_login(connection, user.login)
 | 
			
		||||
    user_validation = await get_user_by_login(connection, user.login)
 | 
			
		||||
 | 
			
		||||
    if user_validation is None:
 | 
			
		||||
        await create_user(connection, user, authorize_user.id)
 | 
			
		||||
        user_new = await get_user_login(connection, user.login)
 | 
			
		||||
 | 
			
		||||
        await create_user(connection,user,authorize_user.id)
 | 
			
		||||
        user_new = await get_user_by_login(connection, user.login)
 | 
			
		||||
        return user_new
 | 
			
		||||
 | 
			
		||||
    else:
 | 
			
		||||
@@ -62,7 +90,7 @@ async def create_account(user: UserUpdate, request: Request, connection: AsyncCo
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@api_router.put("/{user_id}")
 | 
			
		||||
@api_router.put("/{user_id}", response_model=User)
 | 
			
		||||
async def update_account(
 | 
			
		||||
    user_id: int, request: Request, user_update: UserUpdate, connection: AsyncConnection = Depends(get_connection_dep)
 | 
			
		||||
):
 | 
			
		||||
@@ -70,7 +98,7 @@ async def update_account(
 | 
			
		||||
 | 
			
		||||
    authorize_user = await db_user_role_validation(connection, current_user)
 | 
			
		||||
 | 
			
		||||
    user = await get_user_id(connection, user_id)
 | 
			
		||||
    user = await get_user_by_id(connection, user_id)
 | 
			
		||||
    if user is None:
 | 
			
		||||
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Account not found")
 | 
			
		||||
 | 
			
		||||
@@ -81,32 +109,40 @@ async def update_account(
 | 
			
		||||
 | 
			
		||||
    user_update_data = User.model_validate({**user.model_dump(), **update_values})
 | 
			
		||||
 | 
			
		||||
    await update_user_id(connection, update_values, user)
 | 
			
		||||
    await update_user_by_id(connection, update_values, user)
 | 
			
		||||
 | 
			
		||||
    user = await get_user_id(connection, user_id)
 | 
			
		||||
 | 
			
		||||
    user = await get_user_by_id(connection, user_id)
 | 
			
		||||
 | 
			
		||||
    return user
 | 
			
		||||
 | 
			
		||||
@api_router.delete("/{user_id}", response_model=User)
 | 
			
		||||
async def delete_account(
 | 
			
		||||
                        user_id: int,
 | 
			
		||||
                        request: Request,
 | 
			
		||||
                        connection: AsyncConnection = Depends(get_connection_dep)
 | 
			
		||||
                    ):
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@api_router.delete("/{user_id}")
 | 
			
		||||
async def delete_account(user_id: int, request: Request, connection: AsyncConnection = Depends(get_connection_dep)):
 | 
			
		||||
    current_user = request.state.current_user
 | 
			
		||||
 | 
			
		||||
    authorize_user = await db_user_role_validation(connection, current_user)
 | 
			
		||||
 | 
			
		||||
    user = await get_user_id(connection, user_id)
 | 
			
		||||
    user = await get_user_by_id(connection, user_id)
 | 
			
		||||
    if user is None:
 | 
			
		||||
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Account not found")
 | 
			
		||||
 | 
			
		||||
    user_update = UserUpdate(status=Status.DELETED.value)
 | 
			
		||||
    user_update = UserUpdate(status=AccountStatus.DELETED.value)
 | 
			
		||||
 | 
			
		||||
    update_values = update_user_data_changes(user_update, user)
 | 
			
		||||
 | 
			
		||||
    if update_values is None:
 | 
			
		||||
        return user
 | 
			
		||||
 | 
			
		||||
    await update_user_id(connection, update_values, user)
 | 
			
		||||
 | 
			
		||||
    user = await get_user_id(connection, user_id)
 | 
			
		||||
    await update_user_by_id(connection, update_values, user)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    user = await get_user_by_id(connection, user_id)
 | 
			
		||||
 | 
			
		||||
    return user
 | 
			
		||||
 
 | 
			
		||||
@@ -2,9 +2,7 @@ from datetime import datetime, timedelta, timezone
 | 
			
		||||
 | 
			
		||||
from fastapi import (
 | 
			
		||||
    APIRouter,
 | 
			
		||||
    Body,
 | 
			
		||||
    Depends,
 | 
			
		||||
    Form,
 | 
			
		||||
    HTTPException,
 | 
			
		||||
    Request,
 | 
			
		||||
    Response,
 | 
			
		||||
@@ -24,7 +22,7 @@ from api.services.auth import authenticate_user
 | 
			
		||||
 | 
			
		||||
from api.db.logic.auth import add_new_refresh_token, upgrade_old_refresh_token
 | 
			
		||||
 | 
			
		||||
from api.schemas.endpoints.auth import Auth, AccessToken
 | 
			
		||||
from api.schemas.endpoints.auth import Auth, Access
 | 
			
		||||
 | 
			
		||||
api_router = APIRouter(
 | 
			
		||||
    prefix="/auth",
 | 
			
		||||
@@ -50,7 +48,7 @@ def get_config():
 | 
			
		||||
    return Settings()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@api_router.post("")
 | 
			
		||||
@api_router.post("", response_model=Access)
 | 
			
		||||
async def login_for_access_token(
 | 
			
		||||
    user: Auth,
 | 
			
		||||
    response: Response,
 | 
			
		||||
@@ -85,10 +83,11 @@ async def login_for_access_token(
 | 
			
		||||
 | 
			
		||||
    Authorize.set_refresh_cookies(refresh_token)
 | 
			
		||||
 | 
			
		||||
    return AccessToken(access_token=access_token)
 | 
			
		||||
    return Access(access_token=access_token)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@api_router.post("/refresh")
 | 
			
		||||
 | 
			
		||||
@api_router.post("/refresh",response_model=Access)
 | 
			
		||||
async def refresh(
 | 
			
		||||
    request: Request, connection: AsyncConnection = Depends(get_connection_dep), Authorize: AuthJWT = Depends()
 | 
			
		||||
):
 | 
			
		||||
@@ -114,4 +113,4 @@ async def refresh(
 | 
			
		||||
 | 
			
		||||
    new_access_token = Authorize.create_access_token(subject=current_user, expires_time=access_token_expires)
 | 
			
		||||
 | 
			
		||||
    return AccessToken(access_token=new_access_token)
 | 
			
		||||
    return Access(access_token=new_access_token)
 | 
			
		||||
 
 | 
			
		||||
@@ -14,10 +14,11 @@ from sqlalchemy.ext.asyncio import AsyncConnection
 | 
			
		||||
 | 
			
		||||
from api.db.connection.session import get_connection_dep
 | 
			
		||||
 | 
			
		||||
from api.db.logic.keyring import get_key_id, create_key, update_key_id
 | 
			
		||||
from api.db.logic.keyring import get_key_by_id,create_key,update_key_by_id
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
from api.schemas.account.account import Status
 | 
			
		||||
 | 
			
		||||
from api.db.tables.account import KeyStatus
 | 
			
		||||
from api.schemas.endpoints.account_keyring import AccountKeyringUpdate
 | 
			
		||||
 | 
			
		||||
from api.schemas.account.account_keyring import AccountKeyring
 | 
			
		||||
@@ -32,13 +33,18 @@ api_router = APIRouter(
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@api_router.get("/{user_id}/{key_id}")
 | 
			
		||||
async def get_keyring(key_id: str, request: Request, connection: AsyncConnection = Depends(get_connection_dep)):
 | 
			
		||||
@api_router.get("/{user_id}/{key_id}", response_model=AccountKeyring)
 | 
			
		||||
async def get_keyring(
 | 
			
		||||
                    key_id: str,
 | 
			
		||||
                    request: Request,
 | 
			
		||||
                    connection: AsyncConnection = Depends(get_connection_dep)
 | 
			
		||||
                    ):
 | 
			
		||||
 | 
			
		||||
    current_user = request.state.current_user
 | 
			
		||||
 | 
			
		||||
    authorize_user = await db_user_role_validation(connection, current_user)
 | 
			
		||||
 | 
			
		||||
    keyring = await get_key_id(connection, key_id)
 | 
			
		||||
    keyring = await get_key_by_id(connection, key_id)
 | 
			
		||||
 | 
			
		||||
    if keyring is None:
 | 
			
		||||
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Key not found")
 | 
			
		||||
@@ -46,7 +52,7 @@ async def get_keyring(key_id: str, request: Request, connection: AsyncConnection
 | 
			
		||||
    return keyring
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@api_router.post("/{user_id}/{key_id}")
 | 
			
		||||
@api_router.post("/{user_id}/{key_id}", response_model=AccountKeyring)
 | 
			
		||||
async def create_keyring(
 | 
			
		||||
    user_id: int,
 | 
			
		||||
    key_id: str,
 | 
			
		||||
@@ -58,15 +64,11 @@ async def create_keyring(
 | 
			
		||||
 | 
			
		||||
    authorize_user = await db_user_role_validation(connection, current_user)
 | 
			
		||||
 | 
			
		||||
    keyring = await get_key_id(connection, key_id)
 | 
			
		||||
    keyring = await get_key_by_id(connection, key_id)
 | 
			
		||||
 | 
			
		||||
    if keyring is None:
 | 
			
		||||
        user_new = await create_key(
 | 
			
		||||
            connection,
 | 
			
		||||
            key,
 | 
			
		||||
            key_id,
 | 
			
		||||
        )
 | 
			
		||||
        return user_new
 | 
			
		||||
        keyring_new = await create_key(connection,key, key_id, )
 | 
			
		||||
        return keyring_new
 | 
			
		||||
 | 
			
		||||
    else:
 | 
			
		||||
        raise HTTPException(
 | 
			
		||||
@@ -74,7 +76,7 @@ async def create_keyring(
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@api_router.put("/{user_id}/{key_id}")
 | 
			
		||||
@api_router.put("/{user_id}/{key_id}", response_model=AccountKeyring)
 | 
			
		||||
async def update_keyring(
 | 
			
		||||
    user_id: int,
 | 
			
		||||
    key_id: str,
 | 
			
		||||
@@ -86,7 +88,7 @@ async def update_keyring(
 | 
			
		||||
 | 
			
		||||
    authorize_user = await db_user_role_validation(connection, current_user)
 | 
			
		||||
 | 
			
		||||
    keyring = await get_key_id(connection, key_id)
 | 
			
		||||
    keyring = await get_key_by_id(connection, key_id)
 | 
			
		||||
    if keyring is None:
 | 
			
		||||
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="keyring not found")
 | 
			
		||||
 | 
			
		||||
@@ -97,14 +99,14 @@ async def update_keyring(
 | 
			
		||||
 | 
			
		||||
    keyring_update_data = AccountKeyring.model_validate({**keyring.model_dump(), **update_values})
 | 
			
		||||
 | 
			
		||||
    await update_key_id(connection, update_values, keyring)
 | 
			
		||||
    await update_key_by_id(connection, update_values, keyring)
 | 
			
		||||
 | 
			
		||||
    keyring = await get_key_id(connection, key_id)
 | 
			
		||||
 | 
			
		||||
    keyring = await get_key_by_id(connection, key_id)
 | 
			
		||||
 | 
			
		||||
    return keyring
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@api_router.delete("/{user_id}/{key_id}")
 | 
			
		||||
@api_router.delete("/{user_id}/{key_id}", response_model=AccountKeyring)
 | 
			
		||||
async def delete_keyring(
 | 
			
		||||
    user_id: int, key_id: str, request: Request, connection: AsyncConnection = Depends(get_connection_dep)
 | 
			
		||||
):
 | 
			
		||||
@@ -112,19 +114,20 @@ async def delete_keyring(
 | 
			
		||||
 | 
			
		||||
    authorize_user = await db_user_role_validation(connection, current_user)
 | 
			
		||||
 | 
			
		||||
    keyring = await get_key_id(connection, key_id)
 | 
			
		||||
    keyring = await get_key_by_id(connection, key_id)
 | 
			
		||||
    if keyring is None:
 | 
			
		||||
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="keyring not found")
 | 
			
		||||
 | 
			
		||||
    keyring_update = AccountKeyringUpdate(status=Status.DELETED.value)
 | 
			
		||||
    keyring_update = AccountKeyringUpdate(status=KeyStatus.DELETED.value)
 | 
			
		||||
 | 
			
		||||
    update_values = update_key_data_changes(keyring_update, keyring)
 | 
			
		||||
 | 
			
		||||
    if update_values is None:
 | 
			
		||||
        return keyring
 | 
			
		||||
 | 
			
		||||
    await update_key_id(connection, update_values, keyring)
 | 
			
		||||
    await update_key_by_id(connection, update_values, keyring)
 | 
			
		||||
 | 
			
		||||
    keyring = await get_key_id(connection, key_id)
 | 
			
		||||
 | 
			
		||||
    keyring = await get_key_by_id(connection, key_id)
 | 
			
		||||
 | 
			
		||||
    return keyring
 | 
			
		||||
 
 | 
			
		||||
@@ -13,10 +13,11 @@ 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_id, update_user_id, get_user_login
 | 
			
		||||
from api.db.logic.account import get_user_by_id, update_user_by_id,get_user_by_login
 | 
			
		||||
from api.services.update_data_validation import update_user_data_changes
 | 
			
		||||
 | 
			
		||||
from api.schemas.endpoints.account import UserUpdate
 | 
			
		||||
from api.schemas.account.account import User
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
api_router = APIRouter(
 | 
			
		||||
@@ -25,7 +26,7 @@ api_router = APIRouter(
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@api_router.get("")
 | 
			
		||||
@api_router.get("",response_model=User)
 | 
			
		||||
async def get_profile(
 | 
			
		||||
    request: Request,
 | 
			
		||||
    connection: AsyncConnection = Depends(get_connection_dep),
 | 
			
		||||
@@ -33,7 +34,7 @@ async def get_profile(
 | 
			
		||||
    # Извлекаем текущего пользователя из request.state
 | 
			
		||||
    current_user = request.state.current_user
 | 
			
		||||
 | 
			
		||||
    user = await get_user_login(connection, 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")
 | 
			
		||||
@@ -41,7 +42,7 @@ async def get_profile(
 | 
			
		||||
    return user
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@api_router.put("")
 | 
			
		||||
@api_router.put("",response_model=User)
 | 
			
		||||
async def update_profile(
 | 
			
		||||
    request: Request,
 | 
			
		||||
    user_updata: UserUpdate,
 | 
			
		||||
@@ -49,7 +50,7 @@ async def update_profile(
 | 
			
		||||
):
 | 
			
		||||
    current_user = request.state.current_user
 | 
			
		||||
 | 
			
		||||
    user = await get_user_login(connection, 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")
 | 
			
		||||
 | 
			
		||||
@@ -59,9 +60,9 @@ async def update_profile(
 | 
			
		||||
        if update_values is None:
 | 
			
		||||
            return user
 | 
			
		||||
 | 
			
		||||
        await update_user_id(connection, update_values, user)
 | 
			
		||||
            await update_user_by_id(connection, update_values, user)
 | 
			
		||||
 | 
			
		||||
        user = await get_user_id(connection, user.id)
 | 
			
		||||
            user = await get_user_by_id(connection, user.id)
 | 
			
		||||
 | 
			
		||||
        return user
 | 
			
		||||
    else:
 | 
			
		||||
 
 | 
			
		||||
@@ -1,37 +1,18 @@
 | 
			
		||||
import datetime
 | 
			
		||||
from enum import Enum
 | 
			
		||||
from datetime import datetime
 | 
			
		||||
from typing import Optional
 | 
			
		||||
from pydantic import EmailStr, Field
 | 
			
		||||
 | 
			
		||||
from api.schemas.base import Base
 | 
			
		||||
from pydantic import BaseModel, EmailStr, Field
 | 
			
		||||
from api.db.tables.account import AccountRole,AccountStatus
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# Модель для хранения информации из запроса
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class Role(Enum):
 | 
			
		||||
    OWNER = "OWNER"
 | 
			
		||||
    ADMIN = "ADMIN"
 | 
			
		||||
    EDITOR = "EDITOR"
 | 
			
		||||
    VIEWER = "VIEWER"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class Status(Enum):
 | 
			
		||||
    ACTIVE = "ACTIVE"
 | 
			
		||||
    DISABLED = "DISABLED"
 | 
			
		||||
    BLOCKED = "BLOCKED"
 | 
			
		||||
    DELETED = "DELETED"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class User(Base):
 | 
			
		||||
class User(BaseModel):
 | 
			
		||||
    id: Optional[int] = None
 | 
			
		||||
    name: str = Field(..., max_length=100)
 | 
			
		||||
    login: str = Field(..., max_length=100)
 | 
			
		||||
    email: Optional[EmailStr] = Field(None, max_length=100)  # Электронная почта (может быть None)
 | 
			
		||||
    bind_tenant_id: Optional[str] = Field(None, max_length=40)
 | 
			
		||||
    role: Role
 | 
			
		||||
    role: AccountRole
 | 
			
		||||
    meta: dict
 | 
			
		||||
    creator_id: Optional[int] = None
 | 
			
		||||
    created_at: datetime
 | 
			
		||||
    status: Status
 | 
			
		||||
    status: AccountStatus
 | 
			
		||||
 
 | 
			
		||||
@@ -1,33 +1,15 @@
 | 
			
		||||
import datetime
 | 
			
		||||
from enum import Enum
 | 
			
		||||
from typing import Optional, Dict
 | 
			
		||||
from pydantic import Field
 | 
			
		||||
from typing import Optional
 | 
			
		||||
from pydantic import BaseModel, Field
 | 
			
		||||
from datetime import datetime
 | 
			
		||||
 | 
			
		||||
from api.schemas.base import Base
 | 
			
		||||
from api.db.tables.account import KeyType,KeyStatus
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# Модель для хранения информации из запроса
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class TypeKey(Enum):
 | 
			
		||||
    PASSWORD = "PASSWORD"
 | 
			
		||||
    ACCESS_TOKEN = "ACCESS_TOKEN"
 | 
			
		||||
    REFRESH_TOKEN = "REFRESH_TOKEN"
 | 
			
		||||
    API_KEY = "API_KEY"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class StatusKey(Enum):
 | 
			
		||||
    ACTIVE = "ACTIVE"
 | 
			
		||||
    EXPIRED = "EXPIRED"
 | 
			
		||||
    DELETED = "DELETED"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class AccountKeyring(Base):
 | 
			
		||||
class AccountKeyring(BaseModel):
 | 
			
		||||
    owner_id: int
 | 
			
		||||
    key_type: TypeKey  # Используем тот же KeyType
 | 
			
		||||
    key_id: Optional[str] = Field(None, max_length=40)  # Изменено на None как default
 | 
			
		||||
    key_type: KeyType
 | 
			
		||||
    key_id: Optional[str] = Field(None, max_length=40)
 | 
			
		||||
    key_value: str = Field(..., max_length=255)
 | 
			
		||||
    created_at: datetime
 | 
			
		||||
    expiry: Optional[datetime] = None
 | 
			
		||||
    status: StatusKey
 | 
			
		||||
    status: KeyStatus
 | 
			
		||||
 
 | 
			
		||||
@@ -1,36 +1,37 @@
 | 
			
		||||
from enum import Enum
 | 
			
		||||
from typing import Optional
 | 
			
		||||
from typing import Optional, List
 | 
			
		||||
from datetime import datetime
 | 
			
		||||
from pydantic import EmailStr, Field
 | 
			
		||||
from pydantic import BaseModel, EmailStr, Field, TypeAdapter
 | 
			
		||||
 | 
			
		||||
from api.schemas.base import Base
 | 
			
		||||
from api.db.tables.account import AccountRole,AccountStatus
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# Таблица для получения информации из запроса
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class Role(Enum):
 | 
			
		||||
    OWNER = "OWNER"
 | 
			
		||||
    ADMIN = "ADMIN"
 | 
			
		||||
    EDITOR = "EDITOR"
 | 
			
		||||
    VIEWER = "VIEWER"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class Status(Enum):
 | 
			
		||||
    ACTIVE = "ACTIVE"
 | 
			
		||||
    DISABLED = "DISABLED"
 | 
			
		||||
    BLOCKED = "BLOCKED"
 | 
			
		||||
    DELETED = "DELETED"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class UserUpdate(Base):
 | 
			
		||||
class UserUpdate(BaseModel):
 | 
			
		||||
    id: Optional[int] = None
 | 
			
		||||
    name: Optional[str] = Field(None, max_length=100)
 | 
			
		||||
    login: Optional[str] = Field(None, max_length=100)
 | 
			
		||||
    email: Optional[EmailStr] = None
 | 
			
		||||
    bind_tenant_id: Optional[str] = Field(None, max_length=40)
 | 
			
		||||
    role: Optional[Role] = None
 | 
			
		||||
    role: Optional[AccountRole] = None
 | 
			
		||||
    meta: Optional[dict] = None
 | 
			
		||||
    creator_id: Optional[int] = None
 | 
			
		||||
    created_at: Optional[datetime] = None
 | 
			
		||||
    status: Optional[Status] = None
 | 
			
		||||
    status: Optional[AccountStatus] = None
 | 
			
		||||
 | 
			
		||||
class AllUser(BaseModel):
 | 
			
		||||
    id: int
 | 
			
		||||
    name: str
 | 
			
		||||
    login: str
 | 
			
		||||
    email: Optional[EmailStr] = None
 | 
			
		||||
    bind_tenant_id: Optional[str] = None
 | 
			
		||||
    role: AccountRole
 | 
			
		||||
    created_at: datetime
 | 
			
		||||
    status: AccountStatus
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class AllUserResponse(BaseModel):
 | 
			
		||||
    users: List[AllUser]
 | 
			
		||||
    amount_count: int
 | 
			
		||||
    amount_pages: int
 | 
			
		||||
 | 
			
		||||
all_user_adapter = TypeAdapter(List[AllUser])
 | 
			
		||||
 
 | 
			
		||||
@@ -1,33 +1,15 @@
 | 
			
		||||
import datetime
 | 
			
		||||
from enum import Enum
 | 
			
		||||
from typing import Optional
 | 
			
		||||
from pydantic import Field
 | 
			
		||||
from pydantic import BaseModel, Field
 | 
			
		||||
from datetime import datetime
 | 
			
		||||
 | 
			
		||||
from api.schemas.base import Base
 | 
			
		||||
from api.db.tables.account import KeyType,KeyStatus
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# Таблица для получения информации из запроса
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class TypeKey(Enum):
 | 
			
		||||
    PASSWORD = "PASSWORD"
 | 
			
		||||
    ACCESS_TOKEN = "ACCESS_TOKEN"
 | 
			
		||||
    REFRESH_TOKEN = "REFRESH_TOKEN"
 | 
			
		||||
    API_KEY = "API_KEY"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class StatusKey(Enum):
 | 
			
		||||
    ACTIVE = "ACTIVE"
 | 
			
		||||
    EXPIRED = "EXPIRED"
 | 
			
		||||
    DELETED = "DELETED"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class AccountKeyringUpdate(Base):
 | 
			
		||||
class AccountKeyringUpdate(BaseModel):
 | 
			
		||||
    owner_id: Optional[int] = None
 | 
			
		||||
    key_type: Optional[TypeKey] = None
 | 
			
		||||
    key_type: Optional[KeyType] = None
 | 
			
		||||
    key_id: Optional[str] = Field(None, max_length=40)
 | 
			
		||||
    key_value: Optional[str] = Field(None, max_length=255)
 | 
			
		||||
    created_at: Optional[datetime] = None
 | 
			
		||||
    expiry: Optional[datetime] = None
 | 
			
		||||
    status: Optional[StatusKey] = None
 | 
			
		||||
    status: Optional[KeyStatus] = None
 | 
			
		||||
 
 | 
			
		||||
@@ -1,17 +1,14 @@
 | 
			
		||||
from api.schemas.base import Base
 | 
			
		||||
 | 
			
		||||
from api.schemas.base import BaseModel
 | 
			
		||||
 | 
			
		||||
# Таблица для получения информации из запроса
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class Auth(Base):
 | 
			
		||||
class Auth(BaseModel):
 | 
			
		||||
    login: str
 | 
			
		||||
    password: str
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class AccessToken(Base):
 | 
			
		||||
    access_token: str
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class Refresh(Base):
 | 
			
		||||
class Refresh(BaseModel,):
 | 
			
		||||
    refresh_token: str
 | 
			
		||||
 | 
			
		||||
class Access(BaseModel):
 | 
			
		||||
    access_token: str
 | 
			
		||||
 
 | 
			
		||||
@@ -3,7 +3,7 @@ from typing import Dict, Any
 | 
			
		||||
from datetime import datetime
 | 
			
		||||
from enum import Enum
 | 
			
		||||
 | 
			
		||||
from api.schemas.base import Base
 | 
			
		||||
from api.schemas.base import BaseModel
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class State(Enum):
 | 
			
		||||
@@ -17,7 +17,7 @@ class Status(Enum):
 | 
			
		||||
    DELETED = "Deleted"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class ListEvent(Base):
 | 
			
		||||
class ListEvent(BaseModel):
 | 
			
		||||
    id: int
 | 
			
		||||
    name: str = Field(..., max_length=40)
 | 
			
		||||
    title: str = Field(..., max_length=64)
 | 
			
		||||
 
 | 
			
		||||
@@ -3,15 +3,17 @@ from sqlalchemy.ext.asyncio import AsyncConnection
 | 
			
		||||
from api.db.logic.auth import get_user
 | 
			
		||||
 | 
			
		||||
# # from backend.schemas.users.token import TokenData
 | 
			
		||||
from api.schemas.account.account import User, Status
 | 
			
		||||
from api.schemas.account.account import User
 | 
			
		||||
from api.db.tables.account import AccountStatus
 | 
			
		||||
 | 
			
		||||
from api.utils.hasher import Hasher
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
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 != Status.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
 | 
			
		||||
 
 | 
			
		||||
@@ -1,7 +1,9 @@
 | 
			
		||||
from enum import Enum
 | 
			
		||||
from typing import Optional
 | 
			
		||||
from api.schemas.endpoints.account import UserUpdate, Role, Status
 | 
			
		||||
from api.schemas.endpoints.account_keyring import AccountKeyringUpdate, StatusKey, TypeKey
 | 
			
		||||
from api.schemas.endpoints.account import UserUpdate
 | 
			
		||||
from api.db.tables.account import KeyType,KeyStatus
 | 
			
		||||
from api.schemas.endpoints.account_keyring import AccountKeyringUpdate
 | 
			
		||||
from api.db.tables.account import AccountRole,AccountStatus
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def update_user_data_changes(update_data: UserUpdate, user) -> Optional[dict]:
 | 
			
		||||
@@ -18,7 +20,7 @@ def update_user_data_changes(update_data: UserUpdate, user) -> Optional[dict]:
 | 
			
		||||
        if value is None:
 | 
			
		||||
            continue
 | 
			
		||||
 | 
			
		||||
        if isinstance(value, (Role, Status)):
 | 
			
		||||
        if isinstance(value, (AccountRole, AccountStatus)):
 | 
			
		||||
            update_values[field] = value.value
 | 
			
		||||
        else:
 | 
			
		||||
            update_values[field] = value
 | 
			
		||||
@@ -52,7 +54,7 @@ def update_key_data_changes(update_data: AccountKeyringUpdate, key) -> Optional[
 | 
			
		||||
        if value is None:
 | 
			
		||||
            continue
 | 
			
		||||
 | 
			
		||||
        if isinstance(value, (TypeKey, StatusKey)):
 | 
			
		||||
        if isinstance(value, (KeyType, KeyStatus)):
 | 
			
		||||
            update_values[field] = value.value
 | 
			
		||||
        else:
 | 
			
		||||
            update_values[field] = value
 | 
			
		||||
 
 | 
			
		||||
@@ -2,12 +2,16 @@ from fastapi import (
 | 
			
		||||
    HTTPException,
 | 
			
		||||
    status,
 | 
			
		||||
)
 | 
			
		||||
from api.db.logic.account import get_user_login
 | 
			
		||||
from api.schemas.account.account import Role, Status
 | 
			
		||||
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_login(connection, current_user)
 | 
			
		||||
    if authorize_user.role not in {Role.OWNER, Role.ADMIN}:
 | 
			
		||||
        raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="You do not have enough permissions")
 | 
			
		||||
 | 
			
		||||
    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")
 | 
			
		||||
    return authorize_user
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user