Commit 112da93f by christopher lee

POST EncodedVideo set

EncodedVideo part of the upload. Complete EncodedVideo dicts may
now be uploaded. Rejects all EncodedVideos of a Video when there is
an invalid EncodedVideo. Does not reject other Video when a differet
Video is invalid. Currently, EncodedVideo cannot be updated, they can
only be created.

Other notes:
-Added django-debug-toolbar==1.2.1
-constants.py has been reorganized
parent 7a910438
...@@ -108,4 +108,4 @@ def get_video_info(edx_video_id, location=None): ...@@ -108,4 +108,4 @@ def get_video_info(edx_video_id, location=None):
error_message = u"Could not get edx_video_id: {0}".format(edx_video_id) error_message = u"Could not get edx_video_id: {0}".format(edx_video_id)
logger.exception(error_message) logger.exception(error_message)
raise ValInternalError(error_message) raise ValInternalError(error_message)
return result.data return result.data
\ No newline at end of file
...@@ -10,7 +10,10 @@ class Profile(models.Model): ...@@ -10,7 +10,10 @@ class Profile(models.Model):
""" """
Details for pre-defined encoding format Details for pre-defined encoding format
""" """
profile_name = models.CharField(max_length=50, unique=True) profile_name = models.CharField(
max_length=50,
unique=True,
)
extension = models.CharField(max_length=10) extension = models.CharField(max_length=10)
width = models.PositiveIntegerField() width = models.PositiveIntegerField()
height = models.PositiveIntegerField() height = models.PositiveIntegerField()
......
...@@ -2,29 +2,60 @@ ...@@ -2,29 +2,60 @@
Serializers for Video Abstraction Layer Serializers for Video Abstraction Layer
""" """
from rest_framework import serializers from rest_framework import serializers
from rest_framework.serializers import ValidationError
from edxval.models import Profile, Video, EncodedVideo from edxval.models import Profile, Video, EncodedVideo
class VideoSerializer(serializers.ModelSerializer): class DisplayProfileName(serializers.WritableField):
"""
Takes a Profile Object and returns only it's profile_name
"""
def from_native(self, data):
try:
if isinstance(data, int):
profile = Profile.objects.get(pk=data)
elif isinstance(data, unicode):
profile = Profile.objects.get(profile_name=str(data))
return profile
except Profile.DoesNotExist:
error_message = "Profile does not exist: {0}".format(data)
raise ValidationError(error_message)
def restore_object(self, attrs, instance=None): def to_native(self, data):
""" return data.profile_name
Given a dictionary of deserialized field values, either update
an existing model instance, or create a new model instance.
""" class DisplayVideoName(serializers.WritableField):
if instance is not None: """
instance.edx_video_id = attrs.get( Takes a Video Object and returns only it's profile_name
'edx_video_id', instance.edx_video_id """
) def from_native(self, data):
instance.duration = attrs.get( #TODO change doc/function name or modify this function, currently
'duration', instance.duration #TODO takes a video pk and converts it to video Object.
) try:
instance.client_video_id = attrs.get( if isinstance(data, int):
'client_video_id', instance.client_video_id video = Video.objects.get(pk=data)
) return video
return instance except Video.DoesNotExist:
return Video(**attrs) error_message = "Video does not exist: {0}".format(data)
raise ValidationError(error_message)
def to_native(self, data):
return data.edx_video_id
class ListField(serializers.WritableField):
"""
Allows the use of a list as a serializer field.
"""
def from_native(self, data):
if isinstance(data, list):
return data
else:
error_message = "Expecting a list: {0}".format(type(data))
raise ValidationError(error_message)
class Meta: class Meta:
model = Video model = Video
...@@ -45,17 +76,59 @@ class ProfileSerializer(serializers.ModelSerializer): ...@@ -45,17 +76,59 @@ class ProfileSerializer(serializers.ModelSerializer):
) )
class OnlyEncodedVideoSerializer(serializers.ModelSerializer): class VideoSerializer(serializers.ModelSerializer):
def restore_object(self, attrs, instance=None):
"""
Given a dictionary of deserialized field values, either update
an existing model instance, or create a new model instance.
"""
if instance is not None:
instance.edx_video_id = attrs.get('edx_video_id', instance.edx_video_id)
instance.duration = attrs.get('duration', instance.duration)
instance.client_video_id = attrs.get('client_video_id', instance.client_video_id)
return instance
return Video(**attrs)
class Meta:
model = Video
fields = (
"client_video_id",
"duration",
"edx_video_id"
)
class EncodedVideoSerializer(serializers.ModelSerializer):
""" """
Used to serialize the EncodedVideo for the EncodedVideoSetSerializer Used to serialize the EncodedVideo for the EncodedVideoSetSerializer
""" """
profile = ProfileSerializer(required=False) profile = DisplayProfileName()
video = DisplayVideoName()
def restore_object(self, attrs, instance=None):
"""
Given a dictionary of deserialized field values, either update
an existing model instance, or create a new model instance.
"""
if instance is not None:
#TODO Currently not updating Encodedvideo Object.
instance.url = attrs.get('url', instance.url)
instance.file_size = attrs.get('file_size', instance.file_size)
instance.bitrate = attrs.get('bitrate', instance.bitrate)
#TODO profile instance.profile = attrs.get('profile', instance.profile)
return instance
return EncodedVideo(**attrs)
class Meta: class Meta:
model = EncodedVideo model = EncodedVideo
fields = ( fields = (
"url", "url",
"file_size", "file_size",
"bitrate" "bitrate",
"profile",
"video"
) )
...@@ -64,12 +137,114 @@ class EncodedVideoSetSerializer(serializers.ModelSerializer): ...@@ -64,12 +137,114 @@ class EncodedVideoSetSerializer(serializers.ModelSerializer):
Used to serialize a list of EncodedVideo objects it's foreign key Video Object. Used to serialize a list of EncodedVideo objects it's foreign key Video Object.
""" """
edx_video_id = serializers.CharField(max_length=50) edx_video_id = serializers.CharField(max_length=50)
encoded_videos = OnlyEncodedVideoSerializer() encoded_videos = EncodedVideoSerializer(required=False)
class Meta: class Meta:
model = Video model = Video
fields = ( fields = (
"duration", "duration",
"client_video_id" "client_video_id",
"edx_video_id",
"encoded_videos"
) )
class EncodedVideoSetDeserializer(serializers.Serializer):
"""
Deserializes a dict of Video fields and list of EncodedVideos.
Example:
>>>data = dict(
... client_video_id="Shallow Swordfish",
... duration=122.00,
... edx_video_id="supersoaker",
... encoded_videos=[
... dict(
... url="https://www.swordsingers.com",
... file_size=9000,
... bitrate=42,
... profile=1,
... ),
... dict(
... url="https://www.swordsingers.com",
... file_size=9000,
... bitrate=42,
... profile=2,
... )
... ]
... )
>>>serilizer = EncodedVideoSetDeserializer(data=data)
>>>if serilizer.is_valid()
>>> serializer.save()
>>>video = Video.objects.get(edx_video_id="supersoaker")
>>>print EncodedVideoSetDeserializer(video).data
{
'duration': 122.0,
'client_video_id': u'ShallowSwordfish',
'edx_video_id': u'supersoaker',
'encoded_videos': [
{
'url': u'https: //www.swordsingers.com',
'file_size': 9000,
'bitrate': 42,
'profile': u'mobile',
'video': u'supersoaker'
},
{
'url': u'https: //www.swordsingers.com',
'file_size': 9000,
'bitrate': 42,
'profile': u'desktop',
'video': u'supersoaker'
}
]
}
"""
client_video_id = serializers.CharField(max_length=50)
duration = serializers.FloatField()
edx_video_id = serializers.CharField(max_length=50)
encoded_videos = ListField(required=False)
def restore_object(self, attrs, instance=None):
"""
Updates or creates video object and creates valid EncodedVideo objects.
If the Video parameters are not valid, the errors are returns and the
Video object is not created and the desrialization ends. If any of the
EncodedVideo Parameters are invalid, the errors are returns and the
EncodedVideos objects are not created.
"""
#Get or create the Video object, else return errors
try:
instance = Video.objects.get(edx_video_id=attrs.get("edx_video_id"))
except Video.DoesNotExist:
instance = None
video = VideoSerializer(
data=dict(
edx_video_id=attrs.get("edx_video_id"),
duration=attrs.get("duration"),
client_video_id=attrs.get("client_video_id")
),
instance=instance
)
if video.is_valid():
video.save()
else:
for key in video.errors:
self.errors[key] = video.errors[key]
return
#Point encoded_videos to parent video
if not "encoded_videos" in attrs:
return video
for item in attrs.get("encoded_videos"):
item[u"video"] = Video.objects.get(edx_video_id=attrs.get("edx_video_id")).pk
#Serialize EncodedVideos, else raise errors
ev = EncodedVideoSerializer(data=attrs.get("encoded_videos"), many=True)
if ev.is_valid():
ev.save()
else:
self.errors["encoded_videos"] = ev.errors
return video
\ No newline at end of file
...@@ -124,6 +124,7 @@ INSTALLED_APPS = ( ...@@ -124,6 +124,7 @@ INSTALLED_APPS = (
'rest_framework', 'rest_framework',
# Uncomment the next line to enable the admin: # Uncomment the next line to enable the admin:
'django.contrib.admin', 'django.contrib.admin',
'debug_toolbar'
# Uncomment the next line to enable admin documentation: # Uncomment the next line to enable admin documentation:
# 'django.contrib.admindocs', # 'django.contrib.admindocs',
) )
...@@ -165,4 +166,4 @@ LOGGING = { ...@@ -165,4 +166,4 @@ LOGGING = {
'propagate': True, 'propagate': True,
}, },
} }
} }
\ No newline at end of file
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
EDX_VIDEO_ID = "thisis12char-thisis7" EDX_VIDEO_ID = "itchyjacket"
"""
Generic Profiles for manually creating profile objects
"""
PROFILE_DICT_MOBILE = dict(
profile_name="mobile",
extension="avi",
width=100,
height=101
)
PROFILE_DICT_DESKTOP = dict(
profile_name="desktop",
extension="mp4",
width=200,
height=2001
)
"""
Encoded_videos for test_api, does not have profile.
"""
ENCODED_VIDEO_DICT_MOBILE = dict( ENCODED_VIDEO_DICT_MOBILE = dict(
url="http://www.meowmix.com", url="http://www.meowmix.com",
file_size=25556, file_size=4545,
bitrate=9600, bitrate=6767,
) )
ENCODED_VIDEO_DICT_DESKTOP = dict( ENCODED_VIDEO_DICT_DESKTOP = dict(
url="http://www.meowmagic.com", url="http://www.meowmagic.com",
file_size=25556, file_size=1212,
bitrate=9600, bitrate=2323,
)
"""
Validators
"""
VIDEO_DICT_NEGATIVE_DURATION = dict(
client_video_id="Thunder Cats S01E01",
duration=-111,
edx_video_id="thisis12char-thisis7",
) )
ENCODED_VIDEO_DICT_NEGATIVE_FILESIZE = dict( ENCODED_VIDEO_DICT_NEGATIVE_FILESIZE = dict(
url="http://www.meowmix.com", url="http://www.meowmix.com",
file_size=-25556, file_size=-25556,
...@@ -23,19 +47,18 @@ ENCODED_VIDEO_DICT_NEGATIVE_BITRATE = dict( ...@@ -23,19 +47,18 @@ ENCODED_VIDEO_DICT_NEGATIVE_BITRATE = dict(
file_size=25556, file_size=25556,
bitrate=-9600, bitrate=-9600,
) )
"""
PROFILE_DICT_MOBILE = dict( Non-latin
profile_name="mobile", """
extension="avi", VIDEO_DICT_NON_LATIN_TITLE = dict(
width=100, client_video_id="배고픈 햄스터",
height=101 duration=42,
edx_video_id="ID"
) )
VIDEO_DICT_NON_LATIN_ID = dict(
PROFILE_DICT_DESKTOP = dict( client_video_id="Hungry Hamster",
profile_name="desktop", duration=42,
extension="mp4", edx_video_id="밥줘"
width=200,
height=2001
) )
PROFILE_DICT_NON_LATIN = dict( PROFILE_DICT_NON_LATIN = dict(
profile_name=u"배고파", profile_name=u"배고파",
...@@ -43,71 +66,148 @@ PROFILE_DICT_NON_LATIN = dict( ...@@ -43,71 +66,148 @@ PROFILE_DICT_NON_LATIN = dict(
width=100, width=100,
height=300 height=300
) )
VIDEO_DICT_CATS = dict( """
client_video_id="Thunder Cats S01E01", Fish
duration=111.00, """
edx_video_id="thisis12char-thisis7", VIDEO_DICT_FISH = dict(
client_video_id="Shallow Swordfish",
duration=122.00,
edx_video_id="supersoaker"
) )
VIDEO_DICT_LION = dict( ENCODED_VIDEO_DICT_FISH_MOBILE = dict(
client_video_id="Lolcat", url="https://www.swordsingers.com",
duration=111.00, file_size=9000,
edx_video_id="caw", bitrate=42,
profile="mobile",
) )
VIDEO_DICT_LION2 = dict(
client_video_id="Lolcat", ENCODED_VIDEO_DICT_FISH_DESKTOP = dict(
url="https://www.swordsplints.com",
file_size=1234,
bitrate=4222,
profile="desktop",
)
ENCODED_VIDEO_DICT_FISH_INVALID_PROFILE = dict(
url="https://www.swordsplints.com",
file_size=1234,
bitrate=4222,
profile=11,
)
COMPLETE_SET_FISH = dict(
encoded_videos=[
ENCODED_VIDEO_DICT_FISH_MOBILE,
ENCODED_VIDEO_DICT_FISH_DESKTOP
],
**VIDEO_DICT_FISH
)
COMPLETE_SET_INVALID_ENCODED_VIDEO_FISH = dict(
encoded_videos=[
ENCODED_VIDEO_DICT_FISH_MOBILE,
ENCODED_VIDEO_DICT_FISH_INVALID_PROFILE
],
**VIDEO_DICT_FISH
)
COMPLETE_SET_INVALID_VIDEO_FISH = dict(
client_video_id="Shallow Swordfish",
duration=122.00, duration=122.00,
edx_video_id="caw", edx_video_id="super/soaker",
encoded_videos=[
ENCODED_VIDEO_DICT_FISH_MOBILE,
ENCODED_VIDEO_DICT_FISH_DESKTOP
]
) )
VIDEO_DICT_TIGERS_BEARS = [ COMPLETE_SETS_ALL_INVALID = [
dict( COMPLETE_SET_INVALID_VIDEO_FISH,
client_video_id="Tipsy Tiger", COMPLETE_SET_INVALID_VIDEO_FISH
duration=111.00,
edx_video_id="meeeeeow",
),
dict(
client_video_id="Boring Bear",
duration=111.00,
edx_video_id="hithar",
)
] ]
VIDEO_DICT_INVALID_SET = [
dict(
client_video_id="Average Animal",
duration=111.00,
edx_video_id="mediocrity",
),
dict(
client_video_id="Barking Bee",
duration=111.00,
edx_video_id="wa/sps",
),
dict(
client_video_id="Callous Coat",
duration=111.00,
edx_video_id="not an animal",
)
]
VIDEO_DICT_DUPLICATES = [ """
dict( Star
client_video_id="Gaggling gopher", """
duration=111.00, VIDEO_DICT_STAR = dict(
edx_video_id="gg", client_video_id="TWINKLE TWINKLE",
), duration=122.00,
dict( edx_video_id="little-star"
client_video_id="Gaggling gopher", )
duration=111.00, ENCODED_VIDEO_DICT_STAR = dict(
edx_video_id="gg", url="https://www.howIwonder.com",
file_size=9000,
bitrate=42,
profile=1
)
ENCODED_VIDEO_DICT_STAR2 = dict(
url="https://www.whatyouare.com",
file_size=1111,
bitrate=2333,
profile=2
)
COMPLETE_SET_STAR = dict(
encoded_videos=[
ENCODED_VIDEO_DICT_STAR,
ENCODED_VIDEO_DICT_STAR2
],
**VIDEO_DICT_STAR
)
COMPLETE_SET_NOT_A_LIST = dict(
encoded_videos=dict(
url="https://www.howIwonder.com",
file_size=9000,
bitrate=42,
profile=1
), ),
] **VIDEO_DICT_STAR
)
VIDEO_DICT_NEGATIVE_DURATION = dict( COMPLETE_SET_EXTRA_VIDEO_FIELD = dict(
client_video_id="Thunder Cats S01E01", encoded_videos=[
duration=-111, dict(
edx_video_id="thisis12char-thisis7", url="https://www.vulturevideos.com",
file_size=101010,
bitrate=1234,
profile=1,
video="This should be overridden by parent videofield"
)
],
**VIDEO_DICT_STAR
)
"""
Unsorted
"""
VIDEO_DICT_COAT = dict(
client_video_id="Callous Coat",
duration=111.00,
edx_video_id="itchyjacket",
)
VIDEO_DICT_AVERAGE = dict(
client_video_id="Average Animal",
duration=111.00,
edx_video_id="mediocrity",
)
VIDEO_DICT_AVERAGE2 = dict(
client_video_id="Lolcat",
duration=122.00,
edx_video_id="mediocrity",
)
VIDEO_DICT_CRAYFISH = dict(
client_video_id="Crazy Crayfish",
duration=111.00,
edx_video_id="craycray",
)
VIDEO_DICT_BEE_INVALID = dict(
client_video_id="Barking Bee",
duration=111.00,
edx_video_id="wa/sps",
) )
VIDEO_DICT_INVALID_ID = dict( VIDEO_DICT_INVALID_ID = dict(
...@@ -116,14 +216,30 @@ VIDEO_DICT_INVALID_ID = dict( ...@@ -116,14 +216,30 @@ VIDEO_DICT_INVALID_ID = dict(
edx_video_id="sloppy/sloth!!" edx_video_id="sloppy/sloth!!"
) )
VIDEO_DICT_NON_LATIN_TITLE = dict( VIDEO_DICT_DUPLICATES = [
client_video_id="배고픈 햄스터", VIDEO_DICT_CRAYFISH,
duration=42, VIDEO_DICT_CRAYFISH,
edx_video_id="ID" VIDEO_DICT_CRAYFISH
) ]
VIDEO_DICT_NON_LATIN_ID = dict( COMPLETE_SETS = [
client_video_id="Hungry Hamster", COMPLETE_SET_STAR,
duration=42, COMPLETE_SET_FISH
edx_video_id="밥줘" ]
)
\ No newline at end of file COMPLETE_SETS_ONE_INVALID = [
COMPLETE_SET_STAR,
COMPLETE_SET_INVALID_VIDEO_FISH
]
VIDEO_DICT_SET_OF_THREE = [
VIDEO_DICT_COAT,
VIDEO_DICT_AVERAGE,
VIDEO_DICT_CRAYFISH
]
VIDEO_DICT_INVALID_SET = [
VIDEO_DICT_COAT,
VIDEO_DICT_INVALID_ID,
VIDEO_DICT_BEE_INVALID
]
...@@ -25,17 +25,17 @@ class GetVideoInfoTest(TestCase): ...@@ -25,17 +25,17 @@ class GetVideoInfoTest(TestCase):
""" """
Profile.objects.create(**constants.PROFILE_DICT_MOBILE) Profile.objects.create(**constants.PROFILE_DICT_MOBILE)
Profile.objects.create(**constants.PROFILE_DICT_DESKTOP) Profile.objects.create(**constants.PROFILE_DICT_DESKTOP)
Video.objects.create(**constants.VIDEO_DICT_CATS) Video.objects.create(**constants.VIDEO_DICT_COAT)
EncodedVideo.objects.create( EncodedVideo.objects.create(
video=Video.objects.get( video=Video.objects.get(
edx_video_id=constants.VIDEO_DICT_CATS.get("edx_video_id") edx_video_id=constants.VIDEO_DICT_COAT.get("edx_video_id")
), ),
profile=Profile.objects.get(profile_name="mobile"), profile=Profile.objects.get(profile_name="mobile"),
**constants.ENCODED_VIDEO_DICT_MOBILE **constants.ENCODED_VIDEO_DICT_MOBILE
) )
EncodedVideo.objects.create( EncodedVideo.objects.create(
video=Video.objects.get( video=Video.objects.get(
edx_video_id=constants.VIDEO_DICT_CATS.get("edx_video_id") edx_video_id=constants.VIDEO_DICT_COAT.get("edx_video_id")
), ),
profile=Profile.objects.get(profile_name="desktop"), profile=Profile.objects.get(profile_name="desktop"),
**constants.ENCODED_VIDEO_DICT_DESKTOP **constants.ENCODED_VIDEO_DICT_DESKTOP
...@@ -77,4 +77,4 @@ class GetVideoInfoTest(TestCase): ...@@ -77,4 +77,4 @@ class GetVideoInfoTest(TestCase):
""" """
mock_get.side_effect = DatabaseError("DatabaseError") mock_get.side_effect = DatabaseError("DatabaseError")
with self.assertRaises(api.ValInternalError): with self.assertRaises(api.ValInternalError):
api.get_video_info(constants.EDX_VIDEO_ID) api.get_video_info(constants.EDX_VIDEO_ID)
\ No newline at end of file
...@@ -6,12 +6,14 @@ Tests the serializers for the Video Abstraction Layer ...@@ -6,12 +6,14 @@ Tests the serializers for the Video Abstraction Layer
from django.test import TestCase from django.test import TestCase
from edxval.serializers import ( from edxval.serializers import (
OnlyEncodedVideoSerializer, EncodedVideoSerializer,
EncodedVideoSetSerializer, EncodedVideoSetSerializer,
ProfileSerializer, ProfileSerializer,
VideoSerializer VideoSerializer,
DisplayProfileName
) )
from edxval.models import Profile from edxval.models import Profile, Video, EncodedVideo
from edxval.tests import constants from edxval.tests import constants
...@@ -24,6 +26,7 @@ class SerializerTests(TestCase): ...@@ -24,6 +26,7 @@ class SerializerTests(TestCase):
Creates EncodedVideo objects in database Creates EncodedVideo objects in database
""" """
Profile.objects.create(**constants.PROFILE_DICT_MOBILE) Profile.objects.create(**constants.PROFILE_DICT_MOBILE)
Profile.objects.create(**constants.PROFILE_DICT_DESKTOP)
Profile.objects.create(**constants.PROFILE_DICT_NON_LATIN) Profile.objects.create(**constants.PROFILE_DICT_NON_LATIN)
def test_negative_fields_only_encoded_video(self): def test_negative_fields_only_encoded_video(self):
...@@ -32,11 +35,12 @@ class SerializerTests(TestCase): ...@@ -32,11 +35,12 @@ class SerializerTests(TestCase):
Tests negative inputs for bitrate, file_size in EncodedVideo Tests negative inputs for bitrate, file_size in EncodedVideo
""" """
a = OnlyEncodedVideoSerializer( a = EncodedVideoSerializer(
data=constants.ENCODED_VIDEO_DICT_NEGATIVE_BITRATE).errors data=constants.ENCODED_VIDEO_DICT_NEGATIVE_BITRATE).errors
self.assertEqual(a.get('bitrate')[0], self.assertEqual(a.get('bitrate')[0],
u"Ensure this value is greater than or equal to 0.") u"Ensure this value is greater than or equal to 0.")
b = OnlyEncodedVideoSerializer( b = EncodedVideoSerializer(
data=constants.ENCODED_VIDEO_DICT_NEGATIVE_FILESIZE).errors data=constants.ENCODED_VIDEO_DICT_NEGATIVE_FILESIZE).errors
self.assertEqual(b.get('file_size')[0], self.assertEqual(b.get('file_size')[0],
u"Ensure this value is greater than or equal to 0.") u"Ensure this value is greater than or equal to 0.")
...@@ -56,6 +60,7 @@ class SerializerTests(TestCase): ...@@ -56,6 +60,7 @@ class SerializerTests(TestCase):
""" """
Tests if the serializers can accept non-latin chars Tests if the serializers can accept non-latin chars
""" """
#TODO not the best test. Need to understand what result we want
self.assertIsNotNone( self.assertIsNotNone(
ProfileSerializer(Profile.objects.get(profile_name="배고파")) ProfileSerializer(Profile.objects.get(profile_name="배고파"))
) )
...@@ -68,4 +73,22 @@ class SerializerTests(TestCase): ...@@ -68,4 +73,22 @@ class SerializerTests(TestCase):
message = error.get("edx_video_id")[0] message = error.get("edx_video_id")[0]
self.assertEqual( self.assertEqual(
message, message,
u"edx_video_id has invalid characters") u"edx_video_id has invalid characters")
\ No newline at end of file
def test_encoded_video_set_output(self):
"""
Tests for basic structure of EncodedVideoSetSerializer
"""
video = Video.objects.create(**constants.VIDEO_DICT_COAT)
EncodedVideo.objects.create(
video=video,
profile=Profile.objects.get(profile_name="desktop"),
**constants.ENCODED_VIDEO_DICT_DESKTOP
)
EncodedVideo.objects.create(
video=video,
profile=Profile.objects.get(profile_name="mobile"),
**constants.ENCODED_VIDEO_DICT_MOBILE
)
result = EncodedVideoSetSerializer(video).data
self.assertEqual(len(result.get("encoded_videos")), 2)
...@@ -3,12 +3,15 @@ from rest_framework.response import Response ...@@ -3,12 +3,15 @@ from rest_framework.response import Response
from rest_framework import status, generics from rest_framework import status, generics
from edxval.models import Video from edxval.models import Video
from edxval.serializers import VideoSerializer from edxval.serializers import VideoSerializer, EncodedVideoSetDeserializer, EncodedVideoSetSerializer
class VideoList(APIView): class VideoList(APIView):
""" """
HTTP API for Video objects <<<<<<< HEAD
HTTP API for Video and EncodedVideo objects
""" """
def get(self, request, format=None): def get(self, request, format=None):
...@@ -16,44 +19,27 @@ class VideoList(APIView): ...@@ -16,44 +19,27 @@ class VideoList(APIView):
Gets all videos Gets all videos
""" """
video = Video.objects.all() video = Video.objects.all()
serializer = VideoSerializer(video, many=True) serializer = EncodedVideoSetSerializer(video, many=True)
return Response(serializer.data) return Response(serializer.data)
def post(self, request, format=None): def post(self, request, format=None):
""" """
Takes an object (where we get our list of dict) and creates the objects Takes a Video dict of a list of EncodedVideo dicts and creates the objects
Request.DATA is a list of dictionaries. Each item is individually validated
and if valid, saved. All invalid dicts are returned in the error message.
Args: Args:
request (object): Object where we get our information for POST request (object): Object where we get our information for POST
format (str): format of our data (JSON, XML, etc.) data_format (str): format of our data (JSON, XML, etc.)
Returns: Returns:
Response(message, HTTP status) Response(message, HTTP status)
""" """
if not isinstance(request.DATA, list): serializer = EncodedVideoSetDeserializer(data=request.DATA)
error_message = "Not a list: {0}".format(type(request.DATA)) if serializer.is_valid():
return Response(error_message, status=status.HTTP_400_BAD_REQUEST) serializer.save()
invalid_videos = [] return Response("Success", status=status.HTTP_201_CREATED)
for item in request.DATA:
try:
instance = Video.objects.get(
edx_video_id=item.get("edx_video_id")
)
except Video.DoesNotExist:
instance = None
serializer = VideoSerializer(instance, data=item)
if serializer.is_valid():
serializer.save()
else:
invalid_videos.append((serializer.errors, item))
if invalid_videos:
return Response(invalid_videos, status=status.HTTP_400_BAD_REQUEST)
else: else:
return Response(status=status.HTTP_201_CREATED) return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
class VideoDetail(generics.RetrieveUpdateDestroyAPIView): class VideoDetail(generics.RetrieveUpdateDestroyAPIView):
...@@ -62,4 +48,4 @@ class VideoDetail(generics.RetrieveUpdateDestroyAPIView): ...@@ -62,4 +48,4 @@ class VideoDetail(generics.RetrieveUpdateDestroyAPIView):
""" """
lookup_field = "edx_video_id" lookup_field = "edx_video_id"
queryset = Video.objects.all() queryset = Video.objects.all()
serializer_class = VideoSerializer serializer_class = VideoSerializer
\ No newline at end of file
django-nose==1.2 django-nose==1.2
coverage==3.7.1 coverage==3.7.1
mock==1.0.1 mock==1.0.1
\ No newline at end of file django-debug-toolbar==1.2.1
from django.conf.urls import patterns, include, url from django.conf.urls import patterns, include, url
from rest_framework.urlpatterns import format_suffix_patterns
from edxval import views
from django.contrib import admin from django.contrib import admin
admin.autodiscover() admin.autodiscover()
urlpatterns = patterns('', urlpatterns = patterns('',
url(r'^edxval/', include('edxval.urls')), url(r'^edxval/video/$', views.VideoList.as_view(),
name="video_view"),
url(r'^edxval/video/(?P<edx_video_id>\w+)',
views.VideoDetail.as_view(),
name="video_detail_view"),
url(r'^admin/', include(admin.site.urls)), url(r'^admin/', include(admin.site.urls)),
) )
\ No newline at end of file
urlpatterns = format_suffix_patterns(urlpatterns)
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