feat: add new column and delete old

This commit is contained in:
2026-05-13 11:23:59 +03:00
parent caa84525b1
commit 7019f14af2
14 changed files with 71 additions and 71 deletions

View File

@@ -19,7 +19,7 @@ class IUserRepository(ABC):
raise NotImplementedError raise NotImplementedError
@abstractmethod @abstractmethod
async def set_crypto_wallet(self, user_id: str, wallet_address: str) -> UserEntity: async def set_encrypted_mnemonic(self, user_id: str, encrypted_mnemonic: str) -> UserEntity:
raise NotImplementedError raise NotImplementedError
@abstractmethod @abstractmethod

View File

@@ -1,7 +1,7 @@
from src.application.commands.get_me import GetMeCommand from src.application.commands.get_me import GetMeCommand
from src.application.commands.set_phone import SetPhoneCommand from src.application.commands.set_phone import SetPhoneCommand
from src.application.commands.set_crypto_wallet_start import SetCryptoWalletStartCommand from src.application.commands.set_encrypted_mnemonic_start import SetEncryptedMnemonicStartCommand
from src.application.commands.set_crypto_wallet_complete import SetCryptoWalletCompleteCommand from src.application.commands.set_encrypted_mnemonic_complete import SetEncryptedMnemonicCompleteCommand
from src.application.commands.update_bank_details_start import UpdateBankDetailsStartCommand from src.application.commands.update_bank_details_start import UpdateBankDetailsStartCommand
from src.application.commands.update_bank_details_complete import UpdateBankDetailsCompleteCommand from src.application.commands.update_bank_details_complete import UpdateBankDetailsCompleteCommand
from src.application.commands.change_password_start import ChangePasswordStartCommand from src.application.commands.change_password_start import ChangePasswordStartCommand

View File

