from rest_framework import serializers from .models import GmailCredential import json class GmailCredentialSerializer(serializers.ModelSerializer): client_secret_json = serializers.JSONField(write_only=True, required=False, allow_null=True) client_secret_file = serializers.FileField(write_only=True, required=False, allow_null=True) auth_code = serializers.CharField(write_only=True, required=False, allow_blank=True) email = serializers.EmailField(required=False, allow_blank=True) # Make email optional class Meta: model = GmailCredential fields = ['id', 'email', 'is_default', 'created_at', 'updated_at', 'is_valid', 'client_secret_json', 'client_secret_file', 'auth_code'] read_only_fields = ['created_at', 'updated_at', 'is_valid'] def validate(self, data): """Validate client_secret input (either JSON or file).""" client_secret_json = data.get('client_secret_json') client_secret_file = data.get('client_secret_file') auth_code = data.get('auth_code') # For auth initiation, only client_secret is required if not auth_code: # Initiation phase if not client_secret_json and not client_secret_file: raise serializers.ValidationError( "Either client_secret_json or client_secret_file is required." ) if client_secret_json and client_secret_file: raise serializers.ValidationError( "Provide only one of client_secret_json or client_secret_file." ) # For auth completion, both auth_code and client_secret are required if auth_code and not (client_secret_json or client_secret_file): raise serializers.ValidationError( "client_secret_json or client_secret_file is required with auth_code." ) # Parse client_secret_json if provided if client_secret_json: try: json.dumps(client_secret_json) except (TypeError, ValueError): raise serializers.ValidationError("client_secret_json must be valid JSON.") # Parse client_secret_file if provided if client_secret_file: try: content = client_secret_file.read().decode('utf-8') client_secret_json = json.loads(content) data['client_secret_json'] = client_secret_json except (json.JSONDecodeError, UnicodeDecodeError): raise serializers.ValidationError("client_secret_file must contain valid JSON.") return data def validate_email(self, value): """Ensure email is unique for the user (only for completion).""" if not value: # Email is optional during initiation return value user = self.context['request'].user if self.instance: # Update case if GmailCredential.objects.filter(user=user, email=value).exclude(id=self.instance.id).exists(): raise serializers.ValidationError("This Gmail account is already added.") else: # Create case if GmailCredential.objects.filter(user=user, email=value).exists(): raise serializers.ValidationError("This Gmail account is already added.") return value