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):
error_message
=
u"CourseVideo not found for edx_video_id: {0}"
.
format
(
edx_video_id
)
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
)
...
...
@@ -323,7 +323,7 @@ def get_url_for_profile(edx_video_id, 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
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
videos
=
videos
.
order_by
(
sort_field
.
value
,
"edx_video_id"
)
if
sort_dir
==
SortDirection
.
desc
:
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
):
...
...
@@ -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
},
sort_field
,
sort_dir
,
context
=
{
'course_id'
:
course_id
}
)
...
...
edxval/models.py
View file @
47eee6da
...
...
@@ -14,6 +14,7 @@ invalid profile_name will be returned.
from
contextlib
import
closing
import
logging
import
os
from
uuid
import
uuid4
from
django.db
import
models
from
django.dispatch
import
receiver
...
...
@@ -41,6 +42,7 @@ class ModelFactoryWithValidation(object):
ret_val
=
cls
(
*
args
,
**
kwargs
)
ret_val
.
full_clean
()
ret_val
.
save
()
return
ret_val
@classmethod
def
get_or_create_with_validation
(
cls
,
*
args
,
**
kwargs
):
...
...
@@ -198,27 +200,38 @@ class VideoImage(TimeStampedModel):
image
=
CustomizableImageField
()
@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.
Arguments:
course_video (CourseVideo): CourseVideo instance
file_name (str): File name of the image
image_data (InMemoryUploadedFile): Image data to be saved.
file_name (str): File name.
Returns:
Returns a tuple of (video_image, created).
"""
video_image
,
created
=
cls
.
objects
.
get_or_create
(
course_video
=
course_video
)
with
closing
(
image_data
)
as
image_file
:
__
,
file_extension
=
os
.
path
.
splitext
(
file_name
)
file_name
=
'{timestamp}{ext}'
.
format
(
timestamp
=
video_image
.
modified
.
strftime
(
"
%
s"
),
ext
=
file_extension
)
video_image
.
image
.
save
(
file_name
,
image_file
)
video_image
.
save
()
if
image_data
:
with
closing
(
image_data
)
as
image_file
:
file_name
=
'{uuid}{ext}'
.
format
(
uuid
=
uuid4
()
.
hex
,
ext
=
os
.
path
.
splitext
(
file_name
)[
1
])
video_image
.
image
.
save
(
file_name
,
image_file
)
else
:
video_image
.
image
.
name
=
file_name
video_image
.
save
()
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
=
(
(
'srt'
,
'SubRip'
),
...
...
edxval/serializers.py
View file @
47eee6da
...
...
@@ -7,8 +7,7 @@ EncodedVideoSerializer which uses the profile_name as it's profile field.
from
rest_framework
import
serializers
from
rest_framework.fields
import
IntegerField
,
DateTimeField
from
edxval.models
import
Profile
,
Video
,
EncodedVideo
,
Subtitle
,
CourseVideo
from
edxval.exceptions
import
ValVideoImageNotFoundError
from
edxval.models
import
Profile
,
Video
,
EncodedVideo
,
Subtitle
,
CourseVideo
,
VideoImage
class
EncodedVideoSerializer
(
serializers
.
ModelSerializer
):
...
...
@@ -88,14 +87,27 @@ class CourseSerializer(serializers.RelatedField):
"""
Field for CourseVideo
"""
def
to_representation
(
self
,
value
):
return
value
.
course_id
def
to_representation
(
self
,
course_video
):
"""
Returns a serializable representation of a CourseVideo instance.
"""
return
{
course_video
.
course_id
:
VideoImage
.
image_url
(
course_video
)
}
def
to_internal_value
(
self
,
data
):
if
data
:
course_video
=
CourseVideo
(
course_id
=
data
)
course_video
.
full_clean
(
exclude
=
[
"video"
])
return
course_video
"""
Convert data into CourseVideo instance and image filename tuple.
"""
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
):
...
...
@@ -112,7 +124,6 @@ class VideoSerializer(serializers.ModelSerializer):
required
=
False
,
queryset
=
CourseVideo
.
objects
.
all
()
)
course_video_image_url
=
serializers
.
SerializerMethodField
()
url
=
serializers
.
SerializerMethodField
()
# Django Rest Framework v3 converts datetimes to unicode by default.
...
...
@@ -124,21 +135,6 @@ class VideoSerializer(serializers.ModelSerializer):
lookup_field
=
"edx_video_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
):
"""
Return relative url for the object
...
...
@@ -185,9 +181,12 @@ class VideoSerializer(serializers.ModelSerializer):
# The CourseSerializer will already have converted the course data
# 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
.
save
()
if
image
:
VideoImage
.
create_or_update
(
course_video
,
image
)
return
video
...
...
@@ -217,8 +216,11 @@ class VideoSerializer(serializers.ModelSerializer):
# Set courses
# NOTE: for backwards compatibility with the DRF v2 behavior,
# 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
.
save
()
if
image
:
VideoImage
.
create_or_update
(
course_video
,
image
)
return
instance
edxval/tests/test_api.py
View file @
47eee6da
...
...
@@ -1241,12 +1241,12 @@ class CourseVideoImageTest(TestCase):
"""
video_data_generator
=
api
.
get_videos_for_course
(
self
.
course_id
)
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
):
"""
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
=
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):
self
.
assertEqual
(
response
.
status_code
,
status
.
HTTP_201_CREATED
)
videos
=
self
.
client
.
get
(
"/edxval/videos/"
)
.
data
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
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