236 lines
6.3 KiB
Python
236 lines
6.3 KiB
Python
"""
|
|
Serializers for file upload and sharing.
|
|
"""
|
|
|
|
from rest_framework import serializers
|
|
from django.utils import timezone
|
|
|
|
from .models import MediaFile, PublicShare, FileAccessLog
|
|
|
|
|
|
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 FileAccessLogSerializer(serializers.ModelSerializer):
|
|
class Meta:
|
|
model = FileAccessLog
|
|
fields = [
|
|
'id',
|
|
'media_file',
|
|
'share',
|
|
'accessed_at',
|
|
'ip_address',
|
|
'access_type',
|
|
]
|
|
read_only_fields = fields
|