kopia lustrzana https://dev.funkwhale.audio/funkwhale/funkwhale
168 wiersze
5.5 KiB
Python
168 wiersze
5.5 KiB
Python
import mimetypes
|
|
from os.path import splitext
|
|
|
|
from django.core import validators
|
|
from django.core.exceptions import ValidationError
|
|
from django.core.files.images import get_image_dimensions
|
|
from django.template.defaultfilters import filesizeformat
|
|
from django.utils.deconstruct import deconstructible
|
|
from django.utils.translation import ugettext_lazy as _
|
|
|
|
|
|
@deconstructible
|
|
class ImageDimensionsValidator:
|
|
"""
|
|
ImageField dimensions validator.
|
|
|
|
from https://gist.github.com/emilio-rst/4f81ea2718736a6aaf9bdb64d5f2ea6c
|
|
"""
|
|
|
|
def __init__(
|
|
self,
|
|
width=None,
|
|
height=None,
|
|
min_width=None,
|
|
max_width=None,
|
|
min_height=None,
|
|
max_height=None,
|
|
):
|
|
"""
|
|
Constructor
|
|
|
|
Args:
|
|
width (int): exact width
|
|
height (int): exact height
|
|
min_width (int): minimum width
|
|
min_height (int): minimum height
|
|
max_width (int): maximum width
|
|
max_height (int): maximum height
|
|
"""
|
|
|
|
self.width = width
|
|
self.height = height
|
|
self.min_width = min_width
|
|
self.max_width = max_width
|
|
self.min_height = min_height
|
|
self.max_height = max_height
|
|
|
|
def __call__(self, image):
|
|
w, h = get_image_dimensions(image)
|
|
|
|
if self.width is not None and w != self.width:
|
|
raise ValidationError(_("Width must be %dpx.") % (self.width,))
|
|
|
|
if self.height is not None and h != self.height:
|
|
raise ValidationError(_("Height must be %dpx.") % (self.height,))
|
|
|
|
if self.min_width is not None and w < self.min_width:
|
|
raise ValidationError(_("Minimum width must be %dpx.") % (self.min_width,))
|
|
|
|
if self.min_height is not None and h < self.min_height:
|
|
raise ValidationError(
|
|
_("Minimum height must be %dpx.") % (self.min_height,)
|
|
)
|
|
|
|
if self.max_width is not None and w > self.max_width:
|
|
raise ValidationError(_("Maximum width must be %dpx.") % (self.max_width,))
|
|
|
|
if self.max_height is not None and h > self.max_height:
|
|
raise ValidationError(
|
|
_("Maximum height must be %dpx.") % (self.max_height,)
|
|
)
|
|
|
|
|
|
@deconstructible
|
|
class FileValidator(object):
|
|
"""
|
|
Taken from https://gist.github.com/jrosebr1/2140738
|
|
Validator for files, checking the size, extension and mimetype.
|
|
Initialization parameters:
|
|
allowed_extensions: iterable with allowed file extensions
|
|
ie. ('txt', 'doc')
|
|
allowd_mimetypes: iterable with allowed mimetypes
|
|
ie. ('image/png', )
|
|
min_size: minimum number of bytes allowed
|
|
ie. 100
|
|
max_size: maximum number of bytes allowed
|
|
ie. 24*1024*1024 for 24 MB
|
|
Usage example::
|
|
MyModel(models.Model):
|
|
myfile = FileField(validators=FileValidator(max_size=24*1024*1024), ...)
|
|
"""
|
|
|
|
extension_message = _(
|
|
"Extension '%(extension)s' not allowed. Allowed extensions are: '%(allowed_extensions)s.'"
|
|
)
|
|
mime_message = _(
|
|
"MIME type '%(mimetype)s' is not valid. Allowed types are: %(allowed_mimetypes)s."
|
|
)
|
|
min_size_message = _(
|
|
"The current file %(size)s, which is too small. The minumum file size is %(allowed_size)s."
|
|
)
|
|
max_size_message = _(
|
|
"The current file %(size)s, which is too large. The maximum file size is %(allowed_size)s."
|
|
)
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
self.allowed_extensions = kwargs.pop("allowed_extensions", None)
|
|
self.allowed_mimetypes = kwargs.pop("allowed_mimetypes", None)
|
|
self.min_size = kwargs.pop("min_size", 0)
|
|
self.max_size = kwargs.pop("max_size", None)
|
|
|
|
def __call__(self, value):
|
|
"""
|
|
Check the extension, content type and file size.
|
|
"""
|
|
|
|
# Check the extension
|
|
ext = splitext(value.name)[1][1:].lower()
|
|
if self.allowed_extensions and ext not in self.allowed_extensions:
|
|
message = self.extension_message % {
|
|
"extension": ext,
|
|
"allowed_extensions": ", ".join(self.allowed_extensions),
|
|
}
|
|
|
|
raise ValidationError(message)
|
|
|
|
# Check the content type
|
|
mimetype = mimetypes.guess_type(value.name)[0]
|
|
if self.allowed_mimetypes and mimetype not in self.allowed_mimetypes:
|
|
message = self.mime_message % {
|
|
"mimetype": mimetype,
|
|
"allowed_mimetypes": ", ".join(self.allowed_mimetypes),
|
|
}
|
|
|
|
raise ValidationError(message)
|
|
|
|
# Check the file size
|
|
filesize = len(value)
|
|
if self.max_size and filesize > self.max_size:
|
|
message = self.max_size_message % {
|
|
"size": filesizeformat(filesize),
|
|
"allowed_size": filesizeformat(self.max_size),
|
|
}
|
|
|
|
raise ValidationError(message)
|
|
|
|
elif filesize < self.min_size:
|
|
message = self.min_size_message % {
|
|
"size": filesizeformat(filesize),
|
|
"allowed_size": filesizeformat(self.min_size),
|
|
}
|
|
|
|
raise ValidationError(message)
|
|
|
|
|
|
class DomainValidator(validators.URLValidator):
|
|
message = "Enter a valid domain name."
|
|
|
|
def __call__(self, value):
|
|
"""
|
|
This is a bit hackish but since we don't have any built-in domain validator,
|
|
we use the url one, and prepend http:// in front of it.
|
|
|
|
If it fails, we know the domain is not valid.
|
|
"""
|
|
super().__call__("http://{}".format(value))
|
|
return value
|