Files
GNX-mailEnterprise/emails/serializers.py
Iliyan Angelov 9454b6ae19 update
2025-09-22 20:29:41 +03:00

301 lines
9.7 KiB
Python

from rest_framework import serializers
from django.contrib.auth import get_user_model
from .models import (
Email, EmailFolder, EmailAttachment, EmailThread, EmailTemplate,
EmailSignature, EmailRule, EmailSearch
)
User = get_user_model()
class EmailFolderSerializer(serializers.ModelSerializer):
"""Serializer for email folders."""
email_count = serializers.SerializerMethodField()
unread_count = serializers.SerializerMethodField()
class Meta:
model = EmailFolder
fields = '__all__'
read_only_fields = ('user', 'created_at', 'updated_at')
def get_email_count(self, obj):
return obj.emails.count()
def get_unread_count(self, obj):
return obj.emails.filter(is_read=False).count()
class EmailAttachmentSerializer(serializers.ModelSerializer):
"""Serializer for email attachments."""
class Meta:
model = EmailAttachment
fields = '__all__'
read_only_fields = ('created_at',)
class EmailSerializer(serializers.ModelSerializer):
"""Serializer for emails."""
attachments = EmailAttachmentSerializer(many=True, read_only=True)
folder_name = serializers.CharField(source='folder.name', read_only=True)
from_name = serializers.SerializerMethodField()
recipients = serializers.SerializerMethodField()
thread_count = serializers.SerializerMethodField()
class Meta:
model = Email
fields = '__all__'
read_only_fields = ('uuid', 'user', 'message_id', 'created_at', 'updated_at')
def get_from_name(self, obj):
# Try to get name from contacts or use email
return obj.from_email
def get_recipients(self, obj):
return {
'to': obj.to_emails,
'cc': obj.cc_emails,
'bcc': obj.bcc_emails,
}
def get_thread_count(self, obj):
return obj.threads.count()
class JSONListField(serializers.Field):
"""Custom field to handle JSON strings for email lists."""
def to_internal_value(self, data):
import json
if isinstance(data, str):
try:
return json.loads(data)
except json.JSONDecodeError:
# If it's not valid JSON, treat as a single email
return [data] if data else []
return data or []
def to_representation(self, value):
return value
class EmailCreateSerializer(serializers.ModelSerializer):
"""Serializer for creating emails."""
attachments = serializers.ListField(
child=serializers.FileField(),
required=False,
write_only=True
)
# Override email fields to use custom JSON field
to_emails = JSONListField()
cc_emails = JSONListField(required=False)
bcc_emails = JSONListField(required=False)
class Meta:
model = Email
fields = (
'subject', 'to_emails', 'cc_emails', 'bcc_emails', 'reply_to',
'body_text', 'body_html', 'priority', 'attachments'
)
def validate_to_emails(self, value):
if not value:
raise serializers.ValidationError("At least one recipient is required.")
return value
def validate_cc_emails(self, value):
return value or []
def validate_bcc_emails(self, value):
return value or []
def create(self, validated_data):
attachments_data = validated_data.pop('attachments', [])
user = self.context['request'].user
# Set from_email to user's email
validated_data['from_email'] = user.email
# Set default folder to "Sent" if not specified
if 'folder' not in validated_data:
try:
sent_folder = EmailFolder.objects.get(user=user, folder_type='sent')
validated_data['folder'] = sent_folder
except EmailFolder.DoesNotExist:
# Fallback to first available folder
folder = EmailFolder.objects.filter(user=user).first()
if folder:
validated_data['folder'] = folder
# Create email
email = Email.objects.create(user=user, **validated_data)
# Handle attachments
for attachment_file in attachments_data:
EmailAttachment.objects.create(
email=email,
filename=attachment_file.name,
content_type=attachment_file.content_type,
size=attachment_file.size,
file=attachment_file
)
return email
class EmailReplySerializer(serializers.ModelSerializer):
"""Serializer for replying to emails."""
original_email = serializers.PrimaryKeyRelatedField(queryset=Email.objects.all())
class Meta:
model = Email
fields = ('original_email', 'subject', 'body_text', 'body_html', 'priority')
def create(self, validated_data):
original_email = validated_data.pop('original_email')
user = self.context['request'].user
# Set reply headers
validated_data.update({
'user': user,
'from_email': user.email,
'to_emails': [original_email.from_email],
'in_reply_to': original_email.message_id,
'references': f"{original_email.references} {original_email.message_id}".strip(),
'folder': EmailFolder.objects.get(user=user, folder_type='sent'),
})
# Add "Re: " prefix if not already present
subject = validated_data.get('subject', '')
if not subject.startswith('Re: '):
validated_data['subject'] = f"Re: {subject}"
return Email.objects.create(**validated_data)
class EmailForwardSerializer(serializers.ModelSerializer):
"""Serializer for forwarding emails."""
original_email = serializers.PrimaryKeyRelatedField(queryset=Email.objects.all())
class Meta:
model = Email
fields = ('original_email', 'to_emails', 'cc_emails', 'bcc_emails', 'subject', 'body_text', 'body_html', 'priority')
def create(self, validated_data):
original_email = validated_data.pop('original_email')
user = self.context['request'].user
# Set forward headers
validated_data.update({
'user': user,
'from_email': user.email,
'in_reply_to': original_email.message_id,
'folder': EmailFolder.objects.get(user=user, folder_type='sent'),
})
# Add "Fwd: " prefix if not already present
subject = validated_data.get('subject', '')
if not subject.startswith('Fwd: '):
validated_data['subject'] = f"Fwd: {subject}"
# Add original email content
original_content = f"\n\n--- Forwarded message ---\nFrom: {original_email.from_email}\nDate: {original_email.sent_at}\nSubject: {original_email.subject}\n\n{original_email.body_text}"
validated_data['body_text'] += original_content
return Email.objects.create(**validated_data)
class EmailThreadSerializer(serializers.ModelSerializer):
"""Serializer for email threads."""
emails = EmailSerializer(many=True, read_only=True)
email_count = serializers.SerializerMethodField()
class Meta:
model = EmailThread
fields = '__all__'
def get_email_count(self, obj):
return obj.emails.count()
class EmailTemplateSerializer(serializers.ModelSerializer):
"""Serializer for email templates."""
class Meta:
model = EmailTemplate
fields = '__all__'
read_only_fields = ('user', 'created_at', 'updated_at')
class EmailSignatureSerializer(serializers.ModelSerializer):
"""Serializer for email signatures."""
class Meta:
model = EmailSignature
fields = '__all__'
read_only_fields = ('user', 'created_at', 'updated_at')
class EmailRuleSerializer(serializers.ModelSerializer):
"""Serializer for email rules."""
class Meta:
model = EmailRule
fields = '__all__'
read_only_fields = ('user', 'created_at', 'updated_at')
class EmailSearchSerializer(serializers.ModelSerializer):
"""Serializer for email searches."""
class Meta:
model = EmailSearch
fields = '__all__'
read_only_fields = ('user', 'created_at')
class EmailBulkActionSerializer(serializers.Serializer):
"""Serializer for bulk email actions."""
ACTION_CHOICES = [
('mark_read', 'Mark as read'),
('mark_unread', 'Mark as unread'),
('mark_starred', 'Mark as starred'),
('mark_unstarred', 'Mark as unstarred'),
('mark_important', 'Mark as important'),
('mark_unimportant', 'Mark as unimportant'),
('move_to_folder', 'Move to folder'),
('delete', 'Delete'),
]
email_ids = serializers.ListField(
child=serializers.IntegerField(),
min_length=1
)
action = serializers.ChoiceField(choices=ACTION_CHOICES)
folder_id = serializers.IntegerField(required=False)
def validate_email_ids(self, value):
user = self.context['request'].user
# Verify all emails belong to the user
email_count = Email.objects.filter(id__in=value, user=user).count()
if email_count != len(value):
raise serializers.ValidationError("Some emails don't exist or don't belong to you.")
return value
def validate(self, attrs):
action = attrs.get('action')
folder_id = attrs.get('folder_id')
if action == 'move_to_folder' and not folder_id:
raise serializers.ValidationError("folder_id is required for move_to_folder action.")
return attrs