feat: add contact form functionality with admin management
Add a complete contact form system with the following changes: - Create ContactMessage model to store form submissions with tracking fields (is_read, is_responded) - Implement ContactMessage admin interface with custom actions, filters, and bulk operations - Add contact endpoint documentation to API root view - Update email configuration to use admin@attunehearttherapy.com as sender address This enables users to submit contact inquiries and allows administrators to track and manage these messages efficiently through the Django admin panel.
This commit is contained in:
parent
23c185c93d
commit
cd5ad1d753
@ -139,9 +139,9 @@ EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
|
||||
EMAIL_HOST = os.getenv('SMTP_HOST', 'smtp.hostinger.com')
|
||||
EMAIL_PORT = int(os.getenv('SMTP_PORT', 465))
|
||||
EMAIL_USE_SSL = True
|
||||
EMAIL_HOST_USER = os.getenv('SMTP_USERNAME', 'hello@attunehearttherapy.com')
|
||||
EMAIL_HOST_USER = os.getenv('SMTP_USERNAME', 'admin@attunehearttherapy.com')
|
||||
EMAIL_HOST_PASSWORD = os.getenv('SMTP_PASSWORD')
|
||||
DEFAULT_FROM_EMAIL = os.getenv('SMTP_FROM', 'hello@attunehearttherapy.com')
|
||||
DEFAULT_FROM_EMAIL = os.getenv('SMTP_FROM', 'admin@attunehearttherapy.com')
|
||||
|
||||
|
||||
REST_FRAMEWORK = {
|
||||
|
||||
@ -8,6 +8,24 @@ def api_root(request, format=None):
|
||||
base_url = request.build_absolute_uri('/api/')
|
||||
|
||||
endpoints = {
|
||||
'contact': {
|
||||
'description': 'Contact form submission endpoint',
|
||||
'base_path': '/api/auth/',
|
||||
'endpoints': {
|
||||
'contact': {
|
||||
'description': 'Submit a contact form',
|
||||
'url': request.build_absolute_uri('/api/auth/contact/'),
|
||||
'methods': ['POST'],
|
||||
'required_fields': ['name', 'email', 'phone', 'message'],
|
||||
'example_request': {
|
||||
'name': 'John Doe',
|
||||
'email': 'n8E5I@example.com',
|
||||
'phone': '+1234567890',
|
||||
'message': 'Hello, how can I help you?'
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
'authentication': {
|
||||
'description': 'User authentication and management endpoints',
|
||||
'base_path': '/api/auth/',
|
||||
|
||||
@ -0,0 +1,18 @@
|
||||
# Generated by Django 5.2.8 on 2025-11-28 15:37
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('meetings', '0001_initial'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='appointmentrequest',
|
||||
name='jitsi_room_id',
|
||||
field=models.CharField(blank=True, default=None, help_text='Jitsi room ID', max_length=100, null=True, unique=True),
|
||||
),
|
||||
]
|
||||
105
templates/emails/admin_contact_notification.html
Normal file
105
templates/emails/admin_contact_notification.html
Normal file
@ -0,0 +1,105 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>New Contact Form Submission</title>
|
||||
</head>
|
||||
<body style="margin: 0; padding: 0; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif; background-color: #f3f4f6;">
|
||||
<table width="100%" cellpadding="0" cellspacing="0" style="background-color: #f3f4f6; padding: 40px 0;">
|
||||
<tr>
|
||||
<td align="center">
|
||||
<table width="600" cellpadding="0" cellspacing="0" style="background-color: #ffffff; border-radius: 12px; box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);">
|
||||
|
||||
<tr>
|
||||
<td style="background: linear-gradient(135deg, #f43f5e 0%, #ec4899 100%); padding: 40px; border-radius: 12px 12px 0 0; text-align: center;">
|
||||
<h1 style="margin: 0; color: #ffffff; font-size: 28px; font-weight: 700;">
|
||||
🔔 New Contact Message
|
||||
</h1>
|
||||
<p style="margin: 10px 0 0 0; color: #fce7f3; font-size: 16px;">
|
||||
Someone just reached out to you
|
||||
</p>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td style="padding: 40px;">
|
||||
<table width="100%" cellpadding="0" cellspacing="0" style="margin-bottom: 30px;">
|
||||
<tr>
|
||||
<td colspan="2" style="padding-bottom: 20px;">
|
||||
<h2 style="margin: 0; color: #111827; font-size: 20px; font-weight: 600;">
|
||||
Contact Information
|
||||
</h2>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="padding: 12px 0; width: 120px; color: #6b7280; font-size: 14px; font-weight: 600;">
|
||||
Name:
|
||||
</td>
|
||||
<td style="padding: 12px 0; color: #111827; font-size: 14px;">
|
||||
{{ contact_message.name }}
|
||||
</td>
|
||||
</tr>
|
||||
<tr style="border-top: 1px solid #e5e7eb;">
|
||||
<td style="padding: 12px 0; width: 120px; color: #6b7280; font-size: 14px; font-weight: 600;">
|
||||
Email:
|
||||
</td>
|
||||
<td style="padding: 12px 0;">
|
||||
<a href="mailto:{{ contact_message.email }}" style="color: #f43f5e; text-decoration: none; font-size: 14px;">
|
||||
{{ contact_message.email }}
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
{% if contact_message.phone %}
|
||||
<tr style="border-top: 1px solid #e5e7eb;">
|
||||
<td style="padding: 12px 0; width: 120px; color: #6b7280; font-size: 14px; font-weight: 600;">
|
||||
Phone:
|
||||
</td>
|
||||
<td style="padding: 12px 0;">
|
||||
<a href="tel:{{ contact_message.phone }}" style="color: #f43f5e; text-decoration: none; font-size: 14px;">
|
||||
{{ contact_message.phone }}
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
<tr style="border-top: 1px solid #e5e7eb;">
|
||||
<td style="padding: 12px 0; width: 120px; color: #6b7280; font-size: 14px; font-weight: 600;">
|
||||
Received:
|
||||
</td>
|
||||
<td style="padding: 12px 0; color: #111827; font-size: 14px;">
|
||||
{{ contact_message.created_at|date:"F d, Y" }} at {{ contact_message.created_at|time:"h:i A" }}
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<div style="margin-bottom: 30px;">
|
||||
<h2 style="margin: 0 0 15px 0; color: #111827; font-size: 20px; font-weight: 600;">
|
||||
Message
|
||||
</h2>
|
||||
<div style="background-color: #f9fafb; border: 1px solid #e5e7eb; border-radius: 8px; padding: 20px;">
|
||||
<p style="margin: 0; color: #374151; font-size: 14px; line-height: 1.6; white-space: pre-wrap;">{{ contact_message.message }}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style="text-align: center; margin-top: 30px;">
|
||||
<a href="mailto:{{ contact_message.email }}" style="display: inline-block; background: linear-gradient(135deg, #f43f5e 0%, #ec4899 100%); color: #ffffff; text-decoration: none; padding: 14px 32px; border-radius: 8px; font-weight: 600; font-size: 15px; box-shadow: 0 4px 6px rgba(244, 63, 94, 0.3);">
|
||||
Reply to {{ contact_message.name }}
|
||||
</a>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td style="background-color: #f9fafb; padding: 30px; border-radius: 0 0 12px 12px; text-align: center; border-top: 1px solid #e5e7eb;">
|
||||
<p style="margin: 0; color: #6b7280; font-size: 13px; line-height: 1.6;">
|
||||
This is an automated notification from your contact form.<br>
|
||||
Please respond to the sender as soon as possible.
|
||||
</p>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</body>
|
||||
</html>
|
||||
80
templates/emails/user_contact_confirmation.html
Normal file
80
templates/emails/user_contact_confirmation.html
Normal file
@ -0,0 +1,80 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Thank You for Contacting Us</title>
|
||||
</head>
|
||||
<body style="margin: 0; padding: 0; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif; background-color: #f3f4f6;">
|
||||
<table width="100%" cellpadding="0" cellspacing="0" style="background-color: #f3f4f6; padding: 40px 0;">
|
||||
<tr>
|
||||
<td align="center">
|
||||
<table width="600" cellpadding="0" cellspacing="0" style="background-color: #ffffff; border-radius: 12px; box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);">
|
||||
<tr>
|
||||
<td style="background: linear-gradient(135deg, #f43f5e 0%, #ec4899 100%); padding: 40px; border-radius: 12px 12px 0 0; text-align: center;">
|
||||
<h1 style="margin: 0; color: #ffffff; font-size: 28px; font-weight: 700;">
|
||||
✨ Thank You!
|
||||
</h1>
|
||||
<p style="margin: 10px 0 0 0; color: #fce7f3; font-size: 16px;">
|
||||
We've received your message
|
||||
</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="padding: 40px;">
|
||||
<div style="text-align: center; margin-bottom: 30px;">
|
||||
<div style="display: inline-block; background-color: #fef2f2; border-radius: 50%; padding: 20px; margin-bottom: 20px;">
|
||||
<span style="font-size: 48px;">✅</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h2 style="margin: 0 0 20px 0; color: #111827; font-size: 22px; font-weight: 600; text-align: center;">
|
||||
Hi {{ contact_message.name }},
|
||||
</h2>
|
||||
|
||||
<p style="margin: 0 0 20px 0; color: #374151; font-size: 16px; line-height: 1.6; text-align: center;">
|
||||
Thank you for reaching out to us. We've received your message and our team will review it shortly. We typically respond within 24-48 hours.
|
||||
</p>
|
||||
<div style="background-color: #f9fafb; border: 1px solid #e5e7eb; border-radius: 8px; padding: 25px; margin: 30px 0;">
|
||||
<h3 style="margin: 0 0 15px 0; color: #111827; font-size: 16px; font-weight: 600;">
|
||||
Your Message:
|
||||
</h3>
|
||||
<p style="margin: 0; color: #6b7280; font-size: 14px; line-height: 1.6; white-space: pre-wrap;">{{ contact_message.message }}</p>
|
||||
</div>
|
||||
<div style="background-color: #fef2f2; border-left: 4px solid #f43f5e; padding: 20px; border-radius: 6px; margin: 30px 0;">
|
||||
<p style="margin: 0 0 10px 0; color: #991b1b; font-weight: 600; font-size: 14px;">
|
||||
📧 We'll reply to:
|
||||
</p>
|
||||
<p style="margin: 0; color: #b91c1c; font-size: 14px;">
|
||||
{{ contact_message.email }}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<p style="margin: 30px 0 0 0; color: #6b7280; font-size: 14px; line-height: 1.6; text-align: center;">
|
||||
If you have any urgent questions in the meantime, please don't hesitate to reach out to us directly.
|
||||
</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="background-color: #f9fafb; padding: 30px; border-radius: 0 0 12px 12px; text-align: center; border-top: 1px solid #e5e7eb;">
|
||||
<p style="margin: 0 0 15px 0; color: #111827; font-size: 14px; font-weight: 600;">
|
||||
Need immediate assistance?
|
||||
</p>
|
||||
<p style="margin: 0; color: #6b7280; font-size: 13px; line-height: 1.6;">
|
||||
Email us at <a href="mailto:{{support_email}}" style="color: #f43f5e; text-decoration: none;">{{support_email}}</a><br>
|
||||
or call us at <a href="tel:+1754816-2311" style="color: #f43f5e; text-decoration: none;">+1 (754) 816-2311</a>
|
||||
</p>
|
||||
|
||||
<div style="margin-top: 20px; padding-top: 20px; border-top: 1px solid #e5e7eb;">
|
||||
<p style="margin: 0 0 10px 0; color: #9ca3af; font-size: 12px;">
|
||||
© {{ current_year }} {{ company_name }}. All rights reserved.
|
||||
</p>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</body>
|
||||
</html>
|
||||
@ -1,7 +1,5 @@
|
||||
from django.contrib import admin
|
||||
from .models import CustomUser, UserProfile
|
||||
|
||||
# Register your models here.
|
||||
from .models import CustomUser, UserProfile, ContactMessage
|
||||
|
||||
@admin.register(CustomUser)
|
||||
class UserAdmin(admin.ModelAdmin):
|
||||
@ -17,3 +15,41 @@ class UserProfileAdmin(admin.ModelAdmin):
|
||||
ordering = ('user__email',)
|
||||
|
||||
|
||||
|
||||
@admin.register(ContactMessage)
|
||||
class ContactMessageAdmin(admin.ModelAdmin):
|
||||
list_display = ['name', 'email', 'phone', 'created_at', 'is_read', 'is_responded']
|
||||
list_filter = ['is_read', 'is_responded', 'created_at']
|
||||
search_fields = ['name', 'email', 'phone', 'message']
|
||||
readonly_fields = ['created_at']
|
||||
date_hierarchy = 'created_at'
|
||||
|
||||
fieldsets = (
|
||||
('Contact Information', {
|
||||
'fields': ('name', 'email', 'phone')
|
||||
}),
|
||||
('Message', {
|
||||
'fields': ('message',)
|
||||
}),
|
||||
('Status', {
|
||||
'fields': ('is_read', 'is_responded', 'created_at')
|
||||
}),
|
||||
)
|
||||
|
||||
def get_queryset(self, request):
|
||||
qs = super().get_queryset(request)
|
||||
return qs.select_related()
|
||||
|
||||
actions = ['mark_as_read', 'mark_as_responded']
|
||||
|
||||
def mark_as_read(self, request, queryset):
|
||||
updated = queryset.update(is_read=True)
|
||||
self.message_user(request, f'{updated} message(s) marked as read.')
|
||||
mark_as_read.short_description = "Mark selected as read"
|
||||
|
||||
def mark_as_responded(self, request, queryset):
|
||||
updated = queryset.update(is_responded=True)
|
||||
self.message_user(request, f'{updated} message(s) marked as responded.')
|
||||
mark_as_responded.short_description = "Mark selected as responded"
|
||||
|
||||
|
||||
|
||||
31
users/migrations/0002_contactmessage.py
Normal file
31
users/migrations/0002_contactmessage.py
Normal file
@ -0,0 +1,31 @@
|
||||
# Generated by Django 5.2.8 on 2025-11-28 15:37
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('users', '0001_initial'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='ContactMessage',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('name', models.CharField(max_length=255)),
|
||||
('email', models.EmailField(max_length=254)),
|
||||
('phone', models.CharField(blank=True, max_length=20)),
|
||||
('message', models.TextField()),
|
||||
('created_at', models.DateTimeField(auto_now_add=True)),
|
||||
('is_read', models.BooleanField(default=False)),
|
||||
('is_responded', models.BooleanField(default=False)),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'Contact Message',
|
||||
'verbose_name_plural': 'Contact Messages',
|
||||
'ordering': ['-created_at'],
|
||||
},
|
||||
),
|
||||
]
|
||||
@ -38,3 +38,21 @@ class UserProfile(models.Model):
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.user.email} Profile"
|
||||
|
||||
|
||||
class ContactMessage(models.Model):
|
||||
name = models.CharField(max_length=255)
|
||||
email = models.EmailField()
|
||||
phone = models.CharField(max_length=20, blank=True)
|
||||
message = models.TextField()
|
||||
created_at = models.DateTimeField(auto_now_add=True)
|
||||
is_read = models.BooleanField(default=False)
|
||||
is_responded = models.BooleanField(default=False)
|
||||
|
||||
class Meta:
|
||||
ordering = ['-created_at']
|
||||
verbose_name = 'Contact Message'
|
||||
verbose_name_plural = 'Contact Messages'
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.name} - {self.email} - {self.created_at.strftime('%Y-%m-%d')}"
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
from rest_framework import serializers
|
||||
from django.contrib.auth.password_validation import validate_password
|
||||
from .models import CustomUser, UserProfile
|
||||
from .models import CustomUser, UserProfile, ContactMessage
|
||||
|
||||
class UserProfileSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
@ -54,3 +54,22 @@ class UserSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = CustomUser
|
||||
fields = ('id', 'email', 'first_name', 'last_name', 'phone_number', 'isVerified', 'date_joined', 'last_login', 'is_staff', 'is_superuser', 'is_active')
|
||||
|
||||
from rest_framework import serializers
|
||||
from .models import ContactMessage
|
||||
|
||||
class ContactMessageSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = ContactMessage
|
||||
fields = ['id', 'name', 'email', 'phone', 'message', 'created_at']
|
||||
read_only_fields = ['id', 'created_at']
|
||||
|
||||
def validate_name(self, value):
|
||||
if len(value.strip()) < 2:
|
||||
raise serializers.ValidationError("Name must be at least 2 characters long.")
|
||||
return value.strip()
|
||||
|
||||
def validate_message(self, value):
|
||||
if len(value.strip()) < 10:
|
||||
raise serializers.ValidationError("Message must be at least 10 characters long.")
|
||||
return value.strip()
|
||||
|
||||
@ -3,6 +3,8 @@ from rest_framework_simplejwt.views import TokenRefreshView
|
||||
from . import views
|
||||
|
||||
urlpatterns = [
|
||||
path('contact/', views.ContactMessageView.as_view(), name='contact-message'),
|
||||
|
||||
|
||||
path('register/', views.register_user, name='register'),
|
||||
path('login/', views.login_user, name='login'),
|
||||
|
||||
@ -6,6 +6,9 @@ from django.conf import settings
|
||||
from django.core.mail import EmailMultiAlternatives
|
||||
from django.template.loader import render_to_string
|
||||
from django.utils.html import strip_tags
|
||||
import logging
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
def generate_otp():
|
||||
return str(random.randint(100000, 999999))
|
||||
@ -55,3 +58,48 @@ def is_otp_expired(otp_expiry):
|
||||
if otp_expiry and timezone.now() < otp_expiry:
|
||||
return False
|
||||
return True
|
||||
|
||||
def send_email_notifications(contact_message):
|
||||
try:
|
||||
send_admin_notification(contact_message)
|
||||
|
||||
|
||||
send_user_confirmation(contact_message)
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error sending email notifications: {str(e)}")
|
||||
|
||||
def send_admin_notification(contact_message):
|
||||
subject = f"New Contact Form Submission from {contact_message.name}"
|
||||
|
||||
html_content = render_to_string('emails/admin_contact_notification.html', {
|
||||
'contact_message': contact_message
|
||||
})
|
||||
|
||||
email = EmailMultiAlternatives(
|
||||
subject=subject,
|
||||
body=html_content,
|
||||
from_email=settings.DEFAULT_FROM_EMAIL,
|
||||
to=[settings.DEFAULT_FROM_EMAIL]
|
||||
)
|
||||
email.content_subtype = 'html'
|
||||
email.send()
|
||||
|
||||
def send_user_confirmation(self, contact_message):
|
||||
subject = "Thank you for contacting us"
|
||||
|
||||
html_content = render_to_string('emails/user_contact_confirmation.html', {
|
||||
'contact_message': contact_message,
|
||||
'company_name': 'Attune Heart Therapy',
|
||||
'support_email': 'admin@attunehearttherapy.com',
|
||||
'current_year': timezone.now().year,
|
||||
})
|
||||
|
||||
email = EmailMultiAlternatives(
|
||||
subject=subject,
|
||||
body=html_content,
|
||||
from_email=settings.DEFAULT_FROM_EMAIL,
|
||||
to=[contact_message.email]
|
||||
)
|
||||
email.content_subtype = 'html'
|
||||
email.send()
|
||||
|
||||
@ -1,16 +1,51 @@
|
||||
from rest_framework import status, generics
|
||||
from rest_framework.decorators import api_view, permission_classes
|
||||
from rest_framework.views import APIView
|
||||
from rest_framework.response import Response
|
||||
from rest_framework.permissions import AllowAny, IsAuthenticated, IsAdminUser
|
||||
from rest_framework_simplejwt.tokens import RefreshToken
|
||||
from django.contrib.auth import authenticate
|
||||
from .models import CustomUser, UserProfile
|
||||
from .serializers import UserRegistrationSerializer, UserSerializer, ResetPasswordSerializer, ForgotPasswordSerializer, VerifyPasswordResetOTPSerializer
|
||||
from .utils import send_otp_via_email, is_otp_expired, generate_otp
|
||||
from .models import CustomUser, UserProfile, ContactMessage
|
||||
from .serializers import UserRegistrationSerializer, UserSerializer, ResetPasswordSerializer, ForgotPasswordSerializer, VerifyPasswordResetOTPSerializer, ContactMessageSerializer
|
||||
from .utils import send_otp_via_email, is_otp_expired, generate_otp,send_email_notifications
|
||||
from django.utils import timezone
|
||||
from datetime import timedelta
|
||||
from rest_framework.reverse import reverse
|
||||
from meetings.models import AppointmentRequest
|
||||
import logging
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
class ContactMessageView(APIView):
|
||||
def post(self, request):
|
||||
serializer = ContactMessageSerializer(data=request.data)
|
||||
|
||||
if serializer.is_valid():
|
||||
try:
|
||||
contact_message = serializer.save()
|
||||
|
||||
send_email_notifications(contact_message)
|
||||
|
||||
return Response({
|
||||
'success': True,
|
||||
'message': 'Thank you for your message. We will get back to you soon!',
|
||||
'data': serializer.data
|
||||
}, status=status.HTTP_201_CREATED)
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error processing contact form: {str(e)}")
|
||||
return Response({
|
||||
'success': False,
|
||||
'message': 'There was an error processing your request. Please try again later.'
|
||||
}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
|
||||
|
||||
return Response({
|
||||
'success': False,
|
||||
'message': 'Please check your input and try again.',
|
||||
'errors': serializer.errors
|
||||
}, status=status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
|
||||
|
||||
|
||||
@api_view(['POST'])
|
||||
|
||||
Loading…
Reference in New Issue
Block a user