feat: add new column and delete old
This commit is contained in:
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
@@ -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:
|
||||||
@@ -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
|
||||||
|
|||||||
2
src/infrastructure/cache/keydb_client.py
vendored
2
src/infrastructure/cache/keydb_client.py
vendored
@@ -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,
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
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
|
||||||
|
|
||||||
|
|
||||||
class UserModel(Base, UlidPrimaryKeyMixin, AuditTimestampsMixin, SoftDeleteMixin):
|
class UserModel(Base, 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)
|
||||||
|
|||||||
@@ -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:
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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
|
||||||
@@ -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
|
||||||
Reference in New Issue
Block a user