""" Serializers for file upload and sharing. """ from rest_framework import serializers from django.utils import timezone from .models import MediaFile, PublicShare, FileAccessLog, MemoryCard class MediaFileSerializer(serializers.ModelSerializer): file_url = serializers.SerializerMethodField() share_count = serializers.SerializerMethodField() has_active_shares = serializers.SerializerMethodField() class Meta: model = MediaFile fields = [ 'id', 'file', 'file_url', 'original_filename', 'title', 'description', 'mime_type', 'file_size', 'file_hash', 'tags', 'extracted_text', 'is_processed', 'processing_error', 'shared_space', 'created_at', 'updated_at', 'share_count', 'has_active_shares', ] read_only_fields = [ 'id', 'file_url', 'file_size', 'file_hash', 'is_processed', 'processing_error', 'created_at', 'updated_at', 'share_count', 'has_active_shares', ] def get_file_url(self, obj): request = self.context.get('request') if obj.file and request: return request.build_absolute_uri(obj.file.url) return None def get_share_count(self, obj): return obj.get_public_shares().count() def get_has_active_shares(self, obj): return obj.get_public_shares().exists() class MediaFileUploadSerializer(serializers.ModelSerializer): original_filename = serializers.CharField(required=False, allow_blank=True) mime_type = serializers.CharField(required=False, allow_blank=True) class Meta: model = MediaFile fields = [ 'file', 'original_filename', 'title', 'description', 'mime_type', 'tags', 'shared_space', ] def create(self, validated_data): file_obj = validated_data.get('file') if file_obj and not validated_data.get('original_filename'): validated_data['original_filename'] = file_obj.name if file_obj and not validated_data.get('mime_type'): validated_data['mime_type'] = getattr(file_obj, 'content_type', 'application/octet-stream') request = self.context.get('request') if request and request.user.is_authenticated: validated_data['uploaded_by'] = request.user return super().create(validated_data) class PublicShareSerializer(serializers.ModelSerializer): public_url = serializers.SerializerMethodField() is_valid = serializers.SerializerMethodField() file_info = serializers.SerializerMethodField() class Meta: model = PublicShare fields = [ 'id', 'token', 'media_file', 'public_url', 'expires_at', 'max_downloads', 'download_count', 'is_password_protected', 'note', 'is_active', 'is_valid', 'created_at', 'file_info', ] read_only_fields = [ 'id', 'token', 'public_url', 'download_count', 'is_valid', 'created_at', 'file_info', ] extra_kwargs = { 'media_file': {'required': True} } def get_public_url(self, obj): return obj.get_public_url() def get_is_valid(self, obj): return obj.is_valid def get_file_info(self, obj): return { 'id': str(obj.media_file.id), 'title': obj.media_file.title, 'original_filename': obj.media_file.original_filename, 'mime_type': obj.media_file.mime_type, 'file_size': obj.media_file.file_size, } class PublicShareCreateSerializer(serializers.ModelSerializer): password = serializers.CharField( write_only=True, required=False, allow_blank=True, ) expires_in_hours = serializers.IntegerField( write_only=True, required=False, min_value=1, max_value=8760, ) class Meta: model = PublicShare fields = [ 'media_file', 'expires_at', 'expires_in_hours', 'max_downloads', 'password', 'note', ] def validate(self, data): if 'expires_in_hours' in data: hours = data.pop('expires_in_hours') data['expires_at'] = timezone.now() + timezone.timedelta(hours=hours) return data def create(self, validated_data): password = validated_data.pop('password', None) request = self.context.get('request') if request and request.user.is_authenticated: validated_data['created_by'] = request.user share = super().create(validated_data) if password: share.set_password(password) return share class PublicShareInfoSerializer(serializers.ModelSerializer): file_info = serializers.SerializerMethodField() is_valid = serializers.SerializerMethodField() downloads_remaining = serializers.SerializerMethodField() class Meta: model = PublicShare fields = [ 'is_password_protected', 'is_valid', 'expires_at', 'downloads_remaining', 'file_info', 'note', ] def get_is_valid(self, obj): return obj.is_valid def get_downloads_remaining(self, obj): if obj.max_downloads is None: return None return max(0, obj.max_downloads - obj.download_count) def get_file_info(self, obj): return { 'title': obj.media_file.title, 'original_filename': obj.media_file.original_filename, 'file_size': obj.media_file.file_size, 'mime_type': obj.media_file.mime_type, } class MemoryCardSerializer(serializers.ModelSerializer): attachment_count = serializers.SerializerMethodField() class Meta: model = MemoryCard fields = [ 'id', 'shared_space', 'title', 'body', 'card_type', 'tags', 'media_files', 'position', 'docmost_page_id', 'created_by', 'created_at', 'updated_at', 'attachment_count', ] read_only_fields = [ 'id', 'created_by', 'created_at', 'updated_at', 'attachment_count', ] def get_attachment_count(self, obj): return obj.media_files.count() def create(self, validated_data): media_files = validated_data.pop('media_files', []) request = self.context.get('request') if request and request.user.is_authenticated: validated_data['created_by'] = request.user card = super().create(validated_data) if media_files: card.media_files.set(media_files) return card class FileAccessLogSerializer(serializers.ModelSerializer): class Meta: model = FileAccessLog fields = [ 'id', 'media_file', 'share', 'accessed_at', 'ip_address', 'access_type', ] read_only_fields = fields