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.
111 lines
3.9 KiB
111 lines
3.9 KiB
9 years ago
|
# -*- 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)
|