from rest_framework import serializers
from django.utils.html import strip_tags, escape
from django.core.exceptions import ValidationError
import re
from .models import ContactSubmission
class ContactSubmissionSerializer(serializers.ModelSerializer):
"""
Serializer for ContactSubmission model.
Handles both creation and retrieval of contact form submissions.
"""
# Computed fields
full_name = serializers.ReadOnlyField()
is_high_priority = serializers.ReadOnlyField()
is_enterprise_client = serializers.ReadOnlyField()
industry_display = serializers.SerializerMethodField()
project_type_display = serializers.SerializerMethodField()
budget_display = serializers.SerializerMethodField()
class Meta:
model = ContactSubmission
fields = [
'id',
'first_name',
'last_name',
'full_name',
'email',
'phone',
'company',
'job_title',
'industry',
'industry_display',
'company_size',
'project_type',
'project_type_display',
'timeline',
'budget',
'budget_display',
'message',
'newsletter_subscription',
'privacy_consent',
'status',
'priority',
'is_high_priority',
'is_enterprise_client',
'created_at',
'updated_at',
'admin_notes',
'assigned_to',
]
read_only_fields = [
'id',
'status',
'priority',
'created_at',
'updated_at',
'admin_notes',
'assigned_to',
]
def get_industry_display(self, obj):
return obj.get_industry_display()
def get_project_type_display(self, obj):
return obj.get_project_type_display()
def get_budget_display(self, obj):
return obj.get_budget_display()
def validate_email(self, value):
"""
Custom email validation to ensure it's a business email.
"""
if value and not any(domain in value.lower() for domain in ['@gmail.com', '@yahoo.com', '@hotmail.com']):
return value
# Allow personal emails but log them
return value
def validate_privacy_consent(self, value):
"""
Ensure privacy consent is given.
"""
if not value:
raise serializers.ValidationError("Privacy consent is required to submit the form.")
return value
def validate(self, attrs):
"""
Cross-field validation.
"""
# Ensure required fields are present
required_fields = ['first_name', 'last_name', 'email', 'company', 'job_title', 'message']
for field in required_fields:
if not attrs.get(field):
raise serializers.ValidationError(f"{field.replace('_', ' ').title()} is required.")
# Validate enterprise client indicators
if attrs.get('company_size') in ['201-1000', '1000+'] and attrs.get('budget') in ['under-50k', '50k-100k']:
# This might be a mismatch, but we'll allow it and flag for review
pass
return attrs
class ContactSubmissionCreateSerializer(serializers.ModelSerializer):
"""
Simplified serializer for creating contact submissions.
Only includes fields that should be provided by the frontend.
"""
class Meta:
model = ContactSubmission
fields = [
'first_name',
'last_name',
'email',
'phone',
'company',
'job_title',
'industry',
'company_size',
'project_type',
'timeline',
'budget',
'message',
'newsletter_subscription',
'privacy_consent',
]
def _sanitize_text_field(self, value):
"""
Sanitize text fields by detecting and rejecting HTML/script tags.
Returns cleaned text or raises ValidationError if dangerous content is detected.
"""
if not value:
return value
# Check for script tags and other dangerous HTML patterns
dangerous_patterns = [
(r'', 'Script tags are not allowed'),
(r'', 'Iframe tags are not allowed'),
(r'javascript:', 'JavaScript protocol is not allowed'),
(r'on\w+\s*=', 'Event handlers are not allowed'),
(r'