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
9a878df0
Commit
9a878df0
authored
May 08, 2017
by
muhammad-ammar
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
support video images for course re-run and import/export
parent
23a651d5
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
142 additions
and
42 deletions
+142
-42
.travis.yml
+1
-0
edxval/api.py
+44
-10
edxval/models.py
+6
-4
edxval/serializers.py
+6
-6
edxval/tests/test_api.py
+84
-21
setup.py
+1
-1
No files found.
.travis.yml
View file @
9a878df0
...
...
@@ -10,5 +10,6 @@ script:
branches
:
only
:
-
master
-
ammar/course-rerun-import-export
after_success
:
coveralls
edxval/api.py
View file @
9a878df0
...
...
@@ -61,6 +61,7 @@ def create_video(video_data):
file_size: size of the video in bytes
profile: ID of the profile
courses: Courses associated with this video
image: poster image file name for a particular course
}
Raises:
...
...
@@ -147,7 +148,9 @@ def get_course_video_image_url(course_id, edx_video_id):
Returns course video image url or None if no image found
"""
try
:
video_image
=
CourseVideo
.
objects
.
get
(
course_id
=
course_id
,
video__edx_video_id
=
edx_video_id
)
.
video_image
video_image
=
CourseVideo
.
objects
.
select_related
(
'video_image'
)
.
get
(
course_id
=
course_id
,
video__edx_video_id
=
edx_video_id
)
.
video_image
return
video_image
.
image_url
()
except
ObjectDoesNotExist
:
return
None
...
...
@@ -157,6 +160,10 @@ def update_video_image(edx_video_id, course_id, image_data, file_name):
"""
Update video image for an existing video.
NOTE: If `image_data` is None then `file_name` value will be used as it is, otherwise
a new file name is constructed based on uuid and extension from `file_name` value.
`image_data` will be None in case of course re-run and export.
Arguments:
image_data (InMemoryUploadedFile): Image data to be saved for a course video.
...
...
@@ -167,9 +174,14 @@ def update_video_image(edx_video_id, course_id, image_data, file_name):
Raises ValVideoNotFoundError if the CourseVideo cannot be retrieved.
"""
try
:
course_video
=
CourseVideo
.
objects
.
get
(
course_id
=
course_id
,
video__edx_video_id
=
edx_video_id
)
course_video
=
CourseVideo
.
objects
.
select_related
(
'video'
)
.
get
(
course_id
=
course_id
,
video__edx_video_id
=
edx_video_id
)
except
ObjectDoesNotExist
:
error_message
=
u'CourseVideo not found for edx_video_id: {0}'
.
format
(
edx_video_id
)
error_message
=
u'VAL: CourseVideo not found for edx_video_id: {0} and course_id: {1}'
.
format
(
edx_video_id
,
course_id
)
raise
ValVideoNotFoundError
(
error_message
)
video_image
,
_
=
VideoImage
.
create_or_update
(
course_video
,
file_name
,
image_data
)
...
...
@@ -476,21 +488,29 @@ def copy_course_videos(source_course_id, destination_course_id):
if
source_course_id
==
destination_course_id
:
return
videos
=
Video
.
objects
.
filter
(
courses__course_id
=
unicode
(
source_course_id
))
course_videos
=
CourseVideo
.
objects
.
select_related
(
'video'
,
'video_image'
)
.
filter
(
course_id
=
unicode
(
source_course_id
)
)
for
video
in
videos
:
CourseVideo
.
objects
.
get_or_create
(
video
=
video
,
for
course_video
in
course_
videos
:
destination_course_video
,
__
=
CourseVideo
.
objects
.
get_or_create
(
video
=
course_video
.
video
,
course_id
=
destination_course_id
)
if
hasattr
(
course_video
,
'video_image'
):
VideoImage
.
create_or_update
(
course_video
=
destination_course_video
,
file_name
=
course_video
.
video_image
.
image
.
name
)
def
export_to_xml
(
edx_video_id
):
def
export_to_xml
(
edx_video_id
,
course_id
=
None
):
"""
Exports data about the given edx_video_id into the given xml object.
Args:
edx_video_id (str): The ID of the video to export
course_id (str): The ID of the course with which this video is associated
Returns:
An lxml video_asset element containing export data
...
...
@@ -498,12 +518,21 @@ def export_to_xml(edx_video_id):
Raises:
ValVideoNotFoundError: if the video does not exist
"""
video_image_name
=
''
video
=
_get_video
(
edx_video_id
)
try
:
course_video
=
CourseVideo
.
objects
.
select_related
(
'video_image'
)
.
get
(
course_id
=
course_id
,
video
=
video
)
video_image_name
=
course_video
.
video_image
.
image
.
name
except
ObjectDoesNotExist
:
pass
video_el
=
Element
(
'video_asset'
,
attrib
=
{
'client_video_id'
:
video
.
client_video_id
,
'duration'
:
unicode
(
video
.
duration
),
'image'
:
video_image_name
}
)
for
encoded_video
in
video
.
encoded_videos
.
all
():
...
...
@@ -548,7 +577,12 @@ def import_from_xml(xml, edx_video_id, course_id=None):
course_id
,
)
if
course_id
:
CourseVideo
.
get_or_create_with_validation
(
video
=
video
,
course_id
=
course_id
)
course_video
,
__
=
CourseVideo
.
get_or_create_with_validation
(
video
=
video
,
course_id
=
course_id
)
image_file_name
=
xml
.
get
(
'image'
,
''
)
.
strip
()
if
image_file_name
:
VideoImage
.
create_or_update
(
course_video
,
image_file_name
)
return
except
ValidationError
as
err
:
logger
.
exception
(
err
.
message
)
...
...
@@ -563,7 +597,7 @@ def import_from_xml(xml, edx_video_id, course_id=None):
'duration'
:
xml
.
get
(
'duration'
),
'status'
:
'imported'
,
'encoded_videos'
:
[],
'courses'
:
[
course_id
]
if
course_id
else
[],
'courses'
:
[
{
course_id
:
xml
.
get
(
'image'
)}
]
if
course_id
else
[],
}
for
encoded_video_el
in
xml
.
iterfind
(
'encoded_video'
):
profile_name
=
encoded_video_el
.
get
(
'profile'
)
...
...
edxval/models.py
View file @
9a878df0
...
...
@@ -211,6 +211,10 @@ class VideoImage(TimeStampedModel):
"""
Create a VideoImage object for a CourseVideo.
NOTE: If `image_data` is None then `file_name` value will be used as it is, otherwise
a new file name is constructed based on uuid and extension from `file_name` value.
`image_data` will be None in case of course re-run and export.
Arguments:
course_video (CourseVideo): CourseVideo instance
file_name (str): File name of the image
...
...
@@ -224,14 +228,12 @@ class VideoImage(TimeStampedModel):
with
closing
(
image_data
)
as
image_file
:
file_name
=
'{uuid}{ext}'
.
format
(
uuid
=
uuid4
()
.
hex
,
ext
=
os
.
path
.
splitext
(
file_name
)[
1
])
try
:
course_id
=
course_video
.
course_id
edx_video_id
=
course_video
.
video
.
edx_video_id
video_image
.
image
.
save
(
file_name
,
image_file
)
except
Exception
:
# pylint: disable=broad-except
logger
.
exception
(
'VAL: Video Image save failed to storage for course_id [
%
s] and video_id [
%
s]'
,
course_id
,
edx_video_id
course_
video
.
course_
id
,
course_video
.
video
.
edx_video_id
)
raise
else
:
...
...
edxval/serializers.py
View file @
9a878df0
...
...
@@ -182,11 +182,11 @@ 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.
# Also create VideoImage objects if an image filename is present
for
course_video
,
image
in
courses
:
for
course_video
,
image
_name
in
courses
:
course_video
.
video
=
video
course_video
.
save
()
if
image
:
VideoImage
.
create_or_update
(
course_video
,
image
)
if
image
_name
:
VideoImage
.
create_or_update
(
course_video
,
image
_name
)
return
video
...
...
@@ -217,10 +217,10 @@ class VideoSerializer(serializers.ModelSerializer):
# NOTE: for backwards compatibility with the DRF v2 behavior,
# we do NOT delete existing course videos during the update.
# Also update VideoImage objects if an image filename is present
for
course_video
,
image
in
validated_data
.
get
(
"courses"
,
[]):
for
course_video
,
image
_name
in
validated_data
.
get
(
"courses"
,
[]):
course_video
.
video
=
instance
course_video
.
save
()
if
image
:
VideoImage
.
create_or_update
(
course_video
,
image
)
if
image
_name
:
VideoImage
.
create_or_update
(
course_video
,
image
_name
)
return
instance
edxval/tests/test_api.py
View file @
9a878df0
This diff is collapsed.
Click to expand it.
setup.py
View file @
9a878df0
...
...
@@ -39,7 +39,7 @@ def load_requirements(*requirements_paths):
setup
(
name
=
'edxval'
,
version
=
'0.0.1
3
'
,
version
=
'0.0.1
5
'
,
author
=
'edX'
,
url
=
'http://github.com/edx/edx-val'
,
description
=
'edx-val'
,
...
...
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