You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
110 lines
3.9 KiB
110 lines
3.9 KiB
# -*- coding: utf-8 -*- |
|
from __future__ import unicode_literals |
|
# Erik Stein <code@classlibrary.net>, 2016 |
|
|
|
import os |
|
from django import forms |
|
from django.contrib.admin.widgets import AdminFileWidget |
|
from django.db import models |
|
from django.db.models.fields.files import FileDescriptor |
|
from django.utils.html import conditional_escape |
|
from django.utils.text import slugify |
|
|
|
from ..storages import ProtectedMediaAssetStorage |
|
|
|
|
|
# TODO Define the central storage somewhere more central |
|
ORIGINALS_STORAGE = ProtectedMediaAssetStorage() |
|
# TODO Move filename max length to storage |
|
FILENAME_MAX_LENGTH = 255 |
|
|
|
|
|
# TOD Move get_upload_path to utils |
|
def get_upload_path(instance, filename): |
|
""" |
|
Returns /<uuid_hex>/original/<slugified_filename.ext> |
|
where |
|
- uuid is taken from instance, |
|
- filename is slugified and shortened to a max length including the extension. |
|
""" |
|
name, ext = os.path.splitext(filename) |
|
name = slugify(name) |
|
name = name[:(FILENAME_MAX_LENGTH - len(ext))] |
|
filename = "%s%s" % (name, ext) |
|
return os.path.join( |
|
instance.get_uuid(), |
|
instance.STORAGE.ORIGINAL_FILE_PREFIX, |
|
filename |
|
) |
|
|
|
|
|
DEFAULT_UPLOAD_TO = get_upload_path |
|
|
|
|
|
class MediaAssetFileWidget(AdminFileWidget): |
|
""" |
|
Widget which understands ProtectedMediaAssetStorage |
|
(knows that the url property is not relevant), also |
|
does not provide a link to the original file. |
|
# TODO Add admin access to the original file, if permissions apply |
|
# TODO Add permission "allowed to view original file" |
|
""" |
|
|
|
template_with_initial = ( |
|
'%(initial_text)s: %(initial)s ' |
|
'%(clear_template)s<br />%(input_text)s: %(input)s' |
|
) |
|
|
|
def is_initial(self, value): |
|
# Checks for 'name' instead of 'url' property |
|
return bool(value and hasattr(value, 'name')) |
|
|
|
def get_template_substitution_values(self, value): |
|
# Does not use value.url |
|
return { |
|
'initial': conditional_escape(value), |
|
} |
|
|
|
|
|
class MediaAssetFileDescriptor(FileDescriptor): |
|
# TODO Assign metadata fields like width/height |
|
|
|
def __set__(self, instance, value): |
|
previous_file = instance.__dict__.get(self.field.name) |
|
super(MediaAssetFileDescriptor, self).__set__(instance, value) |
|
|
|
# TODO Check if previous_file is actually None in our case; remove comment |
|
# To prevent recalculating image dimensions when we are instantiating |
|
# an object from the database (bug #11084), only update dimensions if |
|
# the field had a value before this assignment. Since the default |
|
# value for FileField subclasses is an instance of field.attr_class, |
|
# previous_file will only be None when we are called from |
|
# Model.__init__(). The ImageField.update_dimension_fields method |
|
# hooked up to the post_init signal handles the Model.__init__() cases. |
|
# Assignment happening outside of Model.__init__() will trigger the |
|
# update right here. |
|
if previous_file is not None: |
|
pass # self.field.update_dimension_fields(instance, force=True) |
|
|
|
|
|
class MediaAssetFormField(forms.FileField): |
|
widget = MediaAssetFileWidget |
|
|
|
|
|
class MediaAssetField(models.FileField): |
|
# The descriptor to use for accessing the attribute off of the class. |
|
description_class = MediaAssetFileDescriptor |
|
|
|
def _init__(self, verbose_name=None, name=None, upload_to='', storage=None, *args, **kwargs): |
|
kwargs['max_length'] = kwargs.get('max_length', FILENAME_MAX_LENGTH) |
|
kwargs['upload_to'] = kwargs.get('upload_to', DEFAULT_UPLOAD_TO) |
|
kwargs['storage'] = kwargs.get('storage', ORIGINALS_STORAGE) |
|
super(MediaAssetField, self).__init__(verbose_name, name, **kwargs) |
|
|
|
def formfield(self, **kwargs): |
|
defaults = { |
|
'form_class': MediaAssetFormField, |
|
'max_length': self.max_length |
|
} |
|
defaults.update(kwargs) |
|
return super(MediaAssetField, self).formfield(**defaults)
|
|
|