feat: add get me

This commit is contained in:
2026-05-12 20:48:06 +03:00
parent 1a76aa5a66
commit d9ecdd7b86
8 changed files with 88 additions and 105 deletions

View File

@@ -30,10 +30,9 @@ async def me(
'birth_date': str(user.birth_date) if user.birth_date else None,
'crypto_wallet': user.crypto_wallet,
'phone': user.phone,
'bik': user.bik,
'account_number': user.account_number,
'card_number': user.card_number,
'passport_data': user.passport_data,
'inn': user.inn,
'erc20': user.erc20,
'kyc_verified': user.kyc_verified,
'is_deleted': user.is_deleted,
'created_at': user.created_at.isoformat() if user.created_at else None,

View File

@@ -136,15 +136,15 @@ async def bank_details_complete(
user = await command(
user_id=auth.user_id,
code=body.code,
bik=body.bik,
account_number=body.account_number,
card_number=body.card_number,
passport_data=body.passport_data,
inn=body.inn,
erc20=body.erc20,
)
return ORJSONResponse(
status_code=status.HTTP_200_OK,
content={
'bik': user.bik,
'account_number': user.account_number,
'card_number': user.card_number,
'passport_data': user.passport_data,
'inn': user.inn,
'erc20': user.erc20,
},
)

View File

@@ -4,69 +4,67 @@ from pydantic import BaseModel, field_validator, model_validator
class BankUpdateRequest(BaseModel):
bik: str | None = None
account_number: str | None = None
card_number: str | None = None
passport_data: str | None = None
inn: str | None = None
erc20: str | None = None
@model_validator(mode='after')
def at_least_one(self) -> Self:
if not any([self.bik, self.account_number, self.card_number]):
if not any([self.passport_data, self.inn, self.erc20]):
raise ValueError('At least one field is required')
return self
@field_validator('bik')
@field_validator('passport_data', 'inn', 'erc20')
@classmethod
def validate_bik(cls, v: str | None) -> str | None:
def strip_optional(cls, v: str | None) -> str | None:
if v is None:
return None
s = v.strip()
return s or None
@field_validator('inn')
@classmethod
def validate_inn(cls, v: str | None) -> str | None:
if v is None:
return None
v = v.strip()
if not re.match(r'^\d{9}$', v):
raise ValueError('BIK must be exactly 9 digits')
if not re.match(r'^\d{10}(\d{2})?$', v):
raise ValueError('INN must be 10 or 12 digits')
if len(v) > 12:
raise ValueError('INN is too long')
return v
@field_validator('account_number')
@field_validator('erc20')
@classmethod
def validate_account_number(cls, v: str | None) -> str | None:
def validate_erc20(cls, v: str | None) -> str | None:
if v is None:
return None
v = v.strip()
if not re.match(r'^\d{20}$', v):
raise ValueError('Account number must be exactly 20 digits')
if not re.match(r'^0x[a-fA-F0-9]{40}$', v):
raise ValueError('ERC20 address must be 0x followed by 40 hex characters')
return v
@field_validator('card_number')
@field_validator('passport_data')
@classmethod
def validate_card_number(cls, v: str | None) -> str | None:
def validate_passport_data(cls, v: str | None) -> str | None:
if v is None:
return None
v = re.sub(r'[\s\-]', '', v)
if not re.match(r'^\d{13,19}$', v):
raise ValueError('Card number must be 13-19 digits')
if not cls._luhn_check(v):
raise ValueError('Invalid card number (Luhn check failed)')
v = v.strip()
if len(v) > 255:
raise ValueError('Passport data is too long')
return v
@staticmethod
def _luhn_check(number: str) -> bool:
digits = [int(d) for d in number]
odd_digits = digits[-1::-2]
even_digits = digits[-2::-2]
total = sum(odd_digits)
for d in even_digits:
total += sum(divmod(d * 2, 10))
return total % 10 == 0
class BankConfirmRequest(BaseModel):
code: str
bik: str | None = None
account_number: str | None = None
card_number: str | None = None
passport_data: str | None = None
inn: str | None = None
erc20: str | None = None
@model_validator(mode='after')
def at_least_one_field(self) -> Self:
if not any([self.bik, self.account_number, self.card_number]):
raise ValueError('At least one bank field is required')
if not any([self.passport_data, self.inn, self.erc20]):
raise ValueError('At least one field is required')
return self
@field_validator('code')
@@ -77,34 +75,42 @@ class BankConfirmRequest(BaseModel):
raise ValueError('Code must be exactly 6 digits')
return v
@field_validator('bik')
@field_validator('passport_data', 'inn', 'erc20')
@classmethod
def validate_bik(cls, v: str | None) -> str | None:
def strip_optional(cls, v: str | None) -> str | None:
if v is None:
return None
s = v.strip()
return s or None
@field_validator('inn')
@classmethod
def validate_inn(cls, v: str | None) -> str | None:
if v is None:
return None
v = v.strip()
if not re.match(r'^\d{9}$', v):
raise ValueError('BIK must be exactly 9 digits')
if not re.match(r'^\d{10}(\d{2})?$', v):
raise ValueError('INN must be 10 or 12 digits')
if len(v) > 12:
raise ValueError('INN is too long')
return v
@field_validator('account_number')
@field_validator('erc20')
@classmethod
def validate_account_number(cls, v: str | None) -> str | None:
def validate_erc20(cls, v: str | None) -> str | None:
if v is None:
return None
v = v.strip()
if not re.match(r'^\d{20}$', v):
raise ValueError('Account number must be exactly 20 digits')
if not re.match(r'^0x[a-fA-F0-9]{40}$', v):
raise ValueError('ERC20 address must be 0x followed by 40 hex characters')
return v
@field_validator('card_number')
@field_validator('passport_data')
@classmethod
def validate_card_number(cls, v: str | None) -> str | None:
def validate_passport_data(cls, v: str | None) -> str | None:
if v is None:
return None
v = re.sub(r'[\s\-]', '', v)
if not re.match(r'^\d{13,19}$', v):
raise ValueError('Card number must be 13-19 digits')
if not BankUpdateRequest._luhn_check(v):
raise ValueError('Invalid card number (Luhn check failed)')
v = v.strip()
if len(v) > 255:
raise ValueError('Passport data is too long')
return v