feat: add FAQ question form with email notifications and validations
All checks were successful
Build and Push Docker Image / build (push) Successful in 43s
All checks were successful
Build and Push Docker Image / build (push) Successful in 43s
- Created `FaqQuestionForm` in `forms.py` with custom field validations - Added FAQ form to the FAQ section with CSRF protection and error handling - Integrated email notifications to administrator upon FAQ submission - Updated styles and scripts for form inputs, validation messages, and messages UI - Adjusted FAQ section layout in `faq.html` and related CSS for responsiveness - Implemented tests for FAQ form submission and email notifications
This commit is contained in:
32
home/forms.py
Normal file
32
home/forms.py
Normal file
@@ -0,0 +1,32 @@
|
||||
from django import forms
|
||||
|
||||
|
||||
class FaqQuestionForm(forms.Form):
|
||||
name = forms.CharField(
|
||||
label="Имя",
|
||||
max_length=150,
|
||||
widget=forms.TextInput(attrs={"placeholder": "Имя", "autocomplete": "name"}),
|
||||
)
|
||||
phone = forms.CharField(
|
||||
label="Номер телефона",
|
||||
max_length=64,
|
||||
widget=forms.TextInput(attrs={"placeholder": "Номер телефона", "autocomplete": "tel"}),
|
||||
)
|
||||
question = forms.CharField(
|
||||
label="Ваш вопрос",
|
||||
max_length=1000,
|
||||
widget=forms.Textarea(attrs={"placeholder": "Ваш вопрос", "rows": 4, "autocomplete": "off"}),
|
||||
)
|
||||
accept = forms.BooleanField(
|
||||
label="Я согласен с политикой обработки персональных данных",
|
||||
error_messages={"required": "Необходимо согласие на обработку персональных данных."},
|
||||
)
|
||||
|
||||
def clean_name(self):
|
||||
return self.cleaned_data["name"].strip()
|
||||
|
||||
def clean_phone(self):
|
||||
return self.cleaned_data["phone"].strip()
|
||||
|
||||
def clean_question(self):
|
||||
return self.cleaned_data["question"].strip()
|
||||
@@ -1,3 +1,38 @@
|
||||
from django.test import TestCase
|
||||
from django.core import mail
|
||||
from django.test import TestCase, override_settings
|
||||
from django.urls import reverse
|
||||
|
||||
# Create your tests here.
|
||||
|
||||
@override_settings(EMAIL_BACKEND="django.core.mail.backends.locmem.EmailBackend", ADMINISTRATOR_EMAIL="admin@example.com")
|
||||
class FaqQuestionTests(TestCase):
|
||||
def test_faq_question_form_sends_email_to_administrator(self):
|
||||
response = self.client.post(
|
||||
reverse("home"),
|
||||
data={
|
||||
"name": "Иван Петров",
|
||||
"phone": "+375291112233",
|
||||
"question": "Сколько стоит доставка?",
|
||||
"accept": "on",
|
||||
},
|
||||
)
|
||||
|
||||
self.assertEqual(response.status_code, 302)
|
||||
self.assertEqual(response["Location"], reverse("home") + "#faq-section")
|
||||
self.assertEqual(len(mail.outbox), 1)
|
||||
self.assertEqual(mail.outbox[0].to, ["admin@example.com"])
|
||||
self.assertIn("Иван Петров", mail.outbox[0].body)
|
||||
self.assertIn("Сколько стоит доставка?", mail.outbox[0].body)
|
||||
|
||||
def test_faq_question_form_requires_consent(self):
|
||||
response = self.client.post(
|
||||
reverse("home"),
|
||||
data={
|
||||
"name": "Иван Петров",
|
||||
"phone": "+375291112233",
|
||||
"question": "Сколько стоит доставка?",
|
||||
},
|
||||
)
|
||||
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertEqual(len(mail.outbox), 0)
|
||||
self.assertContains(response, "Необходимо согласие на обработку персональных данных.")
|
||||
|
||||
@@ -1,8 +1,48 @@
|
||||
from django.shortcuts import render
|
||||
import logging
|
||||
|
||||
from django.conf import settings
|
||||
from django.core.mail import send_mail
|
||||
from django.shortcuts import redirect, render
|
||||
from django.urls import reverse
|
||||
from django.contrib import messages
|
||||
|
||||
from home.forms import FaqQuestionForm
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def index(request):
|
||||
return render(request=request, template_name='home/index.html', context={})
|
||||
form = FaqQuestionForm(request.POST or None)
|
||||
|
||||
if request.method == "POST" and form.is_valid():
|
||||
subject = f"Новый вопрос с сайта {settings.SITE_NAME}"
|
||||
message = "\n".join(
|
||||
[
|
||||
f"Имя: {form.cleaned_data['name']}",
|
||||
f"Телефон: {form.cleaned_data['phone']}",
|
||||
f"Вопрос: {form.cleaned_data['question']}",
|
||||
"",
|
||||
f"Страница: {request.build_absolute_uri('/')}",
|
||||
]
|
||||
)
|
||||
|
||||
try:
|
||||
send_mail(
|
||||
subject=subject,
|
||||
message=message,
|
||||
from_email=settings.DEFAULT_FROM_EMAIL,
|
||||
recipient_list=[settings.ADMINISTRATOR_EMAIL],
|
||||
fail_silently=False,
|
||||
)
|
||||
except Exception:
|
||||
logger.exception("Failed to send FAQ question email")
|
||||
form.add_error(None, "Не удалось отправить вопрос. Попробуйте позже.")
|
||||
else:
|
||||
messages.success(request, "Спасибо. Ваш вопрос отправлен, мы свяжемся с вами в ближайшее время.")
|
||||
return redirect(f"{reverse('home')}#faq-section")
|
||||
|
||||
return render(request=request, template_name='home/index.html', context={"faq_form": form})
|
||||
|
||||
|
||||
def services(request):
|
||||
@@ -18,4 +58,4 @@ def warranty(request):
|
||||
|
||||
|
||||
def contacts(request):
|
||||
return render(request=request, template_name='home/contacts.html', context={})
|
||||
return render(request=request, template_name='home/contacts.html', context={})
|
||||
|
||||
Reference in New Issue
Block a user