Skip to content

Commit

Permalink
Merge pull request #73 from edx/ammar/add-video-image-urls-field
Browse files Browse the repository at this point in the history
add support in model for multiple video image urls
  • Loading branch information
muhammad-ammar authored May 19, 2017
2 parents 9a878df + 244197e commit 3e1133f
Show file tree
Hide file tree
Showing 5 changed files with 115 additions and 3 deletions.
1 change: 0 additions & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,5 @@ script:
branches:
only:
- master
- ammar/course-rerun-import-export
after_success:
coveralls
1 change: 1 addition & 0 deletions edxval/migrations/0005_videoimage.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ class Migration(migrations.Migration):
('created', model_utils.fields.AutoCreatedField(default=django.utils.timezone.now, verbose_name='created', editable=False)),
('modified', model_utils.fields.AutoLastModifiedField(default=django.utils.timezone.now, verbose_name='modified', editable=False)),
('image', edxval.models.CustomizableImageField(null=True, blank=True)),
('generated_images', edxval.models.ListField()),
('course_video', models.OneToOneField(related_name='video_image', to='edxval.CourseVideo')),
],
options={
Expand Down
61 changes: 61 additions & 0 deletions edxval/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,14 @@
"""

from contextlib import closing
import json
import logging
import os
from uuid import uuid4

from django.db import models
from django.dispatch import receiver
from django.core.exceptions import ValidationError
from django.core.validators import MinValueValidator, RegexValidator
from django.core.urlresolvers import reverse

Expand All @@ -28,6 +30,7 @@
logger = logging.getLogger(__name__) # pylint: disable=C0103

URL_REGEX = r'^[a-zA-Z0-9\-_]*$'
LIST_MAX_ITEMS = 3


class ModelFactoryWithValidation(object):
Expand Down Expand Up @@ -199,12 +202,70 @@ def deconstruct(self):
return name, path, args, kwargs


class ListField(models.TextField):
"""
ListField use to store and retrieve list data.
"""
__metaclass__ = models.SubfieldBase

def get_prep_value(self, value):
"""
Converts a list to its json represetation to store in database as text.
"""
return json.dumps(value)

def to_python(self, value):
"""
Converts the value into a list.
"""
if not value:
value = []

# If a list is set then validated its items
if isinstance(value, list):
return self.validate(value)
else: # try to de-serialize value and expect list and then validate
try:
py_list = json.loads(value)

if not isinstance(py_list, list):
raise TypeError

self.validate(py_list)
except (ValueError, TypeError):
raise ValidationError(u'Must be a valid list of strings.')

return py_list

def validate(self, value):
"""
Validate data before saving to database.
Arguemtns:
value(list): list to be validated
Returns:
list if validation is successful
Raises:
ValidationError
"""
if len(value) > LIST_MAX_ITEMS:
raise ValidationError(u'list must not contain more than {} items.'.format(LIST_MAX_ITEMS))

if all(isinstance(item, str) for item in value) is False:
raise ValidationError(u'list must only contain strings.')

return value


class VideoImage(TimeStampedModel):
"""
Image model for course video.
"""
course_video = models.OneToOneField(CourseVideo, related_name="video_image")
image = CustomizableImageField()
generated_images = ListField()

@classmethod
def create_or_update(cls, course_video, file_name, image_data=None):
Expand Down
53 changes: 52 additions & 1 deletion edxval/tests/test_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,15 @@
from mock import patch
from lxml import etree

from django.core.exceptions import ValidationError
from django.core.files.images import ImageFile
from django.test import TestCase
from django.db import DatabaseError
from django.core.urlresolvers import reverse
from rest_framework import status
from ddt import ddt, data, unpack

from edxval.models import Profile, Video, EncodedVideo, CourseVideo, VideoImage
from edxval.models import Profile, Video, EncodedVideo, CourseVideo, VideoImage, LIST_MAX_ITEMS
from edxval import api as api
from edxval.api import (
SortDirection,
Expand Down Expand Up @@ -1335,3 +1336,53 @@ def test_update_video_image_exception(self):
does_not_course_id
)
)

def test_video_image_urls_field(self):
"""
Test `VideoImage.generated_images` field works as expected.
"""
image_urls = ['video-images/a.png', 'video-images/b.png']

# an empty list should be returned when there is no value for urls
self.assertEqual(self.course_video.video_image.generated_images, [])

# set a list with data and expect the same list to be returned
course_video = CourseVideo.objects.create(video=self.video, course_id='course101')
video_image = VideoImage.objects.create(course_video=course_video)
video_image.generated_images = image_urls
video_image.save()
self.assertEqual(video_image.generated_images, image_urls)
self.assertEqual(course_video.video_image.generated_images, image_urls)

def test_video_image_urls_field_validation(self):
"""
Test `VideoImage.generated_images` field validation.
"""
course_video = CourseVideo.objects.create(video=self.video, course_id='course101')
video_image = VideoImage.objects.create(course_video=course_video)

# expect a validation error if we try to set a list with more than 3 items
with self.assertRaises(ValidationError) as set_exception:
video_image.generated_images = ['a', 'b', 'c', 'd']

self.assertEqual(
set_exception.exception.message,
u'list must not contain more than {} items.'.format(LIST_MAX_ITEMS)
)

# expect a validation error if we try to a list with non-string items
with self.assertRaises(ValidationError) as set_exception:
video_image.generated_images = ['a', 1, 2]

self.assertEqual(set_exception.exception.message, u'list must only contain strings.')

# expect a validation error if we try to set non list data
exception_messages = set()
for item in ('a string', 555, {'a': 1}, (1,), video_image):
with self.assertRaises(ValidationError) as set_exception:
video_image.generated_images = item

exception_messages.add(set_exception.exception.message)

self.assertEqual(len(exception_messages), 1)
self.assertEqual(exception_messages.pop(), u'Must be a valid list of strings.')
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ def load_requirements(*requirements_paths):

setup(
name='edxval',
version='0.0.15',
version='0.0.14',
author='edX',
url='http://github.com/edx/edx-val',
description='edx-val',
Expand Down

0 comments on commit 3e1133f

Please sign in to comment.