2015-09-06 14:12:34 +02:00
|
|
|
import mimetypes
|
2015-01-24 16:35:50 +01:00
|
|
|
|
2016-01-10 10:52:44 +01:00
|
|
|
from django.conf import settings
|
2015-09-06 14:12:34 +02:00
|
|
|
from django.db import models as dbmodels
|
2016-01-27 09:09:49 +01:00
|
|
|
from PyPDF2 import PdfFileReader
|
2016-11-18 09:40:36 +01:00
|
|
|
from PyPDF2.utils import PdfReadError
|
2015-09-06 14:12:34 +02:00
|
|
|
|
2019-06-28 07:24:28 +02:00
|
|
|
from ..utils.auth import get_group_model
|
|
|
|
from ..utils.rest_api import (
|
|
|
|
FileField,
|
|
|
|
IdPrimaryKeyRelatedField,
|
|
|
|
ModelSerializer,
|
|
|
|
SerializerMethodField,
|
|
|
|
ValidationError,
|
|
|
|
)
|
2019-03-06 14:53:24 +01:00
|
|
|
from .models import Mediafile
|
2015-01-24 16:35:50 +01:00
|
|
|
|
|
|
|
|
2015-09-06 14:12:34 +02:00
|
|
|
class AngularCompatibleFileField(FileField):
|
|
|
|
def to_internal_value(self, data):
|
2019-01-06 16:22:33 +01:00
|
|
|
if data == "":
|
2015-09-06 14:12:34 +02:00
|
|
|
return None
|
|
|
|
return super(AngularCompatibleFileField, self).to_internal_value(data)
|
|
|
|
|
|
|
|
def to_representation(self, value):
|
2019-06-28 07:24:28 +02:00
|
|
|
if value is None or value.name is None:
|
2015-09-06 14:12:34 +02:00
|
|
|
return None
|
2019-06-28 07:24:28 +02:00
|
|
|
filetype = mimetypes.guess_type(value.name)[0]
|
2019-01-06 16:22:33 +01:00
|
|
|
result = {"name": value.name, "type": filetype}
|
|
|
|
if filetype == "application/pdf":
|
2016-02-23 22:34:50 +01:00
|
|
|
try:
|
2019-06-28 07:24:28 +02:00
|
|
|
if (
|
|
|
|
settings.DEFAULT_FILE_STORAGE
|
|
|
|
== "storages.backends.sftpstorage.SFTPStorage"
|
|
|
|
):
|
|
|
|
remote_path = value.storage._remote_path(value.name)
|
|
|
|
file_handle = value.storage.sftp.open(remote_path, mode="rb")
|
|
|
|
else:
|
|
|
|
file_handle = open(value.path, "rb")
|
|
|
|
|
|
|
|
result["pages"] = PdfFileReader(file_handle).getNumPages()
|
2016-02-23 22:34:50 +01:00
|
|
|
except FileNotFoundError:
|
|
|
|
# File was deleted from server. Set 'pages' to 0.
|
2019-01-06 16:22:33 +01:00
|
|
|
result["pages"] = 0
|
2016-11-18 09:40:36 +01:00
|
|
|
except PdfReadError:
|
|
|
|
# File could be encrypted but not be detected by PyPDF.
|
2019-01-06 16:22:33 +01:00
|
|
|
result["pages"] = 0
|
|
|
|
result["encrypted"] = True
|
2016-01-27 09:09:49 +01:00
|
|
|
return result
|
2015-09-06 14:12:34 +02:00
|
|
|
|
|
|
|
|
2015-02-12 18:48:14 +01:00
|
|
|
class MediafileSerializer(ModelSerializer):
|
2015-01-24 16:35:50 +01:00
|
|
|
"""
|
|
|
|
Serializer for mediafile.models.Mediafile objects.
|
|
|
|
"""
|
2019-01-06 16:22:33 +01:00
|
|
|
|
2016-01-10 10:52:44 +01:00
|
|
|
media_url_prefix = SerializerMethodField()
|
2015-02-12 18:48:14 +01:00
|
|
|
filesize = SerializerMethodField()
|
2019-06-28 07:24:28 +02:00
|
|
|
access_groups = IdPrimaryKeyRelatedField(
|
|
|
|
many=True, required=False, queryset=get_group_model().objects.all()
|
|
|
|
)
|
2015-01-24 16:35:50 +01:00
|
|
|
|
2015-09-06 14:12:34 +02:00
|
|
|
def __init__(self, *args, **kwargs):
|
|
|
|
"""
|
|
|
|
This constructor overwrites the FileField field serializer to return the file meta data in a way that the
|
|
|
|
angualarjs upload module likes
|
|
|
|
"""
|
|
|
|
super(MediafileSerializer, self).__init__(*args, **kwargs)
|
|
|
|
self.serializer_field_mapping[dbmodels.FileField] = AngularCompatibleFileField
|
2019-06-28 07:24:28 +02:00
|
|
|
|
|
|
|
# Make some fields read-oinly for updates (not creation)
|
2016-01-24 22:58:45 +01:00
|
|
|
if self.instance is not None:
|
2019-01-06 16:22:33 +01:00
|
|
|
self.fields["mediafile"].read_only = True
|
2015-09-06 14:12:34 +02:00
|
|
|
|
2015-01-24 16:35:50 +01:00
|
|
|
class Meta:
|
|
|
|
model = Mediafile
|
2015-02-04 00:08:38 +01:00
|
|
|
fields = (
|
2019-01-06 16:22:33 +01:00
|
|
|
"id",
|
|
|
|
"title",
|
|
|
|
"mediafile",
|
|
|
|
"media_url_prefix",
|
|
|
|
"filesize",
|
2019-06-28 07:24:28 +02:00
|
|
|
"access_groups",
|
|
|
|
"create_timestamp",
|
|
|
|
"is_directory",
|
|
|
|
"path",
|
|
|
|
"parent",
|
2019-04-23 16:57:35 +02:00
|
|
|
"list_of_speakers_id",
|
2019-06-28 07:24:28 +02:00
|
|
|
"inherited_access_groups_id",
|
2019-01-06 16:22:33 +01:00
|
|
|
)
|
2015-01-24 16:35:50 +01:00
|
|
|
|
2019-06-28 07:24:28 +02:00
|
|
|
read_only_fields = ("path",)
|
|
|
|
|
|
|
|
def validate(self, data):
|
|
|
|
title = data.get("title")
|
|
|
|
if title is not None and not title:
|
|
|
|
raise ValidationError({"detail": "The title must not be empty"})
|
|
|
|
|
|
|
|
parent = data.get("parent")
|
|
|
|
if parent and not parent.is_directory:
|
|
|
|
raise ValidationError({"detail": "parent must be a directory."})
|
|
|
|
|
|
|
|
if data.get("is_directory") and "/" in data.get("title", ""):
|
|
|
|
raise ValidationError(
|
|
|
|
{"detail": 'The name contains invalid characters: "/"'}
|
|
|
|
)
|
|
|
|
|
|
|
|
return super().validate(data)
|
|
|
|
|
|
|
|
def create(self, validated_data):
|
|
|
|
access_groups = validated_data.pop("access_groups", [])
|
|
|
|
mediafile = super().create(validated_data)
|
|
|
|
mediafile.access_groups.set(access_groups)
|
|
|
|
mediafile.save()
|
|
|
|
return mediafile
|
|
|
|
|
|
|
|
def update(self, instance, validated_data):
|
|
|
|
# remove is_directory, create_timestamp and parent from validated_data
|
|
|
|
# to prevent updating them (mediafile is ensured in the constructor)
|
|
|
|
validated_data.pop("is_directory", None)
|
|
|
|
validated_data.pop("create_timestamp", None)
|
|
|
|
validated_data.pop("parent", None)
|
|
|
|
return super().update(instance, validated_data)
|
|
|
|
|
2015-01-24 16:35:50 +01:00
|
|
|
def get_filesize(self, mediafile):
|
|
|
|
return mediafile.get_filesize()
|
2016-01-10 10:52:44 +01:00
|
|
|
|
|
|
|
def get_media_url_prefix(self, mediafile):
|
|
|
|
return settings.MEDIA_URL
|