diff --git a/app/cabinet/routes/auth.py b/app/cabinet/routes/auth.py index c0635039..db84eb1d 100644 --- a/app/cabinet/routes/auth.py +++ b/app/cabinet/routes/auth.py @@ -7,6 +7,7 @@ from datetime import UTC, datetime from fastapi import APIRouter, Depends, HTTPException, status from sqlalchemy import select +from sqlalchemy.exc import IntegrityError from sqlalchemy.ext.asyncio import AsyncSession from app.config import settings @@ -1010,7 +1011,14 @@ async def request_email_change( user.email_verification_token = verification_token user.email_verification_expires = verification_expires - await db.commit() + try: + await db.commit() + except IntegrityError: + await db.rollback() + raise HTTPException( + status_code=status.HTTP_400_BAD_REQUEST, + detail='This email is already registered', + ) if settings.is_cabinet_email_verification_enabled() and email_service.is_configured(): cabinet_url = settings.CABINET_URL @@ -1031,16 +1039,19 @@ async def request_email_change( ) custom_subject, custom_body = override if override else (None, None) - await asyncio.to_thread( - email_service.send_verification_email, - to_email=request.new_email, - verification_token=verification_token, - verification_url=verification_url, - username=user.first_name, - language=lang, - custom_subject=custom_subject, - custom_body_html=custom_body, - ) + try: + await asyncio.to_thread( + email_service.send_verification_email, + to_email=request.new_email, + verification_token=verification_token, + verification_url=verification_url, + username=user.first_name, + language=lang, + custom_subject=custom_subject, + custom_body_html=custom_body, + ) + except Exception as e: + logger.error(f'Failed to send verification email to {request.new_email} for user {user.id}: {e}') logger.info(f'Unverified email replaced for user {user.id}: {old_email} -> {request.new_email}') diff --git a/app/config.py b/app/config.py index 651548cc..e81dcb7c 100644 --- a/app/config.py +++ b/app/config.py @@ -1057,7 +1057,7 @@ class Settings(BaseSettings): if not sanitized_username: sanitized_username = f'user_{identifier}' - return sanitized_username[:64] + return sanitized_username[:36] @staticmethod def parse_daily_time_list(raw_value: str | None) -> list[time]: diff --git a/app/handlers/start.py b/app/handlers/start.py index d4b9e829..21e56260 100644 --- a/app/handlers/start.py +++ b/app/handlers/start.py @@ -1225,6 +1225,20 @@ async def complete_registration_from_callback(callback: types.CallbackQuery, sta ) logger.info(f'✅ Приветственное сообщение отправлено пользователю {user.telegram_id}') await _send_pinned_message(callback.bot, db, user) + except TelegramBadRequest as e: + if 'parse entities' in str(e).lower() or "can't parse" in str(e).lower(): + logger.warning(f'HTML parse error в приветственном сообщении, повтор без parse_mode: {e}') + try: + await callback.message.answer( + offer_text, + reply_markup=get_post_registration_keyboard(user.language), + parse_mode=None, + ) + await _send_pinned_message(callback.bot, db, user) + except Exception as fallback_err: + logger.error(f'Ошибка при повторной отправке приветственного сообщения: {fallback_err}') + else: + logger.error(f'Ошибка при отправке приветственного сообщения: {e}') except Exception as e: logger.error(f'Ошибка при отправке приветственного сообщения: {e}') else: @@ -1504,6 +1518,20 @@ async def complete_registration(message: types.Message, state: FSMContext, db: A ) logger.info(f'✅ Приветственное сообщение отправлено пользователю {user.telegram_id}') await _send_pinned_message(message.bot, db, user) + except TelegramBadRequest as e: + if 'parse entities' in str(e).lower() or "can't parse" in str(e).lower(): + logger.warning(f'HTML parse error в приветственном сообщении, повтор без parse_mode: {e}') + try: + await message.answer( + offer_text, + reply_markup=keyboard, + parse_mode=None, + ) + await _send_pinned_message(message.bot, db, user) + except Exception as fallback_err: + logger.error(f'Ошибка при повторной отправке приветственного сообщения: {fallback_err}') + else: + logger.error(f'Ошибка при отправке приветственного сообщения: {e}') except Exception as e: logger.error(f'Ошибка при отправке приветственного сообщения: {e}') else: