Corp/backend/common/request_utils.py
lizerk 2ef43e7177 Feature: Add code quality audit tools and safe helpers
- Created CODE_QUALITY_CHECKLIST.md with comprehensive guide
- Added audit_code_patterns.sh for automated code scanning
- Created common/request_utils.py with safe_int(), safe_bool(), etc.
- Fixed unsafe request.data access in notifications/api/views.py
- Updated ldap_password_mixin.py docstring with safe example

Audit found and documented:
- 10 unsafe request.data['key'] accesses
- 8+ unsafe int() conversions without try/except
- Multiple .strip() calls without None checks
2026-03-20 09:06:55 +03:00

116 lines
3.4 KiB
Python

"""Утилиты для безопасной обработки данных запросов."""
from typing import Any, Optional, Union
def safe_int(value: Any, default: int = 0) -> int:
"""Безопасно конвертирует значение в int.
Args:
value: Значение для конверсии (может быть str, int, None, ...)
default: Значение по умолчанию при ошибке конверсии
Returns:
int: Сконвертированное значение или default
Examples:
>>> safe_int('123')
123
>>> safe_int('abc', default=1)
1
>>> safe_int(None, default=10)
10
>>> safe_int('', default=5)
5
"""
if value is None or value == '':
return default
try:
return int(value)
except (ValueError, TypeError):
return default
def safe_bool(value: Any, default: bool = False) -> bool:
"""Безопасно конвертирует значение в bool.
Поддерживает строки: 'true', 'false', '1', '0', 'yes', 'no'
Args:
value: Значение для конверсии
default: Значение по умолчанию при ошибке
Returns:
bool: Сконвертированное значение или default
"""
if value is None:
return default
if isinstance(value, bool):
return value
if isinstance(value, (int, float)):
return bool(value)
if isinstance(value, str):
value_lower = value.lower().strip()
if value_lower in ('true', '1', 'yes', 'on'):
return True
if value_lower in ('false', '0', 'no', 'off', ''):
return False
return default
def safe_float(value: Any, default: float = 0.0) -> float:
"""Безопасно конвертирует значение в float.
Args:
value: Значение для конверсии
default: Значение по умолчанию при ошибке
Returns:
float: Сконвертированное значение или default
"""
if value is None or value == '':
return default
try:
return float(value)
except (ValueError, TypeError):
return default
def safe_get_data(
data: Union[dict, 'QueryDict'],
key: str,
default: Any = None,
required: bool = False,
) -> Any:
"""Безопасно извлекает значение из request.data.
Args:
data: request.data (может быть dict или QueryDict)
key: Ключ для извлечения
default: Значение по умолчанию
required: Если True, вызовет KeyError при отсутствии ключа
Returns:
Значение или default
Raises:
KeyError: Если required=True и ключа нет
Examples:
>>> safe_get_data({'name': 'John'}, 'name')
'John'
>>> safe_get_data({}, 'age', default=18)
18
>>> safe_get_data({}, 'email', required=True)
KeyError: 'email'
"""
if required and key not in data:
raise KeyError(f"Required field '{key}' is missing")
return data.get(key, default)