Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
E
edx-val
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
edx
edx-val
Commits
47eee6da
Commit
47eee6da
authored
May 09, 2017
by
muhammad-ammar
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
update serializer
parent
41b99811
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
55 additions
and
41 deletions
+55
-41
edxval/api.py
+3
-4
edxval/models.py
+20
-7
edxval/serializers.py
+28
-26
edxval/tests/test_api.py
+3
-3
edxval/tests/test_views.py
+1
-1
No files found.
edxval/api.py
View file @
47eee6da
...
@@ -187,7 +187,7 @@ def update_video_image(edx_video_id, course_id, image_data, file_name):
...
@@ -187,7 +187,7 @@ def update_video_image(edx_video_id, course_id, image_data, file_name):
error_message
=
u"CourseVideo not found for edx_video_id: {0}"
.
format
(
edx_video_id
)
error_message
=
u"CourseVideo not found for edx_video_id: {0}"
.
format
(
edx_video_id
)
raise
ValVideoNotFoundError
(
error_message
)
raise
ValVideoNotFoundError
(
error_message
)
video_image
,
_
=
VideoImage
.
create_or_update
(
course_video
,
image_data
,
file_name
)
video_image
,
_
=
VideoImage
.
create_or_update
(
course_video
,
file_name
,
image_data
)
return
get_course_video_image_url
(
video_image
=
video_image
)
return
get_course_video_image_url
(
video_image
=
video_image
)
...
@@ -323,7 +323,7 @@ def get_url_for_profile(edx_video_id, profile):
...
@@ -323,7 +323,7 @@ def get_url_for_profile(edx_video_id, profile):
return
get_urls_for_profiles
(
edx_video_id
,
[
profile
])[
profile
]
return
get_urls_for_profiles
(
edx_video_id
,
[
profile
])[
profile
]
def
_get_videos_for_filter
(
video_filter
,
sort_field
=
None
,
sort_dir
=
SortDirection
.
asc
,
context
=
None
):
def
_get_videos_for_filter
(
video_filter
,
sort_field
=
None
,
sort_dir
=
SortDirection
.
asc
):
"""
"""
Returns a generator expression that contains the videos found, sorted by
Returns a generator expression that contains the videos found, sorted by
the given field and direction, with ties broken by edx_video_id to ensure a
the given field and direction, with ties broken by edx_video_id to ensure a
...
@@ -335,7 +335,7 @@ def _get_videos_for_filter(video_filter, sort_field=None, sort_dir=SortDirection
...
@@ -335,7 +335,7 @@ def _get_videos_for_filter(video_filter, sort_field=None, sort_dir=SortDirection
videos
=
videos
.
order_by
(
sort_field
.
value
,
"edx_video_id"
)
videos
=
videos
.
order_by
(
sort_field
.
value
,
"edx_video_id"
)
if
sort_dir
==
SortDirection
.
desc
:
if
sort_dir
==
SortDirection
.
desc
:
videos
=
videos
.
reverse
()
videos
=
videos
.
reverse
()
return
(
VideoSerializer
(
video
,
context
=
context
)
.
data
for
video
in
videos
)
return
(
VideoSerializer
(
video
)
.
data
for
video
in
videos
)
def
get_videos_for_course
(
course_id
,
sort_field
=
None
,
sort_dir
=
SortDirection
.
asc
):
def
get_videos_for_course
(
course_id
,
sort_field
=
None
,
sort_dir
=
SortDirection
.
asc
):
...
@@ -356,7 +356,6 @@ def get_videos_for_course(course_id, sort_field=None, sort_dir=SortDirection.asc
...
@@ -356,7 +356,6 @@ def get_videos_for_course(course_id, sort_field=None, sort_dir=SortDirection.asc
{
'courses__course_id'
:
unicode
(
course_id
),
'courses__is_hidden'
:
False
},
{
'courses__course_id'
:
unicode
(
course_id
),
'courses__is_hidden'
:
False
},
sort_field
,
sort_field
,
sort_dir
,
sort_dir
,
context
=
{
'course_id'
:
course_id
}
)
)
...
...
edxval/models.py
View file @
47eee6da
...
@@ -14,6 +14,7 @@ invalid profile_name will be returned.
...
@@ -14,6 +14,7 @@ invalid profile_name will be returned.
from
contextlib
import
closing
from
contextlib
import
closing
import
logging
import
logging
import
os
import
os
from
uuid
import
uuid4
from
django.db
import
models
from
django.db
import
models
from
django.dispatch
import
receiver
from
django.dispatch
import
receiver
...
@@ -41,6 +42,7 @@ class ModelFactoryWithValidation(object):
...
@@ -41,6 +42,7 @@ class ModelFactoryWithValidation(object):
ret_val
=
cls
(
*
args
,
**
kwargs
)
ret_val
=
cls
(
*
args
,
**
kwargs
)
ret_val
.
full_clean
()
ret_val
.
full_clean
()
ret_val
.
save
()
ret_val
.
save
()
return
ret_val
@classmethod
@classmethod
def
get_or_create_with_validation
(
cls
,
*
args
,
**
kwargs
):
def
get_or_create_with_validation
(
cls
,
*
args
,
**
kwargs
):
...
@@ -198,27 +200,38 @@ class VideoImage(TimeStampedModel):
...
@@ -198,27 +200,38 @@ class VideoImage(TimeStampedModel):
image
=
CustomizableImageField
()
image
=
CustomizableImageField
()
@classmethod
@classmethod
def
create_or_update
(
cls
,
course_video
,
image_data
,
file_nam
e
):
def
create_or_update
(
cls
,
course_video
,
file_name
,
image_data
=
Non
e
):
"""
"""
Create a VideoImage object for a CourseVideo.
Create a VideoImage object for a CourseVideo.
Arguments:
Arguments:
course_video (CourseVideo): CourseVideo instance
course_video (CourseVideo): CourseVideo instance
file_name (str): File name of the image
image_data (InMemoryUploadedFile): Image data to be saved.
image_data (InMemoryUploadedFile): Image data to be saved.
file_name (str): File name.
Returns:
Returns:
Returns a tuple of (video_image, created).
Returns a tuple of (video_image, created).
"""
"""
video_image
,
created
=
cls
.
objects
.
get_or_create
(
course_video
=
course_video
)
video_image
,
created
=
cls
.
objects
.
get_or_create
(
course_video
=
course_video
)
with
closing
(
image_data
)
as
image_file
:
if
image_data
:
__
,
file_extension
=
os
.
path
.
splitext
(
file_name
)
with
closing
(
image_data
)
as
image_file
:
file_name
=
'{timestamp}{ext}'
.
format
(
timestamp
=
video_image
.
modified
.
strftime
(
"
%
s"
),
ext
=
file_extension
)
file_name
=
'{uuid}{ext}'
.
format
(
uuid
=
uuid4
()
.
hex
,
ext
=
os
.
path
.
splitext
(
file_name
)[
1
])
video_image
.
image
.
save
(
file_name
,
image_file
)
video_image
.
image
.
save
(
file_name
,
image_file
)
video_image
.
save
()
else
:
video_image
.
image
.
name
=
file_name
video_image
.
save
()
return
video_image
,
created
return
video_image
,
created
@classmethod
def
image_url
(
cls
,
course_video
):
"""
Return image url for a course video image.
"""
storage
=
get_video_image_storage
()
if
hasattr
(
course_video
,
'video_image'
):
return
storage
.
url
(
course_video
.
video_image
.
image
.
name
)
SUBTITLE_FORMATS
=
(
SUBTITLE_FORMATS
=
(
(
'srt'
,
'SubRip'
),
(
'srt'
,
'SubRip'
),
...
...
edxval/serializers.py
View file @
47eee6da
...
@@ -7,8 +7,7 @@ EncodedVideoSerializer which uses the profile_name as it's profile field.
...
@@ -7,8 +7,7 @@ EncodedVideoSerializer which uses the profile_name as it's profile field.
from
rest_framework
import
serializers
from
rest_framework
import
serializers
from
rest_framework.fields
import
IntegerField
,
DateTimeField
from
rest_framework.fields
import
IntegerField
,
DateTimeField
from
edxval.models
import
Profile
,
Video
,
EncodedVideo
,
Subtitle
,
CourseVideo
from
edxval.models
import
Profile
,
Video
,
EncodedVideo
,
Subtitle
,
CourseVideo
,
VideoImage
from
edxval.exceptions
import
ValVideoImageNotFoundError
class
EncodedVideoSerializer
(
serializers
.
ModelSerializer
):
class
EncodedVideoSerializer
(
serializers
.
ModelSerializer
):
...
@@ -88,14 +87,27 @@ class CourseSerializer(serializers.RelatedField):
...
@@ -88,14 +87,27 @@ class CourseSerializer(serializers.RelatedField):
"""
"""
Field for CourseVideo
Field for CourseVideo
"""
"""
def
to_representation
(
self
,
value
):
def
to_representation
(
self
,
course_video
):
return
value
.
course_id
"""
Returns a serializable representation of a CourseVideo instance.
"""
return
{
course_video
.
course_id
:
VideoImage
.
image_url
(
course_video
)
}
def
to_internal_value
(
self
,
data
):
def
to_internal_value
(
self
,
data
):
if
data
:
"""
course_video
=
CourseVideo
(
course_id
=
data
)
Convert data into CourseVideo instance and image filename tuple.
course_video
.
full_clean
(
exclude
=
[
"video"
])
"""
return
course_video
if
isinstance
(
data
,
basestring
):
course_id
,
image
=
data
,
None
elif
isinstance
(
data
,
dict
):
(
course_id
,
image
),
=
data
.
items
()
course_video
=
CourseVideo
(
course_id
=
course_id
)
course_video
.
full_clean
(
exclude
=
[
"video"
])
return
course_video
,
image
class
VideoSerializer
(
serializers
.
ModelSerializer
):
class
VideoSerializer
(
serializers
.
ModelSerializer
):
...
@@ -112,7 +124,6 @@ class VideoSerializer(serializers.ModelSerializer):
...
@@ -112,7 +124,6 @@ class VideoSerializer(serializers.ModelSerializer):
required
=
False
,
required
=
False
,
queryset
=
CourseVideo
.
objects
.
all
()
queryset
=
CourseVideo
.
objects
.
all
()
)
)
course_video_image_url
=
serializers
.
SerializerMethodField
()
url
=
serializers
.
SerializerMethodField
()
url
=
serializers
.
SerializerMethodField
()
# Django Rest Framework v3 converts datetimes to unicode by default.
# Django Rest Framework v3 converts datetimes to unicode by default.
...
@@ -124,21 +135,6 @@ class VideoSerializer(serializers.ModelSerializer):
...
@@ -124,21 +135,6 @@ class VideoSerializer(serializers.ModelSerializer):
lookup_field
=
"edx_video_id"
lookup_field
=
"edx_video_id"
exclude
=
(
'id'
,)
exclude
=
(
'id'
,)
def
get_course_video_image_url
(
self
,
video
):
"""
Return image associated with a course video or None if course_id is missing or if there is any error.
"""
# Imported here to avoid circular dependency
from
edxval.api
import
get_course_video_image_url
if
self
.
context
is
None
or
'course_id'
not
in
self
.
context
:
return
None
try
:
return
get_course_video_image_url
(
self
.
context
[
'course_id'
],
video
.
edx_video_id
)
except
ValVideoImageNotFoundError
:
return
None
def
get_url
(
self
,
obj
):
def
get_url
(
self
,
obj
):
"""
"""
Return relative url for the object
Return relative url for the object
...
@@ -185,9 +181,12 @@ class VideoSerializer(serializers.ModelSerializer):
...
@@ -185,9 +181,12 @@ class VideoSerializer(serializers.ModelSerializer):
# The CourseSerializer will already have converted the course data
# The CourseSerializer will already have converted the course data
# to CourseVideo models, so we can just set the video and save.
# to CourseVideo models, so we can just set the video and save.
for
course_video
in
courses
:
# Also create VideoImage objects if an image filename is present
for
course_video
,
image
in
courses
:
course_video
.
video
=
video
course_video
.
video
=
video
course_video
.
save
()
course_video
.
save
()
if
image
:
VideoImage
.
create_or_update
(
course_video
,
image
)
return
video
return
video
...
@@ -217,8 +216,11 @@ class VideoSerializer(serializers.ModelSerializer):
...
@@ -217,8 +216,11 @@ class VideoSerializer(serializers.ModelSerializer):
# Set courses
# Set courses
# NOTE: for backwards compatibility with the DRF v2 behavior,
# NOTE: for backwards compatibility with the DRF v2 behavior,
# we do NOT delete existing course videos during the update.
# we do NOT delete existing course videos during the update.
for
course_video
in
validated_data
.
get
(
"courses"
,
[]):
# Also update VideoImage objects if an image filename is present
for
course_video
,
image
in
validated_data
.
get
(
"courses"
,
[]):
course_video
.
video
=
instance
course_video
.
video
=
instance
course_video
.
save
()
course_video
.
save
()
if
image
:
VideoImage
.
create_or_update
(
course_video
,
image
)
return
instance
return
instance
edxval/tests/test_api.py
View file @
47eee6da
...
@@ -1241,12 +1241,12 @@ class CourseVideoImageTest(TestCase):
...
@@ -1241,12 +1241,12 @@ class CourseVideoImageTest(TestCase):
"""
"""
video_data_generator
=
api
.
get_videos_for_course
(
self
.
course_id
)
video_data_generator
=
api
.
get_videos_for_course
(
self
.
course_id
)
video_data
=
list
(
video_data_generator
)[
0
]
video_data
=
list
(
video_data_generator
)[
0
]
self
.
assertEqual
(
video_data
[
'course
_video_image_url
'
],
self
.
image_url
)
self
.
assertEqual
(
video_data
[
'course
s'
][
0
][
'test-course
'
],
self
.
image_url
)
def
test_get_videos_for_ids
(
self
):
def
test_get_videos_for_ids
(
self
):
"""
"""
Verify that `get_videos_for_ids` api function returns reponse with course_video_image_url set to None.
Verify that `get_videos_for_ids` api function returns re
s
ponse with course_video_image_url set to None.
"""
"""
video_data_generator
=
api
.
get_videos_for_ids
([
self
.
edx_video_id
])
video_data_generator
=
api
.
get_videos_for_ids
([
self
.
edx_video_id
])
video_data
=
list
(
video_data_generator
)[
0
]
video_data
=
list
(
video_data_generator
)[
0
]
self
.
assertEqual
(
video_data
[
'course
_video_image_url'
],
None
)
self
.
assertEqual
(
video_data
[
'course
s'
][
0
][
'test-course'
],
self
.
image_url
)
edxval/tests/test_views.py
View file @
47eee6da
...
@@ -580,7 +580,7 @@ class VideoListTest(APIAuthTestCase):
...
@@ -580,7 +580,7 @@ class VideoListTest(APIAuthTestCase):
self
.
assertEqual
(
response
.
status_code
,
status
.
HTTP_201_CREATED
)
self
.
assertEqual
(
response
.
status_code
,
status
.
HTTP_201_CREATED
)
videos
=
self
.
client
.
get
(
"/edxval/videos/"
)
.
data
videos
=
self
.
client
.
get
(
"/edxval/videos/"
)
.
data
self
.
assertEqual
(
len
(
videos
),
1
)
self
.
assertEqual
(
len
(
videos
),
1
)
self
.
assertEqual
(
videos
[
0
][
'courses'
],
[
course1
,
course2
])
self
.
assertEqual
(
videos
[
0
][
'courses'
],
[
{
course1
:
None
},
{
course2
:
None
}
])
url
=
reverse
(
'video-list'
)
+
'?course=
%
s'
%
course1
url
=
reverse
(
'video-list'
)
+
'?course=
%
s'
%
course1
videos
=
self
.
client
.
get
(
url
)
.
data
videos
=
self
.
client
.
get
(
url
)
.
data
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment