Commit 08667dda by Bill DeRusha Committed by Bill DeRusha

Add course form validations

Add char limits to prereqs and descriptions
Add pixel limits to image uploads

ECOM-6636
parent 310ddd7a
......@@ -7,16 +7,16 @@ from PIL import Image
from django.core.files.uploadedfile import SimpleUploadedFile
def make_image_stream():
def make_image_stream(width, height):
"""
Helper to generate values for program banner_image
"""
image = Image.new('RGB', (1440, 900), 'green')
image = Image.new('RGB', (width, height), 'green')
bio = BytesIO()
image.save(bio, format='JPEG')
return bio
def make_image_file(name):
image_stream = make_image_stream()
def make_image_file(name, width=2120, height=1192):
image_stream = make_image_stream(width, height)
return SimpleUploadedFile(name, image_stream.getvalue(), content_type='image/jpeg')
......@@ -89,7 +89,7 @@ def mock_api_callback(url, data, results_key=True, pagination=False):
def mock_jpeg_callback():
def request_callback(request): # pylint: disable=unused-argument
image_stream = make_image_stream()
image_stream = make_image_stream(2120, 1192)
return 200, {}, image_stream.getvalue()
......
......@@ -59,6 +59,15 @@ class CustomCourseForm(CourseForm):
)
title = forms.CharField(label=_('Course Title'), required=True)
number = forms.CharField(label=_('Course Number'), required=True)
short_description = forms.CharField(
label=_('Brief Description'), max_length=140, widget=forms.Textarea, required=False
)
full_description = forms.CharField(
label=_('Full Description'), max_length=2500, widget=forms.Textarea, required=False
)
prerequisites = forms.CharField(
label=_('Prerequisites'), max_length=200, widget=forms.Textarea, required=False
)
# users will be loaded through AJAX call based on organization
team_admin = UserModelChoiceField(
......
# -*- coding: utf-8 -*-
# Generated by Django 1.9.11 on 2017-01-04 18:30
from __future__ import unicode_literals
import course_discovery.apps.course_metadata.utils
from django.db import migrations, models
import stdimage.models
import stdimage.validators
class Migration(migrations.Migration):
dependencies = [
('publisher', '0024_auto_20170105_1626'),
]
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=[stdimage.validators.MaxSizeValidator(2120, 1192), stdimage.validators.MinSizeValidator(2120, 1192)]),
),
migrations.AlterField(
model_name='historicalcourse',
name='image',
field=models.TextField(blank=True, max_length=100, null=True, validators=[stdimage.validators.MaxSizeValidator(2120, 1192), stdimage.validators.MinSizeValidator(2120, 1192)]),
),
]
......@@ -11,6 +11,7 @@ from django_fsm import FSMField, transition
from simple_history.models import HistoricalRecords
from sortedm2m.fields import SortedManyToManyField
from stdimage.models import StdImageField
from stdimage.validators import MaxSizeValidator, MinSizeValidator
from taggit.managers import TaggableManager
import waffle
......@@ -126,10 +127,9 @@ class Course(TimeStampedModel, ChangedByMixin):
blank=True,
null=True,
variations={
'large': (2120, 1192),
'medium': (1440, 480),
'thumbnail': (100, 100, True),
}
},
validators=[MaxSizeValidator(2120, 1192), MinSizeValidator(2120, 1192), ]
)
is_seo_review = models.BooleanField(default=False)
......
......@@ -35,6 +35,10 @@ from course_discovery.apps.publisher.wrappers import CourseRunWrapper
from course_discovery.apps.publisher_comments.tests.factories import CommentFactory
IMAGE_TOO_SMALL = 'The image you uploaded is too small. The required minimum resolution is: 2120x1192 px.'
IMAGE_TOO_LARGE = 'The image you uploaded is too large. The required maximum resolution is: 2120x1192 px.'
@ddt.ddt
class CreateUpdateCourseViewTests(TestCase):
""" Tests for the publisher `CreateCourseView` and `UpdateCourseView`. """
......@@ -109,6 +113,24 @@ class CreateUpdateCourseViewTests(TestCase):
self._assert_test_data(response, course, self.seat.type, self.seat.price)
@ddt.data(
(make_image_file('test_banner00.jpg', width=2120, height=1191), [IMAGE_TOO_SMALL]),
(make_image_file('test_banner01.jpg', width=2120, height=1193), [IMAGE_TOO_LARGE]),
(make_image_file('test_banner02.jpg', width=2119, height=1192), [IMAGE_TOO_SMALL]),
(make_image_file('test_banner03.jpg', width=2121, height=1192), [IMAGE_TOO_LARGE]),
(make_image_file('test_banner04.jpg', width=2121, height=1191), [IMAGE_TOO_LARGE, IMAGE_TOO_SMALL]),
)
@ddt.unpack
def test_create_course_invalid_image(self, image, errors):
""" Verify that a new course with an invalid image shows the proper error.
"""
self.user.groups.add(Group.objects.get(name=ADMIN_GROUP_NAME))
self._assert_records(1)
course_dict = self._post_data({'image': image}, self.course, self.course_run, self.seat)
response = self.client.post(reverse('publisher:publisher_courses_new'), course_dict, files=image)
self.assertEqual(response.context['course_form'].errors['image'], errors)
self._assert_records(1)
def test_create_with_fail_transaction(self):
""" Verify that in case of any error transactions roll back and no object
created in db.
......
......@@ -226,6 +226,9 @@ class CreateCourseView(mixins.LoginRequiredMixin, CreateView):
if not messages.get_messages(request):
messages.error(request, _('Please fill all required fields.'))
if course_form.errors.get('image'):
messages.error(request, course_form.errors.get('image'))
ctx.update(
{
'course_form': course_form,
......
......@@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2017-01-05 12:31+0500\n"
"POT-Creation-Date: 2017-01-06 09:45-0500\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"
......@@ -448,6 +448,20 @@ msgstr ""
msgid "Course Number"
msgstr ""
#: apps/publisher/forms.py apps/publisher/models.py
#: templates/publisher/add_course_form.html
msgid "Brief Description"
msgstr ""
#: apps/publisher/forms.py apps/publisher/models.py
msgid "Full Description"
msgstr ""
#: apps/publisher/forms.py apps/publisher/models.py
#: templates/publisher/course_run_detail/_all.html
msgid "Prerequisites"
msgstr ""
#: apps/publisher/forms.py
msgid "Organization Course Admin"
msgstr ""
......@@ -525,14 +539,6 @@ msgstr ""
msgid "Course number"
msgstr ""
#: apps/publisher/models.py templates/publisher/add_course_form.html
msgid "Brief Description"
msgstr ""
#: apps/publisher/models.py
msgid "Full Description"
msgstr ""
#: apps/publisher/models.py templates/publisher/course_run_detail/_all.html
msgid "Partner Name"
msgstr ""
......@@ -545,10 +551,6 @@ msgstr ""
msgid "Expected Learnings"
msgstr ""
#: apps/publisher/models.py templates/publisher/course_run_detail/_all.html
msgid "Prerequisites"
msgstr ""
#: apps/publisher/models.py
msgid "Verification deadline"
msgstr ""
......@@ -1251,6 +1253,7 @@ msgid "Dashboard"
msgstr ""
#: templates/publisher/base.html templates/publisher/courses.html
#: templates/publisher/view_course_form.html
msgid "Courses"
msgstr ""
......@@ -1432,6 +1435,7 @@ msgid "Additional Notes"
msgstr ""
#: templates/publisher/course_run_detail/_approval_widget.html
#: templates/publisher/view_course_form.html
msgid "EDIT"
msgstr ""
......
......@@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2017-01-05 12:31+0500\n"
"POT-Creation-Date: 2017-01-06 09:45-0500\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-01-05 12:31+0500\n"
"POT-Creation-Date: 2017-01-06 09:45-0500\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"
......@@ -556,6 +556,20 @@ msgstr "Çöürsé Tïtlé Ⱡ'σяєм ιρѕυм ∂σłσя ѕ#"
msgid "Course Number"
msgstr "Çöürsé Nümßér Ⱡ'σяєм ιρѕυм ∂σłσя ѕι#"
#: apps/publisher/forms.py apps/publisher/models.py
#: templates/publisher/add_course_form.html
msgid "Brief Description"
msgstr "Brïéf Désçrïptïön Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмє#"
#: apps/publisher/forms.py apps/publisher/models.py
msgid "Full Description"
msgstr "Füll Désçrïptïön Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αм#"
#: apps/publisher/forms.py apps/publisher/models.py
#: templates/publisher/course_run_detail/_all.html
msgid "Prerequisites"
msgstr "Préréqüïsïtés Ⱡ'σяєм ιρѕυм ∂σłσя ѕι#"
#: apps/publisher/forms.py
msgid "Organization Course Admin"
msgstr "Örgänïzätïön Çöürsé Àdmïn Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢σηѕ#"
......@@ -635,14 +649,6 @@ msgstr "Çöürsé tïtlé Ⱡ'σяєм ιρѕυм ∂σłσя ѕ#"
msgid "Course number"
msgstr "Çöürsé nümßér Ⱡ'σяєм ιρѕυм ∂σłσя ѕι#"
#: apps/publisher/models.py templates/publisher/add_course_form.html
msgid "Brief Description"
msgstr "Brïéf Désçrïptïön Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмє#"
#: apps/publisher/models.py
msgid "Full Description"
msgstr "Füll Désçrïptïön Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αм#"
#: apps/publisher/models.py templates/publisher/course_run_detail/_all.html
msgid "Partner Name"
msgstr "Pärtnér Nämé Ⱡ'σяєм ιρѕυм ∂σłσя ѕ#"
......@@ -655,10 +661,6 @@ msgstr "Lévél Týpé Ⱡ'σяєм ιρѕυм ∂σłσ#"
msgid "Expected Learnings"
msgstr "Éxpéçtéd Léärnïngs Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт#"
#: apps/publisher/models.py templates/publisher/course_run_detail/_all.html
msgid "Prerequisites"
msgstr "Préréqüïsïtés Ⱡ'σяєм ιρѕυм ∂σłσя ѕι#"
#: apps/publisher/models.py
msgid "Verification deadline"
msgstr "Vérïfïçätïön déädlïné Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, #"
......@@ -1522,6 +1524,7 @@ msgid "Dashboard"
msgstr "Däshßöärd Ⱡ'σяєм ιρѕυм ∂σł#"
#: templates/publisher/base.html templates/publisher/courses.html
#: templates/publisher/view_course_form.html
msgid "Courses"
msgstr "Çöürsés Ⱡ'σяєм ιρѕυм #"
......@@ -1710,6 +1713,7 @@ msgid "Additional Notes"
msgstr "Àddïtïönäl Nötés Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αм#"
#: templates/publisher/course_run_detail/_approval_widget.html
#: templates/publisher/view_course_form.html
msgid "EDIT"
msgstr "ÉDÌT Ⱡ'σяєм ι#"
......
......@@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2017-01-05 12:31+0500\n"
"POT-Creation-Date: 2017-01-06 09:45-0500\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