fix: remove incorrect get_users override, keep logging in save method only
This commit is contained in:
parent
73ed15dd56
commit
c49e5cac10
@ -1,4 +1,5 @@
|
||||
# backend/common/emails.py
|
||||
import logging
|
||||
from pathlib import Path
|
||||
from typing import Iterable, Mapping, Optional
|
||||
|
||||
@ -7,6 +8,8 @@ from django.core.mail import EmailMultiAlternatives
|
||||
from django.template.loader import render_to_string
|
||||
from django.utils.html import strip_tags
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def send_templated_mail(
|
||||
subject: str,
|
||||
@ -22,23 +25,54 @@ def send_templated_mail(
|
||||
templates/<template_base>.txt (опционально)
|
||||
attachments: список троек (name, content_bytes, mimetype)
|
||||
"""
|
||||
html_body = render_to_string(f"{template_base}.html", context)
|
||||
to_list = list(to)
|
||||
|
||||
logger.info(
|
||||
f"[send_templated_mail] 📧 НАЧАЛО ОТПРАВКИ EMAIL\n"
|
||||
f" Subject: '{subject}'\n"
|
||||
f" Template: {template_base}\n"
|
||||
f" Recipients: {to_list}\n"
|
||||
f" From: {from_email or settings.DEFAULT_FROM_EMAIL}"
|
||||
)
|
||||
|
||||
try:
|
||||
html_body = render_to_string(f"{template_base}.html", context)
|
||||
logger.info(f"[send_templated_mail] ✅ HTML шаблон загружен ({len(html_body)} символов)")
|
||||
except Exception as e:
|
||||
logger.error(f"[send_templated_mail] ❌ Ошибка загрузки HTML шаблона: {e}")
|
||||
raise
|
||||
|
||||
# .txt файл опционален — если его нет, берём strip_tags от html
|
||||
try:
|
||||
text_body = render_to_string(f"{template_base}.txt", context)
|
||||
logger.info(f"[send_templated_mail] ✅ TXT шаблон загружен ({len(text_body)} символов)")
|
||||
except Exception:
|
||||
text_body = strip_tags(html_body)
|
||||
logger.info(f"[send_templated_mail] ⚠️ TXT шаблон не найден, используется strip_tags от HTML")
|
||||
|
||||
email = EmailMultiAlternatives(
|
||||
subject=subject,
|
||||
body=text_body,
|
||||
from_email=from_email or settings.DEFAULT_FROM_EMAIL,
|
||||
to=list(to),
|
||||
to=to_list,
|
||||
)
|
||||
email.attach_alternative(html_body, "text/html")
|
||||
|
||||
if attachments:
|
||||
for name, data, mimetype in attachments:
|
||||
email.attach(name, data, mimetype)
|
||||
logger.info(f"[send_templated_mail] 📎 Вложение: {name} ({len(data)} bytes, {mimetype})")
|
||||
|
||||
logger.info(f"[send_templated_mail] ➡️ Вызов email.send()...")
|
||||
|
||||
try:
|
||||
result = email.send(fail_silently=False)
|
||||
logger.info(f"[send_templated_mail] ✅ EMAIL УСПЕШНО ОТПРАВЛЕН (result={result})")
|
||||
return result
|
||||
except Exception as e:
|
||||
logger.error(
|
||||
f"[send_templated_mail] ❌ ОШИБКА ОТПРАВКИ EMAIL: {type(e).__name__}: {e}",
|
||||
exc_info=True
|
||||
)
|
||||
raise
|
||||
|
||||
return email.send(fail_silently=False)
|
||||
|
||||
@ -2,14 +2,17 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import base64
|
||||
import logging
|
||||
import re
|
||||
from typing import Any, Dict, List, Optional
|
||||
|
||||
from django import forms
|
||||
from django.contrib.auth.forms import AuthenticationForm
|
||||
from django.contrib.auth.forms import AuthenticationForm, PasswordResetForm
|
||||
from django.core.files.uploadedfile import UploadedFile
|
||||
from PIL import Image
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class EmailOrPhoneAuthenticationForm(AuthenticationForm):
|
||||
username = forms.CharField(
|
||||
@ -315,3 +318,36 @@ class RegistrationForm(forms.Form):
|
||||
class VerifyEmailForm(forms.Form):
|
||||
email = forms.EmailField(label="Email")
|
||||
code = forms.CharField(max_length=32, label="Код из письма")
|
||||
|
||||
class CustomPasswordResetForm(PasswordResetForm):
|
||||
"""Кастомная форма восстановления пароля с логированием"""
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
"""Переопределяем save для логирования процесса отправки"""
|
||||
email = self.cleaned_data["email"]
|
||||
|
||||
logger.info(
|
||||
f"\n{'='*80}\n"
|
||||
f"[CustomPasswordResetForm.save] 🔐 СОХРАНЕНИЕ ФОРМЫ ВОССТАНОВЛЕНИЯ ПАРОЛЯ\n"
|
||||
f" Email: {email}\n"
|
||||
f"{'='*80}"
|
||||
)
|
||||
|
||||
# Используем встроенный метод get_users - это не статический метод,
|
||||
# а внутренний механизм Django для получения пользователей
|
||||
logger.info(
|
||||
f"[CustomPasswordResetForm.save] ➡️ Вызов super().save() для отправки emails..."
|
||||
)
|
||||
|
||||
try:
|
||||
result = super().save(*args, **kwargs)
|
||||
logger.info(
|
||||
f"[CustomPasswordResetForm.save] ✅ super().save() успешно завершен"
|
||||
)
|
||||
return result
|
||||
except Exception as e:
|
||||
logger.error(
|
||||
f"[CustomPasswordResetForm.save] ❌ Ошибка в super().save(): {type(e).__name__}: {e}",
|
||||
exc_info=True
|
||||
)
|
||||
raise
|
||||
@ -1,5 +1,6 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
from api.client import ApiClient, get_api_client
|
||||
from django.contrib import messages
|
||||
from django.contrib.auth import logout
|
||||
@ -20,7 +21,9 @@ from django.views import View
|
||||
from django.views.decorators.http import require_http_methods
|
||||
|
||||
from .forms_auth import (EmailOrPhoneAuthenticationForm, RegistrationForm,
|
||||
VerifyEmailForm)
|
||||
VerifyEmailForm, CustomPasswordResetForm)
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def _apply_api_errors_to_form(form, data: dict):
|
||||
@ -65,9 +68,6 @@ def register_view(request):
|
||||
Страница регистрации: показываем Django-форму и шлём валидные данные в /api/v1/auth/register/
|
||||
(аватар пока локально, в API не отправляем — загрузим после верификации).
|
||||
"""
|
||||
import logging
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
api = get_api_client(request)
|
||||
|
||||
if request.method == "GET":
|
||||
@ -220,6 +220,27 @@ class PasswordResetView(DjangoPasswordResetView):
|
||||
html_email_template_name = "emails/password_reset_email.html"
|
||||
subject_template_name = "auth/password_reset_subject.txt"
|
||||
success_url = "/auth/password-reset/done/"
|
||||
form_class = CustomPasswordResetForm
|
||||
|
||||
def post(self, request, *args, **kwargs):
|
||||
"""Переопределяем post для логирования"""
|
||||
logger.info(
|
||||
f"\n{'='*80}\n"
|
||||
f"[PasswordResetView.post] 🔑 ЗАПРОС НА ВОССТАНОВЛЕНИЕ ПАРОЛЯ\n"
|
||||
f" Email/телефон: {request.POST.get('email', '?')}\n"
|
||||
f" IP: {request.META.get('REMOTE_ADDR')}\n"
|
||||
f"{'='*80}"
|
||||
)
|
||||
|
||||
return super().post(request, *args, **kwargs)
|
||||
|
||||
def form_valid(self, form):
|
||||
"""Логирование успешной валидации формы"""
|
||||
logger.info(
|
||||
f"[PasswordResetView.form_valid] ✅ Форма валидна, email={form.cleaned_data.get('email')}"
|
||||
)
|
||||
|
||||
return super().form_valid(form)
|
||||
|
||||
|
||||
class PasswordResetDoneView(DjangoPasswordResetDoneView):
|
||||
|
||||
@ -208,6 +208,10 @@ LOGGING = {
|
||||
"documents": {"handlers": ["console"], "level": "DEBUG", "propagate": False},
|
||||
"bots": {"handlers": ["console"], "level": "DEBUG", "propagate": False},
|
||||
"communications": {"handlers": ["console"], "level": "DEBUG", "propagate": False},
|
||||
"notifications": {"handlers": ["console"], "level": "INFO", "propagate": False},
|
||||
"requests_app": {"handlers": ["console"], "level": "DEBUG", "propagate": False},
|
||||
"employees": {"handlers": ["console"], "level": "INFO", "propagate": False},
|
||||
"common": {"handlers": ["console"], "level": "INFO", "propagate": False},
|
||||
"django": {"handlers": ["console"], "level": "INFO", "propagate": False},
|
||||
"aiogram": {"handlers": ["console"], "level": "INFO", "propagate": False},
|
||||
# полезно видеть ошибки и отладку ldap3
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user