rfiles-online/files/serializers.py

278 lines
7.5 KiB
Python

"""
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