@@ -5,7 +5,7 @@ from src.application.domain.exceptions import ApplicationException
from src.infrastructure.database.decorators import transactional from src.infrastructure.database.decorators import transactional
class SetCryptoWalletCompleteCommand: class SetEncryptedMnemonicCompleteCommand:
def __init__( def __init__(
self, self,
unit_of_work: IUnitOfWork, unit_of_work: IUnitOfWork,
@@ -19,42 +19,42 @@ class SetCryptoWalletCompleteCommand:
self._logger = logger self._logger = logger
@transactional @transactional
async def __call__(self, *, user_id: str, code: str, wallet_address: str) -> UserEntity: async def __call__(self, *, user_id: str, code: str, encrypted_mnemonic: str) -> UserEntity:
code = (code or '').strip() code = (code or '').strip()
USER_PREFIX = 'crypto_wallet:user:' USER_PREFIX = 'encrypted_mnemonic:user:'
CODE_PREFIX = 'crypto_wallet:code:' CODE_PREFIX = 'encrypted_mnemonic:code:'
user_key = f'{USER_PREFIX}{user_id}' user_key = f'{USER_PREFIX}{user_id}'
code_key = f'{CODE_PREFIX}{code}' code_key = f'{CODE_PREFIX}{code}'
user = await self._unit_of_work.user_repository.get_user_by_id(user_id=user_id) user = await self._unit_of_work.user_repository.get_user_by_id(user_id=user_id)
if user.crypto_wallet is not None: if user.encrypted_mnemonic is not None:
self._logger.info(f'Crypto wallet already set for user_id={user_id}') self._logger.info(f'Encrypted mnemonic already set for user_id={user_id}')
raise ApplicationException(409, 'Crypto wallet already set and cannot be changed') raise ApplicationException(409, 'Encrypted mnemonic already set and cannot be changed')
cached_user_id = await self._cache.get(code_key) cached_user_id = await self._cache.get(code_key)
if not cached_user_id: if not cached_user_id:
self._logger.info(f'Crypto wallet set failed: code not found (user_id={user_id})') self._logger.info(f'Encrypted mnemonic set failed: code not found (user_id={user_id})')
raise ApplicationException(400, 'Invalid or expired code') raise ApplicationException(400, 'Invalid or expired code')
if cached_user_id != user_id: if cached_user_id != user_id:
self._logger.info(f'Crypto wallet set failed: code-user mismatch (user_id={user_id})') self._logger.info(f'Encrypted mnemonic set failed: code-user mismatch (user_id={user_id})')
raise ApplicationException(400, 'Invalid or expired code') raise ApplicationException(400, 'Invalid or expired code')
code_hash = await self._cache.get(user_key) code_hash = await self._cache.get(user_key)
if not code_hash: if not code_hash:
self._logger.info(f'Crypto wallet set failed: user key missing (user_id={user_id})') self._logger.info(f'Encrypted mnemonic set failed: user key missing (user_id={user_id})')
raise ApplicationException(400, 'Invalid or expired code') raise ApplicationException(400, 'Invalid or expired code')
ok = await self._hash_service.verify(hashed_value=code_hash, plain_value=code) ok = await self._hash_service.verify(hashed_value=code_hash, plain_value=code)
if not ok: if not ok:
self._logger.info(f'Crypto wallet set failed: code hash mismatch (user_id={user_id})') self._logger.info(f'Encrypted mnemonic set failed: code hash mismatch (user_id={user_id})')
raise ApplicationException(400, 'Invalid or expired code') raise ApplicationException(400, 'Invalid or expired code')
user = await self._unit_of_work.user_repository.set_crypto_wallet( user = await self._unit_of_work.user_repository.set_encrypted_mnemonic(
user_id=user_id, user_id=user_id,
wallet_address=wallet_address, encrypted_mnemonic=encrypted_mnemonic,
) )
await self._cache.set_user(user_id, user) await self._cache.set_user(user_id, user)
@@ -62,7 +62,7 @@ class SetCryptoWalletCompleteCommand:
await self._cache.delete(code_key) await self._cache.delete(code_key)
await self._cache.delete(user_key) await self._cache.delete(user_key)
except Exception as e: except Exception as e:
self._logger.warning(f'Crypto wallet set cleanup failed (user_id={user_id}): {e}') self._logger.warning(f'Encrypted mnemonic set cleanup failed (user_id={user_id}): {e}')
self._logger.info(f'Crypto wallet set for user_id={user_id}') self._logger.info(f'Encrypted mnemonic set for user_id={user_id}')
return user return user

View File

@@ -9,7 +9,7 @@ from src.infrastructure.context_vars import trace_id_var
from src.infrastructure.database.decorators import transactional from src.infrastructure.database.decorators import transactional
class SetCryptoWalletStartCommand: class SetEncryptedMnemonicStartCommand:
def __init__( def __init__(
self, self,
hash_service: IHashService, hash_service: IHashService,
@@ -30,15 +30,15 @@ class SetCryptoWalletStartCommand:
LOCK_TTL = 30 LOCK_TTL = 30
MAX_ATTEMPTS = 20 MAX_ATTEMPTS = 20
USER_PREFIX = 'crypto_wallet:user:' USER_PREFIX = 'encrypted_mnemonic:user:'
CODE_PREFIX = 'crypto_wallet:code:' CODE_PREFIX = 'encrypted_mnemonic:code:'
LOCK_PREFIX = 'crypto_wallet:lock:' LOCK_PREFIX = 'encrypted_mnemonic:lock:'
user = await self._unit_of_work.user_repository.get_user_by_id(user_id=user_id) user = await self._unit_of_work.user_repository.get_user_by_id(user_id=user_id)
if user.crypto_wallet is not None: if user.encrypted_mnemonic is not None:
self._logger.info(f'Crypto wallet already set for user_id={user_id}') self._logger.info(f'Encrypted mnemonic already set for user_id={user_id}')
raise ApplicationException(409, 'Crypto wallet already set and cannot be changed') raise ApplicationException(409, 'Encrypted mnemonic already set and cannot be changed')
if not user.email: if not user.email:
self._logger.warning(f'User {user_id} does not have an email address') self._logger.warning(f'User {user_id} does not have an email address')
@@ -51,7 +51,7 @@ class SetCryptoWalletStartCommand:
lock_key = f'{LOCK_PREFIX}{user_id}' lock_key = f'{LOCK_PREFIX}{user_id}'
locked = await self._cache.set_nx(lock_key, '1', ttl=LOCK_TTL) locked = await self._cache.set_nx(lock_key, '1', ttl=LOCK_TTL)
if not locked: if not locked:
self._logger.info(f'Crypto wallet set throttled by lock (user_id={user_id})') self._logger.info(f'Encrypted mnemonic set throttled by lock (user_id={user_id})')
raise ApplicationException(429, 'Too many requests. Please wait.') raise ApplicationException(429, 'Too many requests. Please wait.')
try: try:
@@ -59,7 +59,7 @@ class SetCryptoWalletStartCommand:
existing = await self._cache.get(user_key) existing = await self._cache.get(user_key)
if existing: if existing:
self._logger.info(f'Crypto wallet set denied: code already exists for user_id={user_id}') self._logger.info(f'Encrypted mnemonic set denied: code already exists for user_id={user_id}')
raise ApplicationException(429, 'Code already sent. Please wait before retrying.') raise ApplicationException(429, 'Code already sent. Please wait before retrying.')
for _ in range(MAX_ATTEMPTS): for _ in range(MAX_ATTEMPTS):
@@ -75,7 +75,7 @@ class SetCryptoWalletStartCommand:
saved = await self._cache.set(user_key, code_hash, ttl=TTL) saved = await self._cache.set(user_key, code_hash, ttl=TTL)
if not saved: if not saved:
await self._cache.delete(code_key) await self._cache.delete(code_key)
self._logger.error(f'Crypto wallet set failed: cannot save code hash for user_id={user_id}') self._logger.error(f'Encrypted mnemonic set failed: cannot save code hash for user_id={user_id}')
raise ApplicationException(503, 'Temporary error. Please try again.') raise ApplicationException(503, 'Temporary error. Please try again.')
message_id = str(ULID()) message_id = str(ULID())
@@ -95,12 +95,12 @@ class SetCryptoWalletStartCommand:
} }
message = { message = {
'event': 'crypto_wallet_set', 'event': 'encrypted_mnemonic_set',
'payload': payload, 'payload': payload,
'metadata': metadata, 'metadata': metadata,
} }
self._logger.info(f'Crypto wallet set code created for user_id={user_id}') self._logger.info(f'Encrypted mnemonic set code created for user_id={user_id}')
try: try:
await self._messanger.publish_to_queue( await self._messanger.publish_to_queue(
@@ -118,12 +118,12 @@ class SetCryptoWalletStartCommand:
except Exception as rollback_err: except Exception as rollback_err:
self._logger.error(f'Publish failed and rollback cache failed for user_id={user_id}: {str(rollback_err)}') self._logger.error(f'Publish failed and rollback cache failed for user_id={user_id}: {str(rollback_err)}')
self._logger.error(f'Failed to publish crypto wallet set email for user_id={user_id}: {str(exception)}') self._logger.error(f'Failed to publish encrypted mnemonic set email for user_id={user_id}: {str(exception)}')
raise ApplicationException(503, 'Temporary error. Please try again.') raise ApplicationException(503, 'Temporary error. Please try again.')
return True return True
self._logger.error(f'Crypto wallet set failed: code space exhausted for user_id={user_id}') self._logger.error(f'Encrypted mnemonic set failed: code space exhausted for user_id={user_id}')
raise ApplicationException(503, 'Temporary error. Please try again.') raise ApplicationException(503, 'Temporary error. Please try again.')
finally: finally:

View File

@@ -14,7 +14,7 @@ class UserEntity:
last_name: str | None = None last_name: str | None = None
birth_date: date | None = None birth_date: date | None = None
crypto_wallet: str | None = None encrypted_mnemonic: str | None = None
phone: str | None = None phone: str | None = None
passport_data: str | None = None passport_data: str | None = None

View File

@@ -37,7 +37,7 @@ class KeydbCache(ICache):
'middle_name': user.middle_name, 'middle_name': user.middle_name,
'last_name': user.last_name, 'last_name': user.last_name,
'birth_date': str(user.birth_date) if user.birth_date else None, 'birth_date': str(user.birth_date) if user.birth_date else None,
'crypto_wallet': user.crypto_wallet, 'encrypted_mnemonic': user.encrypted_mnemonic,
'phone': user.phone, 'phone': user.phone,
'passport_data': user.passport_data, 'passport_data': user.passport_data,
'inn': user.inn, 'inn': user.inn,

View File

@@ -1,6 +1,6 @@
from __future__ import annotations from __future__ import annotations
from sqlalchemy import Boolean,Date,String,DateTime from sqlalchemy import Boolean, Date, DateTime, String, Text
from sqlalchemy.orm import Mapped, mapped_column from sqlalchemy.orm import Mapped, mapped_column
from src.infrastructure.database.models.base import Base from src.infrastructure.database.models.base import Base
from src.infrastructure.database.models.mixins import UlidPrimaryKeyMixin, AuditTimestampsMixin, SoftDeleteMixin from src.infrastructure.database.models.mixins import UlidPrimaryKeyMixin, AuditTimestampsMixin, SoftDeleteMixin
@@ -17,7 +17,7 @@ class UserModel(Base, UlidPrimaryKeyMixin, AuditTimestampsMixin, SoftDeleteMixin
middle_name: Mapped[str | None] = mapped_column(String(128), nullable=True) middle_name: Mapped[str | None] = mapped_column(String(128), nullable=True)
birth_date: Mapped[Date | None] = mapped_column(Date, nullable=True) birth_date: Mapped[Date | None] = mapped_column(Date, nullable=True)
crypto_wallet: Mapped[str | None] = mapped_column(String(255), nullable=True) encrypted_mnemonic: Mapped[str | None] = mapped_column(Text, nullable=True)
phone: Mapped[str | None] = mapped_column(String(16), nullable=True) phone: Mapped[str | None] = mapped_column(String(16), nullable=True)
passport_data: Mapped[str | None] = mapped_column(String(255), nullable=True) passport_data: Mapped[str | None] = mapped_column(String(255), nullable=True)

View File

@@ -40,7 +40,7 @@ class UserRepository(IUserRepository):
middle_name=user.middle_name, middle_name=user.middle_name,
last_name=user.last_name, last_name=user.last_name,
birth_date=user.birth_date, birth_date=user.birth_date,
crypto_wallet=user.crypto_wallet, encrypted_mnemonic=user.encrypted_mnemonic,
phone=user.phone, phone=user.phone,
passport_data=user.passport_data, passport_data=user.passport_data,
inn=user.inn, inn=user.inn,
@@ -89,8 +89,8 @@ class UserRepository(IUserRepository):
) )
return await self._update_field(user_id, **payload) return await self._update_field(user_id, **payload)
async def set_crypto_wallet(self, user_id: str, wallet_address: str) -> UserEntity: async def set_encrypted_mnemonic(self, user_id: str, encrypted_mnemonic: str) -> UserEntity:
return await self._update_field(user_id, crypto_wallet=wallet_address) return await self._update_field(user_id, encrypted_mnemonic=encrypted_mnemonic)
async def get_password_hash(self, user_id: str) -> str: async def get_password_hash(self, user_id: str) -> str:
try: try:

View File

@@ -1,8 +1,8 @@
from src.presentation.dependencies.commands import ( from src.presentation.dependencies.commands import (
get_get_me_command, get_get_me_command,
get_set_phone_command, get_set_phone_command,
get_set_crypto_wallet_start_command, get_set_encrypted_mnemonic_start_command,
get_set_crypto_wallet_complete_command, get_set_encrypted_mnemonic_complete_command,
get_update_bank_details_start_command, get_update_bank_details_start_command,
get_update_bank_details_complete_command, get_update_bank_details_complete_command,
get_change_password_start_command, get_change_password_start_command,

View File

@@ -1,6 +1,6 @@
from fastapi import Depends from fastapi import Depends
from src.application.abstractions import IUnitOfWork from src.application.abstractions import IUnitOfWork
from src.application.commands import GetMeCommand, SetPhoneCommand, SetCryptoWalletStartCommand, SetCryptoWalletCompleteCommand, UpdateBankDetailsStartCommand, UpdateBankDetailsCompleteCommand, ChangePasswordStartCommand, ChangePasswordCompleteCommand, ChangeEmailStartCommand, ChangeEmailConfirmOldCommand, ChangeEmailCompleteCommand from src.application.commands import GetMeCommand, SetPhoneCommand, SetEncryptedMnemonicStartCommand, SetEncryptedMnemonicCompleteCommand, UpdateBankDetailsStartCommand, UpdateBankDetailsCompleteCommand, ChangePasswordStartCommand, ChangePasswordCompleteCommand, ChangeEmailStartCommand, ChangeEmailConfirmOldCommand, ChangeEmailCompleteCommand
from src.application.contracts import ILogger, ICache, IQueueMessanger, IHashService from src.application.contracts import ILogger, ICache, IQueueMessanger, IHashService
from src.presentation.dependencies.cache import get_cache from src.presentation.dependencies.cache import get_cache
from src.presentation.dependencies.logger import get_logger from src.presentation.dependencies.logger import get_logger
@@ -25,14 +25,14 @@ def get_set_phone_command(
return SetPhoneCommand(logger=logger, unit_of_work=unit_of_work, cache=cache) return SetPhoneCommand(logger=logger, unit_of_work=unit_of_work, cache=cache)
def get_set_crypto_wallet_start_command( def get_set_encrypted_mnemonic_start_command(
logger: ILogger = Depends(get_logger), logger: ILogger = Depends(get_logger),
unit_of_work: IUnitOfWork = Depends(get_unit_of_work), unit_of_work: IUnitOfWork = Depends(get_unit_of_work),
cache: ICache = Depends(get_cache), cache: ICache = Depends(get_cache),
messanger: IQueueMessanger = Depends(get_rabbit), messanger: IQueueMessanger = Depends(get_rabbit),
hash_service: IHashService = Depends(get_hash_service), hash_service: IHashService = Depends(get_hash_service),
) -> SetCryptoWalletStartCommand: ) -> SetEncryptedMnemonicStartCommand:
return SetCryptoWalletStartCommand( return SetEncryptedMnemonicStartCommand(
logger=logger, logger=logger,
unit_of_work=unit_of_work, unit_of_work=unit_of_work,
cache=cache, cache=cache,
@@ -41,13 +41,13 @@ def get_set_crypto_wallet_start_command(
) )
def get_set_crypto_wallet_complete_command( def get_set_encrypted_mnemonic_complete_command(
logger: ILogger = Depends(get_logger), logger: ILogger = Depends(get_logger),
unit_of_work: IUnitOfWork = Depends(get_unit_of_work), unit_of_work: IUnitOfWork = Depends(get_unit_of_work),
cache: ICache = Depends(get_cache), cache: ICache = Depends(get_cache),
hash_service: IHashService = Depends(get_hash_service), hash_service: IHashService = Depends(get_hash_service),
) -> SetCryptoWalletCompleteCommand: ) -> SetEncryptedMnemonicCompleteCommand:
return SetCryptoWalletCompleteCommand( return SetEncryptedMnemonicCompleteCommand(
logger=logger, logger=logger,
unit_of_work=unit_of_work, unit_of_work=unit_of_work,
cache=cache, cache=cache,

View File

@@ -30,7 +30,7 @@ async def me(
'middle_name': user.middle_name, 'middle_name': user.middle_name,
'last_name': user.last_name, 'last_name': user.last_name,
'birth_date': str(user.birth_date) if user.birth_date else None, 'birth_date': str(user.birth_date) if user.birth_date else None,
'crypto_wallet': user.crypto_wallet, 'encrypted_mnemonic': user.encrypted_mnemonic,
'phone': user.phone, 'phone': user.phone,
'passport_data': user.passport_data, 'passport_data': user.passport_data,
'inn': user.inn, 'inn': user.inn,

View File

@@ -1,13 +1,13 @@
from fastapi import APIRouter, Request, Depends from fastapi import APIRouter, Request, Depends
from fastapi.responses import ORJSONResponse from fastapi.responses import ORJSONResponse
from starlette import status from starlette import status
from src.application.commands import SetPhoneCommand, SetCryptoWalletStartCommand, SetCryptoWalletCompleteCommand, UpdateBankDetailsStartCommand, UpdateBankDetailsCompleteCommand, ChangePasswordStartCommand, ChangePasswordCompleteCommand, ChangeEmailStartCommand, ChangeEmailConfirmOldCommand, ChangeEmailCompleteCommand from src.application.commands import SetPhoneCommand, SetEncryptedMnemonicStartCommand, SetEncryptedMnemonicCompleteCommand, UpdateBankDetailsStartCommand, UpdateBankDetailsCompleteCommand, ChangePasswordStartCommand, ChangePasswordCompleteCommand, ChangeEmailStartCommand, ChangeEmailConfirmOldCommand, ChangeEmailCompleteCommand
from src.application.domain.dto import AuthContext from src.application.domain.dto import AuthContext
from src.presentation.decorators import require_access_token from src.presentation.decorators import require_access_token
from src.presentation.dependencies import ( from src.presentation.dependencies import (
get_set_phone_command, get_set_phone_command,
get_set_crypto_wallet_start_command, get_set_encrypted_mnemonic_start_command,
get_set_crypto_wallet_complete_command, get_set_encrypted_mnemonic_complete_command,
get_update_bank_details_start_command, get_update_bank_details_start_command,
get_update_bank_details_complete_command, get_update_bank_details_complete_command,
get_change_password_start_command, get_change_password_start_command,
@@ -16,7 +16,7 @@ from src.presentation.dependencies import (
get_change_email_confirm_old_command, get_change_email_confirm_old_command,
get_change_email_complete_command, get_change_email_complete_command,
) )
from src.presentation.schemas import SetPhoneRequest, CryptoWalletConfirmRequest, BankConfirmRequest, ChangePasswordConfirmRequest, ChangeEmailConfirmOldRequest, ChangeEmailCompleteRequest from src.presentation.schemas import SetPhoneRequest, EncryptedMnemonicConfirmRequest, BankConfirmRequest, ChangePasswordConfirmRequest, ChangeEmailConfirmOldRequest, ChangeEmailCompleteRequest
account_settings_router = APIRouter(prefix='/settings') account_settings_router = APIRouter(prefix='/settings')
@@ -33,29 +33,29 @@ async def set_phone(
return ORJSONResponse(status_code=status.HTTP_200_OK, content={'phone': user.phone}) return ORJSONResponse(status_code=status.HTTP_200_OK, content={'phone': user.phone})
@account_settings_router.post(path='/crypto-wallet/start', response_class=ORJSONResponse, status_code=status.HTTP_200_OK) @account_settings_router.post(path='/encrypted-mnemonic/start', response_class=ORJSONResponse, status_code=status.HTTP_200_OK)
async def crypto_wallet_start( async def encrypted_mnemonic_start(
request: Request, request: Request,
auth: AuthContext = Depends(require_access_token), auth: AuthContext = Depends(require_access_token),
command: SetCryptoWalletStartCommand = Depends(get_set_crypto_wallet_start_command), command: SetEncryptedMnemonicStartCommand = Depends(get_set_encrypted_mnemonic_start_command),
): ):
result = await command(user_id=auth.user_id) result = await command(user_id=auth.user_id)
return {'success': result} return {'success': result}
@account_settings_router.post(path='/crypto-wallet/complete', response_class=ORJSONResponse, status_code=status.HTTP_200_OK) @account_settings_router.post(path='/encrypted-mnemonic/complete', response_class=ORJSONResponse, status_code=status.HTTP_200_OK)
async def crypto_wallet_complete( async def encrypted_mnemonic_complete(
request: Request, request: Request,
body: CryptoWalletConfirmRequest, body: EncryptedMnemonicConfirmRequest,
auth: AuthContext = Depends(require_access_token), auth: AuthContext = Depends(require_access_token),
command: SetCryptoWalletCompleteCommand = Depends(get_set_crypto_wallet_complete_command), command: SetEncryptedMnemonicCompleteCommand = Depends(get_set_encrypted_mnemonic_complete_command),
): ):
user = await command( user = await command(
user_id=auth.user_id, user_id=auth.user_id,
code=body.code, code=body.code,
wallet_address=body.wallet_address, encrypted_mnemonic=body.encrypted_mnemonic,
) )
return {'crypto_wallet': user.crypto_wallet} return {'encrypted_mnemonic': user.encrypted_mnemonic}
@account_settings_router.post(path='/email/start', response_class=ORJSONResponse, status_code=status.HTTP_200_OK) @account_settings_router.post(path='/email/start', response_class=ORJSONResponse, status_code=status.HTTP_200_OK)

View File

@@ -1,5 +1,5 @@
from src.presentation.schemas.phone import SetPhoneRequest from src.presentation.schemas.phone import SetPhoneRequest
from src.presentation.schemas.bank import BankUpdateRequest, BankConfirmRequest from src.presentation.schemas.bank import BankUpdateRequest, BankConfirmRequest
from src.presentation.schemas.crypto_wallet import CryptoWalletConfirmRequest from src.presentation.schemas.encrypted_mnemonic import EncryptedMnemonicConfirmRequest
from src.presentation.schemas.password import ChangePasswordConfirmRequest from src.presentation.schemas.password import ChangePasswordConfirmRequest
from src.presentation.schemas.email import ChangeEmailConfirmOldRequest, ChangeEmailCompleteRequest from src.presentation.schemas.email import ChangeEmailConfirmOldRequest, ChangeEmailCompleteRequest

View File

@@ -2,9 +2,9 @@ import re
from pydantic import BaseModel, field_validator from pydantic import BaseModel, field_validator
class CryptoWalletConfirmRequest(BaseModel): class EncryptedMnemonicConfirmRequest(BaseModel):
code: str code: str
wallet_address: str encrypted_mnemonic: str
@field_validator('code') @field_validator('code')
@classmethod @classmethod
@@ -14,10 +14,10 @@ class CryptoWalletConfirmRequest(BaseModel):
raise ValueError('Code must be exactly 6 digits') raise ValueError('Code must be exactly 6 digits')
return v return v
@field_validator('wallet_address') @field_validator('encrypted_mnemonic')
@classmethod @classmethod
def validate_tron_address(cls, v: str) -> str: def validate_encrypted_mnemonic(cls, v: str) -> str:
v = v.strip() v = v.strip()
if not re.match(r'^T[1-9A-HJ-NP-Za-km-z]{33}$', v): if not v:
raise ValueError('Invalid TRON wallet address') raise ValueError('encrypted_mnemonic must not be empty')
return v return v