Commit 5def1caf by Simon Chen

Improve image validator to allow mulitple image resolutions to be uploaded into Publisher

EDUCATOR-1954
parent f64e79e9
# -*- coding: utf-8 -*-
# Generated by Django 1.11.3 on 2017-12-12 20:16
from __future__ import unicode_literals
import django.db.models.deletion
import stdimage.models
from django.db import migrations, models
import course_discovery.apps.course_metadata.utils
class Migration(migrations.Migration):
dependencies = [
('course_metadata', '0073_program_instructors'),
]
operations = [
migrations.AlterField(
model_name='course',
name='image',
field=stdimage.models.StdImageField(blank=True, help_text='Please provide a course preview image', null=True, upload_to=course_discovery.apps.course_metadata.utils.UploadToFieldNamePath('uuid', path='media/course/image')),
),
migrations.AlterField(
model_name='courseentitlement',
name='partner',
field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to='core.Partner'),
),
migrations.AlterField(
model_name='person',
name='profile_image',
field=stdimage.models.StdImageField(blank=True, null=True, upload_to=course_discovery.apps.course_metadata.utils.UploadToFieldNamePath('uuid', path='media/people/profile_images')),
),
]
# -*- coding: utf-8 -*-
# Generated by Django 1.11.3 on 2017-12-12 20:16
from __future__ import unicode_literals
import stdimage.models
from django.db import migrations, models
import course_discovery.apps.course_metadata.utils
import course_discovery.apps.publisher.validators
class Migration(migrations.Migration):
dependencies = [
('publisher', '0061_add_people_permission'),
]
operations = [
migrations.AlterField(
model_name='course',
name='image',
field=stdimage.models.StdImageField(blank=True, null=True, upload_to=course_discovery.apps.course_metadata.utils.UploadToFieldNamePath('number', path='media/publisher/courses/images'), validators=[course_discovery.apps.publisher.validators.ImageMultiSizeValidator([(2120, 1192), (1134, 675), (378, 225)])]),
),
migrations.AlterField(
model_name='historicalcourse',
name='image',
field=models.TextField(blank=True, max_length=100, null=True, validators=[course_discovery.apps.publisher.validators.ImageMultiSizeValidator([(2120, 1192), (1134, 675), (378, 225)])]),
),
]
......@@ -27,7 +27,7 @@ from course_discovery.apps.publisher import emails
from course_discovery.apps.publisher.choices import (CourseRunStateChoices, CourseStateChoices, InternalUserRole,
PublisherUserRole)
from course_discovery.apps.publisher.utils import is_email_notification_enabled
from course_discovery.apps.publisher.validators import ImageSizeValidator
from course_discovery.apps.publisher.validators import ImageMultiSizeValidator
logger = logging.getLogger(__name__)
......@@ -77,10 +77,7 @@ class Course(TimeStampedModel, ChangedByMixin):
),
blank=True,
null=True,
variations={
'thumbnail': (100, 100, True),
},
validators=[ImageSizeValidator(width=2120, height=1192)]
validators=[ImageMultiSizeValidator([(2120, 1192), (1134, 675), (378, 225)])]
)
is_seo_review = models.BooleanField(default=False)
......
......@@ -340,7 +340,7 @@
<br/>
<strong>{% trans "Course Image Guidelines:" %}</strong>
<ul>
<li>{% trans "The image size must be 2120 x 1192 pixels." %}</li>
<li>{% trans "The image size must be of size 1134 X 675 pixels." %}</li>
<li>{% trans "Each course in a sequence must have a unique image." %}</li>
<li>{% trans "The image cannot include text or headlines." %}</li>
<li>{% trans "You must have permission to use the image. Possible image sources include Flickr creative commons, Stock Vault, Stock XCHNG, and iStock Photo." %}</li>
......
......@@ -111,22 +111,25 @@ class CreateCourseViewTests(SiteMixin, TestCase):
response = self.client.post(reverse('publisher:publisher_courses_new'), course_dict)
self.assertEqual(response.status_code, 400)
def test_create_course(self):
@ddt.data(
make_image_file('test_cover00.jpg', width=2120, height=1192),
make_image_file('test_cover01.jpg', width=1134, height=675),
make_image_file('test_cover02.jpg', width=378, height=225),
)
def test_create_course_valid_image(self, image):
"""
Verify that user can create course successfully.
Verify a new course with valid image of acceptable image sizes can be saved properly
"""
data = {'title': 'Test2', 'number': 'testX453', 'image': make_image_file('test_banner.jpg')}
data = {'title': 'Test valid', 'number': 'testX453', 'image': image}
course_dict = self._post_data(data, self.course)
response = self.client.post(reverse('publisher:publisher_courses_new'), course_dict)
course = Course.objects.get(number=course_dict['number'])
self.assertRedirects(
response,
expected_url=reverse('publisher:publisher_course_detail', kwargs={'pk': course.id}),
status_code=302,
target_status_code=200
)
self.assertEqual(course.number, data['number'])
self._assert_image(course)
......@@ -136,13 +139,17 @@ class CreateCourseViewTests(SiteMixin, TestCase):
make_image_file('test_banner02.jpg', width=2119, height=1192),
make_image_file('test_banner03.jpg', width=2121, height=1192),
make_image_file('test_banner04.jpg', width=2121, height=1191),
make_image_file('test_cover01.jpg', width=1600, height=1100),
make_image_file('test_cover01.jpg', width=300, height=220),
)
def test_create_course_invalid_image(self, image):
"""
Verify that a new course with an invalid image shows the proper error.
"""
image_error = [
'The image you uploaded is of incorrect resolution. Course image files must be 2120 x 1192 pixels in size.'
'The image you uploaded is of incorrect resolution. ' +
'Course image files must be in one of the following sizes in pixels: ' +
'(2120 X 1192), (1134 X 675), (378 X 225)',
]
self.user.groups.add(Group.objects.get(name=ADMIN_GROUP_NAME))
self._assert_records(1)
......
from bs4 import BeautifulSoup
from django import forms
from django.core.exceptions import ValidationError
from django.utils.translation import ugettext_lazy as _
from stdimage.validators import BaseSizeValidator
......@@ -7,6 +8,7 @@ from stdimage.validators import BaseSizeValidator
class ImageSizeValidator(BaseSizeValidator):
"""
ImageField validator to validate the width and height of an image.
NOTE: This is not used in the current models. But it was used in model migrations
"""
def compare(self, img_size, limit_size): # pylint: disable=arguments-differ
......@@ -18,6 +20,37 @@ class ImageSizeValidator(BaseSizeValidator):
)
class ImageMultiSizeValidator(ImageSizeValidator):
"""
ImageField Size validator that takes in a list of sizes to validate
Will pass validation if the image is of one of the specified size
"""
def __init__(self, limit_sizes): # pylint: disable=super-init-not-called
self.limit_value = limit_sizes
def __call__(self, value):
cleaned = self.clean(value)
validated = False
for limit_size in self.limit_value:
if not self.compare(cleaned, limit_size):
validated = True
if not validated:
size_message_array = []
for limit_size in self.limit_value:
size_message_array.append(
'({} X {})'.format(limit_size[0], limit_size[1])
)
params = {
'sizes': ', '.join(size_message_array)
}
raise ValidationError(self.message, code=self.code, params=params)
message = _(
'The image you uploaded is of incorrect resolution. '
'Course image files must be in one of the following sizes in pixels: %(sizes)s'
)
def validate_text_count(max_length):
"""
Custom validator to count the text area characters without html tags.
......
......@@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2017-12-11 20:22+0000\n"
"POT-Creation-Date: 2017-12-12 16:02+0000\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
......@@ -1777,7 +1777,7 @@ msgid "Course Image Guidelines:"
msgstr ""
#: apps/publisher/templates/publisher/course_edit_form.html
msgid "The image size must be 2120 x 1192 pixels."
msgid "The image size must be of size 1134 X 675 pixels."
msgstr ""
#: apps/publisher/templates/publisher/course_edit_form.html
......@@ -3207,6 +3207,13 @@ msgid ""
msgstr ""
#: apps/publisher/validators.py
#, python-format
msgid ""
"The image you uploaded is of incorrect resolution. Course image files must "
"be in one of the following sizes in pixels: %(sizes)s"
msgstr ""
#: apps/publisher/validators.py
#, python-brace-format
msgid ""
"Ensure this value has at most {allowed_char} characters (it has "
......
......@@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2017-12-11 20:22+0000\n"
"POT-Creation-Date: 2017-12-12 16:02+0000\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
......
......@@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2017-12-11 20:22+0000\n"
"POT-Creation-Date: 2017-12-12 16:02+0000\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
......@@ -2094,10 +2094,10 @@ msgid "Course Image Guidelines:"
msgstr "Çöürsé Ìmägé Güïdélïnés: Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢ση#"
#: apps/publisher/templates/publisher/course_edit_form.html
msgid "The image size must be 2120 x 1192 pixels."
msgid "The image size must be of size 1134 X 675 pixels."
msgstr ""
"Thé ïmägé sïzé müst ßé 2120 x 1192 pïxéls. Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, "
"¢σηѕє¢тєтυя #"
"Thé ïmägé sïzé müst ßé öf sïzé 1134 X 675 pïxéls. Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт "
"αмєт, ¢σηѕє¢тєтυя α#"
#: apps/publisher/templates/publisher/course_edit_form.html
msgid "Each course in a sequence must have a unique image."
......@@ -3887,6 +3887,15 @@ msgstr ""
"ßé %(with)s x %(height)s pïxéls ïn sïzé. Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αм#"
#: apps/publisher/validators.py
#, python-format
msgid ""
"The image you uploaded is of incorrect resolution. Course image files must "
"be in one of the following sizes in pixels: %(sizes)s"
msgstr ""
"Thé ïmägé ýöü üplöädéd ïs öf ïnçörréçt résölütïön. Çöürsé ïmägé fïlés müst "
"ßé ïn öné öf thé föllöwïng sïzés ïn pïxéls: %(sizes)s Ⱡ'σяєм ιρѕ#"
#: apps/publisher/validators.py
#, python-brace-format
msgid ""
"Ensure this value has at most {allowed_char} characters (it has "
......
......@@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2017-12-11 20:22+0000\n"
"POT-Creation-Date: 2017-12-12 16:02+0000\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
......
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