From ad0a4837fcd3fb05357185278fd3796f727118d8 Mon Sep 17 00:00:00 2001 From: Vladislav Syrochkin Date: Fri, 27 Jun 2025 13:31:32 +0500 Subject: [PATCH] feat(api): add update password --- api/api/db/logic/keyring.py | 20 ++++++++++++++++++-- api/api/endpoints/account.py | 5 ++++- api/api/schemas/endpoints/account.py | 1 + client/src/types/openapi-types.ts | 4 +++- 4 files changed, 26 insertions(+), 4 deletions(-) diff --git a/api/api/db/logic/keyring.py b/api/api/db/logic/keyring.py index 4856d0a..e1b21b2 100644 --- a/api/api/db/logic/keyring.py +++ b/api/api/db/logic/keyring.py @@ -2,7 +2,7 @@ from datetime import datetime, timedelta, timezone from enum import Enum from typing import Optional -from sqlalchemy import insert, select +from sqlalchemy import insert, select, update from sqlalchemy.ext.asyncio import AsyncConnection from api.db.tables.account import account_keyring_table, KeyStatus, KeyType @@ -80,7 +80,23 @@ async def create_password_key(connection: AsyncConnection, password: str | None, key_value=hasher.hash_data(password), created_at=datetime.now(timezone.utc), expiry=datetime.now(timezone.utc) + timedelta(days=365), - status=KeyStatus.ACTIVE.value, + status=KeyStatus.ACTIVE, ) await connection.execute(stmt) await connection.commit() + + +async def update_password_key(connection: AsyncConnection, owner_id: int, password: str): + stmt = select(account_keyring_table).where(account_keyring_table.c.owner_id == owner_id) + result = await connection.execute(stmt) + keyring = result.one_or_none() + if not keyring: + await create_password_key(connection, password, owner_id) + else: + stmt = ( + update(account_keyring_table) + .values(key_value=hasher.hash_data(password), expiry=datetime.now(timezone.utc) + timedelta(days=365)) + .where(account_keyring_table.c.owner_id == owner_id) + ) + await connection.execute(stmt) + await connection.commit() diff --git a/api/api/endpoints/account.py b/api/api/endpoints/account.py index 9c34096..5ce0da4 100644 --- a/api/api/endpoints/account.py +++ b/api/api/endpoints/account.py @@ -14,7 +14,7 @@ from api.db.logic.account import ( get_user_by_login, update_user_by_id, ) -from api.db.logic.keyring import create_password_key +from api.db.logic.keyring import create_password_key, update_password_key from api.db.tables.account import AccountStatus from api.schemas.account.account import User from api.schemas.base import bearer_schema @@ -95,6 +95,9 @@ async def update_account( if user is None: raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Account not found") + if user_update.password is not None: + await update_password_key(connection, user.id, user_update.password) + update_values = update_user_data_changes(user_update, user) if update_values is None: diff --git a/api/api/schemas/endpoints/account.py b/api/api/schemas/endpoints/account.py index 52afb63..5ec16b0 100644 --- a/api/api/schemas/endpoints/account.py +++ b/api/api/schemas/endpoints/account.py @@ -12,6 +12,7 @@ class UserUpdate(Base): name: Optional[str] = Field(None, max_length=100) login: Optional[str] = Field(None, max_length=100) email: Optional[EmailStr] = None + password: Optional[str] = None bind_tenant_id: Optional[str] = Field(None, max_length=40) role: Optional[AccountRole] = None meta: Optional[dict] = None diff --git a/client/src/types/openapi-types.ts b/client/src/types/openapi-types.ts index c203144..c9eebe6 100644 --- a/client/src/types/openapi-types.ts +++ b/client/src/types/openapi-types.ts @@ -280,6 +280,8 @@ export interface components { login?: string | null; /** Email */ email?: string | null; + /** Password */ + password?: string | null; /** Bindtenantid */ bindTenantId?: string | null; role?: components["schemas"]["AccountRole"] | null; @@ -534,7 +536,7 @@ export interface operations { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["User"]; + "application/json": components["schemas"]["UserUpdate"]; }; }; /** @description Validation Error */