Commit 70552845 by Adam Palay

fix translations for profile images (TNL-3901)

parent e9c8b4b0
......@@ -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
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment