π§ Review Summary: src/presentation/bot/middleware/user_and_locale.py
- File Purpose: Aiogram middleware that loads user profile from database and injects localized i18n translator into handler data. Provides unified user context (
profile and i18n) for callback queries and message handlers.
- Reviewer: Claude Code AI
- Review Date: 2026-02-04
π File Purpose & System Integration
This middleware is part of the language onboarding feature (branch feat/user-language-onboarding). It:
- Intercepts Telegram events (messages, callback queries) before they reach handlers
- Loads user profile via
GetUserProfileInteractor from the database
- Injects i18n translator based on user's saved language preference
- Handles failures gracefully by responding with localized error messages and stopping handler execution
How it fits in the system:
- Registered in
main.py for dp.message and dp.callback_query event types
- Replaces/complements the older
I18nMiddleware in src/infrastructure/i18n/middleware.py
- Works with
GetUserProfileInteractor from application layer
- Uses dishka DI container for dependency injection
β
Strengths
- Clean separation of concerns - middleware handles cross-cutting concern (loading user context)
- Proper error handling - catches
ApplicationError and provides user-friendly feedback
- Event-type-aware responses - different error handling for
CallbackQuery vs InlineQuery
- Logging - appropriate warning logs with context for debugging
- Type hints - good use of union types and type casting
β οΈ Issues & Recommendations
Critical
Important
Minor
Code Style
ποΈ Architectural Considerations
-
Middleware vs. Dependency Injection: The middleware pattern works well here, but consider whether the profile could instead be provided via dishka dependency injection for handlers that need it, allowing optional usage.
-
Coupling to GetUserProfileInteractor: The middleware is tightly coupled to this specific interactor. If profile requirements change, this middleware must change too.
-
Error recovery: Currently, any ApplicationError stops handler execution entirely. Consider whether some errors (e.g., database timeout) should allow retry or fallback behavior.
π§ͺ Test Coverage Needed
# Suggested test file: tests/unit/presentation/bot/middleware/test_user_and_locale.py
class TestUserAndLocaleMiddleware:
async def test_happy_path_injects_profile_and_i18n(self): ...
async def test_callback_query_error_shows_alert(self): ...
async def test_inline_query_error_returns_empty(self): ...
async def test_chosen_inline_result_error_returns_none(self): ...
async def test_uses_telegram_language_on_error(self): ...
π Action Items Summary
| Priority |
Issue |
Effort |
| π΄ Critical |
Add missing error_loading_profile translation key |
Low |
| π‘ Important |
Add unit tests |
Medium |
| π‘ Important |
Clarify relationship with I18nMiddleware |
Low |
| π‘ Important |
Add null check for from_user |
Low |
| π’ Minor |
Add debug logging for silent error cases |
Low |
| π’ Minor |
Extract error handling to helper method |
Low |
π§ Review Summary:
src/presentation/bot/middleware/user_and_locale.pyprofileandi18n) for callback queries and message handlers.π File Purpose & System Integration
This middleware is part of the language onboarding feature (branch
feat/user-language-onboarding). It:GetUserProfileInteractorfrom the databaseHow it fits in the system:
main.pyfordp.messageanddp.callback_queryevent typesI18nMiddlewareinsrc/infrastructure/i18n/middleware.pyGetUserProfileInteractorfrom application layerβ Strengths
ApplicationErrorand provides user-friendly feedbackCallbackQueryvsInlineQueryCritical
error_loading_profile- The middleware callsi18n.error_loading_profile()but this translation key is not defined in any.ftlfile (locales/en/common.ftlandlocales/ru/common.ftlare empty). This will cause a runtime error or return the key name as-is.Important
Potential
AttributeErroronfrom_user- Line 50 accessesuser_event.from_user.idwithout null check. While the middleware is only registered for events that should havefrom_user, the typeUserEventincludesChosenInlineResultwhich theoretically could have edge cases. Consider adding a guard.Duplicate middleware functionality -
I18nMiddlewareinsrc/infrastructure/i18n/middleware.pyprovides similar i18n injection. Having two middlewares that both setdata["i18n"]could cause confusion or conflicts. Consider deprecating/removing the older middleware or documenting the relationship clearly.No unit tests - No tests exist for this middleware. Bot middleware is testable by mocking the handler, event, and container. Missing test coverage for:
Minor
Hardcoded fallback behavior - On error,
InlineQuerygets an empty result with 1-second cache. Consider making cache time configurable or using a constant.Silent handling for
ChosenInlineResult- The comment says "just skip silently" but logging would help debugging. Consider adding a debug log.profilevariable might be referenced before assignment - IfApplicationErroris raised,profileis never set, but this is handled by early return. However, this pattern could be clearer with an early assignment or restructuring.Container key access
data[CONTAINER_NAME]- Could raiseKeyErrorif dishka middleware isn't registered. Consider using.get()with appropriate error handling.Code Style
Docstring could be more detailed - The class docstring is good, but individual method docstrings are missing. Consider adding docstring to
__call__explaining parameters.Consider extracting error handling into helper methods - The error handling block (lines 61-66) could be cleaner as a private method
_handle_error_response(user_event, i18n).ποΈ Architectural Considerations
Middleware vs. Dependency Injection: The middleware pattern works well here, but consider whether the profile could instead be provided via dishka dependency injection for handlers that need it, allowing optional usage.
Coupling to
GetUserProfileInteractor: The middleware is tightly coupled to this specific interactor. If profile requirements change, this middleware must change too.Error recovery: Currently, any
ApplicationErrorstops handler execution entirely. Consider whether some errors (e.g., database timeout) should allow retry or fallback behavior.π§ͺ Test Coverage Needed
π Action Items Summary
error_loading_profiletranslation keyI18nMiddlewarefrom_user