fix translations for profile images (TNL-3901)
This commit is contained in:
@@ -6,7 +6,7 @@ from collections import namedtuple
|
||||
|
||||
from django.conf import settings
|
||||
from django.core.files.base import ContentFile
|
||||
from django.utils.translation import ugettext as _, ugettext_noop as _noop
|
||||
from django.utils.translation import ugettext as _
|
||||
from PIL import Image
|
||||
|
||||
from openedx.core.djangoapps.user_api.accounts.image_helpers import get_profile_image_storage
|
||||
@@ -58,13 +58,6 @@ def get_valid_file_types():
|
||||
return ', '.join([', '.join(IMAGE_TYPES[ft].extensions) for ft in IMAGE_TYPES.keys()])
|
||||
|
||||
|
||||
FILE_UPLOAD_TOO_LARGE = _noop(u'The file must be smaller than {image_max_size} in size.'.format(image_max_size=user_friendly_size(settings.PROFILE_IMAGE_MAX_BYTES))) # pylint: disable=line-too-long
|
||||
FILE_UPLOAD_TOO_SMALL = _noop(u'The file must be at least {image_min_size} in size.'.format(image_min_size=user_friendly_size(settings.PROFILE_IMAGE_MIN_BYTES))) # pylint: disable=line-too-long
|
||||
FILE_UPLOAD_BAD_TYPE = _noop(u'The file must be one of the following types: {valid_file_types}.'.format(valid_file_types=get_valid_file_types())) # pylint: disable=line-too-long
|
||||
FILE_UPLOAD_BAD_EXT = _noop(u'The file name extension for this file does not match the file data. The file may be corrupted.') # pylint: disable=line-too-long
|
||||
FILE_UPLOAD_BAD_MIMETYPE = _noop(u'The Content-Type header for this file does not match the file data. The file may be corrupted.') # pylint: disable=line-too-long
|
||||
|
||||
|
||||
class ImageValidationError(Exception):
|
||||
"""
|
||||
Exception to use when the system rejects a user-supplied source image.
|
||||
@@ -90,25 +83,46 @@ def validate_uploaded_image(uploaded_file):
|
||||
# see also: http://en.wikipedia.org/wiki/Magic_number_%28programming%29
|
||||
|
||||
if uploaded_file.size > settings.PROFILE_IMAGE_MAX_BYTES:
|
||||
raise ImageValidationError(FILE_UPLOAD_TOO_LARGE)
|
||||
file_upload_too_large = _(
|
||||
u'The file must be smaller than {image_max_size} in size.'
|
||||
).format(
|
||||
image_max_size=user_friendly_size(settings.PROFILE_IMAGE_MAX_BYTES)
|
||||
)
|
||||
raise ImageValidationError(file_upload_too_large)
|
||||
elif uploaded_file.size < settings.PROFILE_IMAGE_MIN_BYTES:
|
||||
raise ImageValidationError(FILE_UPLOAD_TOO_SMALL)
|
||||
file_upload_too_small = _(
|
||||
u'The file must be at least {image_min_size} in size.'
|
||||
).format(
|
||||
image_min_size=user_friendly_size(settings.PROFILE_IMAGE_MIN_BYTES)
|
||||
)
|
||||
raise ImageValidationError(file_upload_too_small)
|
||||
|
||||
# check the file extension looks acceptable
|
||||
filename = unicode(uploaded_file.name).lower()
|
||||
filetype = [ft for ft in IMAGE_TYPES if any(filename.endswith(ext) for ext in IMAGE_TYPES[ft].extensions)]
|
||||
if not filetype:
|
||||
raise ImageValidationError(FILE_UPLOAD_BAD_TYPE)
|
||||
file_upload_bad_type = _(
|
||||
u'The file must be one of the following types: {valid_file_types}.'
|
||||
).format(valid_file_types=get_valid_file_types())
|
||||
raise ImageValidationError(file_upload_bad_type)
|
||||
filetype = filetype[0]
|
||||
|
||||
# check mimetype matches expected file type
|
||||
if uploaded_file.content_type not in IMAGE_TYPES[filetype].mimetypes:
|
||||
raise ImageValidationError(FILE_UPLOAD_BAD_MIMETYPE)
|
||||
file_upload_bad_mimetype = _(
|
||||
u'The Content-Type header for this file does not match '
|
||||
u'the file data. The file may be corrupted.'
|
||||
)
|
||||
raise ImageValidationError(file_upload_bad_mimetype)
|
||||
|
||||
# check magic number matches expected file type
|
||||
headers = IMAGE_TYPES[filetype].magic
|
||||
if uploaded_file.read(len(headers[0]) / 2).encode('hex') not in headers:
|
||||
raise ImageValidationError(FILE_UPLOAD_BAD_EXT)
|
||||
file_upload_bad_ext = _(
|
||||
u'The file name extension for this file does not match '
|
||||
u'the file data. The file may be corrupted.'
|
||||
)
|
||||
raise ImageValidationError(file_upload_bad_ext)
|
||||
# avoid unexpected errors from subsequent modules expecting the fp to be at 0
|
||||
uploaded_file.seek(0)
|
||||
|
||||
|
||||
@@ -16,15 +16,11 @@ import mock
|
||||
from PIL import Image
|
||||
|
||||
from ..images import (
|
||||
FILE_UPLOAD_TOO_LARGE,
|
||||
FILE_UPLOAD_TOO_SMALL,
|
||||
FILE_UPLOAD_BAD_TYPE,
|
||||
FILE_UPLOAD_BAD_EXT,
|
||||
FILE_UPLOAD_BAD_MIMETYPE,
|
||||
create_profile_images,
|
||||
ImageValidationError,
|
||||
remove_profile_images,
|
||||
validate_uploaded_image,
|
||||
get_valid_file_types,
|
||||
)
|
||||
from .helpers import make_image_file, make_uploaded_file
|
||||
|
||||
@@ -35,6 +31,12 @@ class TestValidateUploadedImage(TestCase):
|
||||
"""
|
||||
Test validate_uploaded_image
|
||||
"""
|
||||
FILE_UPLOAD_BAD_TYPE = (
|
||||
u'The file must be one of the following types: {valid_file_types}.'.format(
|
||||
valid_file_types=get_valid_file_types()
|
||||
)
|
||||
)
|
||||
|
||||
def check_validation_result(self, uploaded_file, expected_failure_message):
|
||||
"""
|
||||
Internal DRY helper.
|
||||
@@ -48,10 +50,10 @@ class TestValidateUploadedImage(TestCase):
|
||||
self.assertEqual(uploaded_file.tell(), 0)
|
||||
|
||||
@ddt.data(
|
||||
(99, FILE_UPLOAD_TOO_SMALL),
|
||||
(99, u"The file must be at least 100 bytes in size."),
|
||||
(100, ),
|
||||
(1024, ),
|
||||
(1025, FILE_UPLOAD_TOO_LARGE),
|
||||
(1025, u"The file must be smaller than 1 KB in size."),
|
||||
)
|
||||
@ddt.unpack
|
||||
@override_settings(PROFILE_IMAGE_MIN_BYTES=100, PROFILE_IMAGE_MAX_BYTES=1024)
|
||||
@@ -85,6 +87,10 @@ class TestValidateUploadedImage(TestCase):
|
||||
Ensure that validation fails when the file extension does not match the
|
||||
file data.
|
||||
"""
|
||||
file_upload_bad_ext = (
|
||||
u'The file name extension for this file does not match '
|
||||
u'the file data. The file may be corrupted.'
|
||||
)
|
||||
# make a bmp, try to fool the function into thinking it's a jpeg
|
||||
with make_image_file(extension=".bmp") as bmp_file:
|
||||
with closing(NamedTemporaryFile(suffix=".jpeg")) as fake_jpeg_file:
|
||||
@@ -97,17 +103,21 @@ class TestValidateUploadedImage(TestCase):
|
||||
)
|
||||
with self.assertRaises(ImageValidationError) as ctx:
|
||||
validate_uploaded_image(uploaded_file)
|
||||
self.assertEqual(ctx.exception.message, FILE_UPLOAD_BAD_EXT)
|
||||
self.assertEqual(ctx.exception.message, file_upload_bad_ext)
|
||||
|
||||
def test_content_type(self):
|
||||
"""
|
||||
Ensure that validation fails when the content_type header and file
|
||||
extension do not match
|
||||
"""
|
||||
file_upload_bad_mimetype = (
|
||||
u'The Content-Type header for this file does not match '
|
||||
u'the file data. The file may be corrupted.'
|
||||
)
|
||||
with make_uploaded_file(extension=".jpeg", content_type="image/gif") as uploaded_file:
|
||||
with self.assertRaises(ImageValidationError) as ctx:
|
||||
validate_uploaded_image(uploaded_file)
|
||||
self.assertEqual(ctx.exception.message, FILE_UPLOAD_BAD_MIMETYPE)
|
||||
self.assertEqual(ctx.exception.message, file_upload_bad_mimetype)
|
||||
|
||||
|
||||
@ddt.ddt
|
||||
|
||||
Reference in New Issue
Block a user