a2fe4a49e3
Сотрудник сам подключает ящик (autoconfig, вложения, пагинация списка, надёжный IMAP-поиск); в хедере работает /api/search по разделам и сущностям с ACL. Также устойчивость Mattermost-токена для чата. Co-authored-by: Cursor <cursoragent@cursor.com>
49 lines
2.8 KiB
Python
49 lines
2.8 KiB
Python
"""Человекочитаемые ошибки подключения почты."""
|
|
from __future__ import annotations
|
|
|
|
import re
|
|
|
|
|
|
def humanize_mail_error(exc: BaseException, *, host: str = '', port: int | None = None) -> str:
|
|
"""Короткое сообщение для UI (украинский)."""
|
|
raw = str(exc) or exc.__class__.__name__
|
|
low = raw.lower()
|
|
target = f'{host}:{port}' if host and port else (host or 'поштового сервера')
|
|
|
|
if isinstance(exc, UnicodeEncodeError) or 'ordinal not in range' in low or 'ascii' in low and 'codec' in low:
|
|
return (
|
|
'Пароль містить символи, які IMAP-клієнт не зміг передати. '
|
|
'Спробуйте ще раз — якщо помилка лишиться, змініть пароль скриньки на латиницю/цифри.'
|
|
)
|
|
|
|
if any(x in low for x in ('authenticationfailed', 'login failed', 'auth', 'invalid credentials', 'invalid user')):
|
|
return 'Невірний email або пароль скриньки. Перевірте дані та спробуйте знову.'
|
|
|
|
if any(x in low for x in ('name or service not known', 'getaddrinfo', 'nodename nor servname', 'temporary failure in name resolution')):
|
|
return (
|
|
f'Сервер «{host or "?"}» не знайдено в DNS. '
|
|
'Відкрийте «Розширені налаштування» і вкажіть правильний IMAP-хост '
|
|
'(часто mail.ваш-домен).'
|
|
)
|
|
|
|
if any(x in low for x in ('timed out', 'timeout', 'connection timed out')):
|
|
return f'Час очікування вичерпано при з\'єднанні з {target}. Перевірте хост/порт або мережу.'
|
|
|
|
if any(x in low for x in ('connection refused', 'actively refused')):
|
|
return f'Сервер {target} відхилив з\'єднання. Можливо, інший порт (993 SSL або 143).'
|
|
|
|
if any(x in low for x in ('network is unreachable', 'no route to host')):
|
|
return f'Немає маршруту до {target}. Перевірте інтернет або VPN.'
|
|
|
|
if any(x in low for x in ('certificate', 'ssl', 'tls', 'handshake')):
|
|
return (
|
|
f'Помилка SSL/TLS з {target}. Спробуйте інший порт '
|
|
'або зверніться до адміністратора пошти.'
|
|
)
|
|
|
|
# обрезать слишком длинные/технические ответы сервера
|
|
cleaned = re.sub(r'\s+', ' ', raw).strip()
|
|
if len(cleaned) > 180:
|
|
cleaned = cleaned[:177] + '…'
|
|
return f'Не вдалося підключити скриньку ({target}): {cleaned}'
|