feat: add change password event
This commit is contained in:
@@ -1,15 +1,23 @@
|
|||||||
from fastapi import APIRouter, Depends, Request
|
from fastapi import APIRouter, Depends, Request
|
||||||
from fastapi.responses import ORJSONResponse
|
from fastapi.responses import ORJSONResponse
|
||||||
from starlette import status
|
from starlette import status
|
||||||
from src.application.commands import SetPhoneCommand, SetAvatarCommand, DeleteAvatarCommand
|
from src.application.commands import (
|
||||||
|
SetPhoneCommand,
|
||||||
|
SetAvatarCommand,
|
||||||
|
DeleteAvatarCommand,
|
||||||
|
ChangePasswordStartCommand,
|
||||||
|
ChangePasswordCompleteCommand,
|
||||||
|
)
|
||||||
from src.application.domain.dto import AuthContext
|
from src.application.domain.dto import AuthContext
|
||||||
from src.presentation.decorators import require_access_token, csrf_protect
|
from src.presentation.decorators import require_access_token, csrf_protect
|
||||||
from src.presentation.dependencies import (
|
from src.presentation.dependencies import (
|
||||||
get_delete_avatar_command,
|
get_delete_avatar_command,
|
||||||
get_set_avatar_command,
|
get_set_avatar_command,
|
||||||
get_set_phone_command,
|
get_set_phone_command,
|
||||||
|
get_change_password_start_command,
|
||||||
|
get_change_password_complete_command,
|
||||||
)
|
)
|
||||||
from src.presentation.schemas import SetAvatarRequest, SetPhoneRequest
|
from src.presentation.schemas import SetAvatarRequest, SetPhoneRequest, ChangePasswordConfirmRequest
|
||||||
from src.presentation.schemas.api_errors import ApiErrorPayload, ApiValidationErrorsPayload
|
from src.presentation.schemas.api_errors import ApiErrorPayload, ApiValidationErrorsPayload
|
||||||
from src.presentation.schemas.me_public import MeUserPublicResponse, SetAvatarPublicResponse
|
from src.presentation.schemas.me_public import MeUserPublicResponse, SetAvatarPublicResponse
|
||||||
from src.presentation.serializers import me_user_public
|
from src.presentation.serializers import me_user_public
|
||||||
@@ -46,6 +54,38 @@ _SET_AVATAR_ERROR_RESPONSES: dict[int, dict[str, object]] = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
_PASSWORD_ERROR_RESPONSES: dict[int, dict[str, object]] = {
|
||||||
|
status.HTTP_400_BAD_REQUEST: {
|
||||||
|
'description': 'Неверный или просроченный код, пароли не совпадают или совпадают с текущим.',
|
||||||
|
'model': ApiErrorPayload,
|
||||||
|
},
|
||||||
|
status.HTTP_401_UNAUTHORIZED: {
|
||||||
|
'description': 'Не передан или неверен access token.',
|
||||||
|
'model': ApiErrorPayload,
|
||||||
|
},
|
||||||
|
status.HTTP_404_NOT_FOUND: {
|
||||||
|
'description': 'Учётная запись не найдена или у пользователя нет email.',
|
||||||
|
'model': ApiErrorPayload,
|
||||||
|
},
|
||||||
|
status.HTTP_422_UNPROCESSABLE_ENTITY: {
|
||||||
|
'description': 'Тело запроса не соответствует схеме (код, длина пароля).',
|
||||||
|
'model': ApiValidationErrorsPayload,
|
||||||
|
},
|
||||||
|
status.HTTP_429_TOO_MANY_REQUESTS: {
|
||||||
|
'description': 'Код уже отправлен или слишком частые запросы.',
|
||||||
|
'model': ApiErrorPayload,
|
||||||
|
},
|
||||||
|
status.HTTP_500_INTERNAL_SERVER_ERROR: {
|
||||||
|
'description': 'Внутренняя ошибка сервера.',
|
||||||
|
'model': ApiErrorPayload,
|
||||||
|
},
|
||||||
|
status.HTTP_503_SERVICE_UNAVAILABLE: {
|
||||||
|
'description': 'Временная ошибка отправки кода или сохранения в кеш.',
|
||||||
|
'model': ApiErrorPayload,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
_DELETE_AVATAR_ERROR_RESPONSES: dict[int, dict[str, object]] = {
|
_DELETE_AVATAR_ERROR_RESPONSES: dict[int, dict[str, object]] = {
|
||||||
status.HTTP_401_UNAUTHORIZED: {
|
status.HTTP_401_UNAUTHORIZED: {
|
||||||
'description': 'Не передан или неверен access token.',
|
'description': 'Не передан или неверен access token.',
|
||||||
@@ -125,6 +165,52 @@ async def delete_avatar(
|
|||||||
user = await command(user_id=auth.user_id)
|
user = await command(user_id=auth.user_id)
|
||||||
return me_user_public(user)
|
return me_user_public(user)
|
||||||
|
|
||||||
|
|
||||||
|
@account_settings_router.post(
|
||||||
|
path='/password/start',
|
||||||
|
response_class=ORJSONResponse,
|
||||||
|
status_code=status.HTTP_200_OK,
|
||||||
|
summary='Запросить код для смены пароля',
|
||||||
|
description='Отправляет шестизначный код на email текущего пользователя. Повторный запрос возможен после истечения TTL.',
|
||||||
|
responses=_PASSWORD_ERROR_RESPONSES,
|
||||||
|
)
|
||||||
|
@csrf_protect()
|
||||||
|
async def change_password_start(
|
||||||
|
request: Request,
|
||||||
|
auth: AuthContext = Depends(require_access_token),
|
||||||
|
command: ChangePasswordStartCommand = Depends(get_change_password_start_command),
|
||||||
|
):
|
||||||
|
result = await command(user_id=auth.user_id)
|
||||||
|
return ORJSONResponse(status_code=status.HTTP_200_OK, content={'success': result})
|
||||||
|
|
||||||
|
|
||||||
|
@account_settings_router.post(
|
||||||
|
path='/password/complete',
|
||||||
|
response_class=ORJSONResponse,
|
||||||
|
status_code=status.HTTP_200_OK,
|
||||||
|
summary='Подтвердить смену пароля',
|
||||||
|
description=(
|
||||||
|
'Принимает код из письма, новый пароль и его подтверждение. '
|
||||||
|
'Новый пароль должен отличаться от текущего (минимум 8 символов).'
|
||||||
|
),
|
||||||
|
responses=_PASSWORD_ERROR_RESPONSES,
|
||||||
|
)
|
||||||
|
@csrf_protect()
|
||||||
|
async def change_password_complete(
|
||||||
|
request: Request,
|
||||||
|
body: ChangePasswordConfirmRequest,
|
||||||
|
auth: AuthContext = Depends(require_access_token),
|
||||||
|
command: ChangePasswordCompleteCommand = Depends(get_change_password_complete_command),
|
||||||
|
):
|
||||||
|
result = await command(
|
||||||
|
user_id=auth.user_id,
|
||||||
|
code=body.code,
|
||||||
|
new_password=body.new_password,
|
||||||
|
confirm_password=body.confirm_password,
|
||||||
|
)
|
||||||
|
return ORJSONResponse(status_code=status.HTTP_200_OK, content={'success': result})
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# @account_settings_router.post(path='/encrypted-mnemonic/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 encrypted_mnemonic_start(
|
# async def encrypted_mnemonic_start(
|
||||||
@@ -183,32 +269,6 @@ async def delete_avatar(
|
|||||||
# return {'success': result}
|
# return {'success': result}
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
# @account_settings_router.post(path='/password/start', response_class=ORJSONResponse, status_code=status.HTTP_200_OK)
|
|
||||||
# async def change_password_start(
|
|
||||||
# request: Request,
|
|
||||||
# auth: AuthContext = Depends(require_access_token),
|
|
||||||
# command: ChangePasswordStartCommand = Depends(get_change_password_start_command),
|
|
||||||
# ):
|
|
||||||
# result = await command(user_id=auth.user_id)
|
|
||||||
# return {'success': result}
|
|
||||||
#
|
|
||||||
#
|
|
||||||
# @account_settings_router.post(path='/password/complete', response_class=ORJSONResponse, status_code=status.HTTP_200_OK)
|
|
||||||
# async def change_password_complete(
|
|
||||||
# request: Request,
|
|
||||||
# body: ChangePasswordConfirmRequest,
|
|
||||||
# auth: AuthContext = Depends(require_access_token),
|
|
||||||
# command: ChangePasswordCompleteCommand = Depends(get_change_password_complete_command),
|
|
||||||
# ):
|
|
||||||
# result = await command(
|
|
||||||
# user_id=auth.user_id,
|
|
||||||
# code=body.code,
|
|
||||||
# new_password=body.new_password,
|
|
||||||
# confirm_password=body.confirm_password,
|
|
||||||
# )
|
|
||||||
# return {'success': result}
|
|
||||||
#
|
|
||||||
#
|
|
||||||
# @account_settings_router.post(path='/bank/start', response_class=ORJSONResponse, status_code=status.HTTP_200_OK)
|
# @account_settings_router.post(path='/bank/start', response_class=ORJSONResponse, status_code=status.HTTP_200_OK)
|
||||||
# async def bank_details_start(
|
# async def bank_details_start(
|
||||||
# request: Request,
|
# request: Request,
|
||||||
|
|||||||
Reference in New Issue
Block a user