Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
E
edx-platform
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-platform
Commits
037ef3be
Commit
037ef3be
authored
Jun 04, 2015
by
Nimisha Asthagiri
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Video module support for student_view_json.
parent
65e330e8
Show whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
196 additions
and
4 deletions
+196
-4
common/lib/xmodule/xmodule/video_module/video_handlers.py
+2
-1
common/lib/xmodule/xmodule/video_module/video_module.py
+78
-2
lms/djangoapps/courseware/tests/test_video_mongo.py
+116
-1
No files found.
common/lib/xmodule/xmodule/video_module/video_handlers.py
View file @
037ef3be
...
...
@@ -250,9 +250,10 @@ class VideoStudentViewHandlers(object):
response
.
content_type
=
Transcript
.
mime_types
[
'sjson'
]
elif
dispatch
==
'download'
:
lang
=
request
.
GET
.
get
(
'lang'
,
None
)
try
:
transcript_content
,
transcript_filename
,
transcript_mime_type
=
self
.
get_transcript
(
transcripts
,
transcript_format
=
self
.
transcript_download_format
transcripts
,
transcript_format
=
self
.
transcript_download_format
,
lang
=
lang
)
except
(
NotFoundError
,
ValueError
,
KeyError
,
UnicodeDecodeError
):
log
.
debug
(
"Video@download exception"
)
...
...
common/lib/xmodule/xmodule/video_module/video_module.py
View file @
037ef3be
...
...
@@ -20,12 +20,12 @@ import logging
import
random
from
collections
import
OrderedDict
from
operator
import
itemgetter
from
lxml
import
etree
from
pkg_resources
import
resource_string
from
django.conf
import
settings
from
openedx.core.lib.cache_utils
import
memoize_in_request_cache
from
xblock.core
import
XBlock
from
xblock.fields
import
ScopeIds
from
xblock.runtime
import
KvsFieldData
...
...
@@ -329,6 +329,7 @@ class VideoModule(VideoFields, VideoTranscriptsMixin, VideoStudentViewHandlers,
return
self
.
system
.
render_template
(
'video.html'
,
context
)
@XBlock.wants
(
"request_cache"
)
@XBlock.wants
(
"settings"
)
class
VideoDescriptor
(
VideoFields
,
VideoTranscriptsMixin
,
VideoStudioViewHandlers
,
TabsEditingDescriptor
,
EmptyDataRawDescriptor
):
...
...
@@ -722,7 +723,7 @@ class VideoDescriptor(VideoFields, VideoTranscriptsMixin, VideoStudioViewHandler
if
self
.
sub
:
_update_transcript_for_index
()
#
c
heck to see if there are transcripts in other languages besides default transcript
#
C
heck to see if there are transcripts in other languages besides default transcript
if
self
.
transcripts
:
for
language
in
self
.
transcripts
.
keys
():
_update_transcript_for_index
(
language
)
...
...
@@ -734,3 +735,78 @@ class VideoDescriptor(VideoFields, VideoTranscriptsMixin, VideoStudioViewHandler
xblock_body
[
"content_type"
]
=
"Video"
return
xblock_body
@property
def
request_cache
(
self
):
"""
Returns the request_cache from the runtime.
"""
return
self
.
runtime
.
service
(
self
,
"request_cache"
)
@memoize_in_request_cache
(
'request_cache'
)
def
get_cached_val_data_for_course
(
self
,
video_profile_names
,
course_id
):
"""
Returns the VAL data for the requested video profiles for the given course.
"""
return
edxval_api
.
get_video_info_for_course_and_profiles
(
unicode
(
course_id
),
video_profile_names
)
def
student_view_json
(
self
,
context
):
"""
Returns a JSON representation of the student_view of this XModule.
The contract of the JSON content is between the caller and the particular XModule.
"""
# Honor only_on_web
if
self
.
only_on_web
:
return
{
"only_on_web"
:
True
}
encoded_videos
=
{}
val_video_data
=
{}
# Check in VAL data first if edx_video_id exists
if
self
.
edx_video_id
:
video_profile_names
=
context
.
get
(
"profiles"
,
[])
# get and cache bulk VAL data for course
val_course_data
=
self
.
get_cached_val_data_for_course
(
video_profile_names
,
self
.
location
.
course_key
)
val_video_data
=
val_course_data
.
get
(
self
.
edx_video_id
,
{})
# Get the encoded videos if data from VAL is found
if
val_video_data
:
encoded_videos
=
val_video_data
.
get
(
'profiles'
,
{})
# If information for this edx_video_id is not found in the bulk course data, make a
# separate request for this individual edx_video_id, unless cache misses are disabled.
# This is useful/required for videos that don't have a course designated, such as the introductory video
# that is shared across many courses. However, this results in a separate database request so watch
# out for any performance hit if many such videos exist in a course. Set the 'allow_cache_miss' parameter
# to False to disable this fall back.
elif
context
.
get
(
"allow_cache_miss"
,
"True"
)
.
lower
()
==
"true"
:
try
:
val_video_data
=
edxval_api
.
get_video_info
(
self
.
edx_video_id
)
# Unfortunately, the VAL API is inconsistent in how it returns the encodings, so remap here.
for
enc_vid
in
val_video_data
.
pop
(
'encoded_videos'
):
encoded_videos
[
enc_vid
[
'profile'
]]
=
{
key
:
enc_vid
[
key
]
for
key
in
[
"url"
,
"file_size"
]}
except
edxval_api
.
ValVideoNotFoundError
:
pass
# Fall back to other video URLs in the video module if not found in VAL
if
not
encoded_videos
:
video_url
=
self
.
html5_sources
[
0
]
if
self
.
html5_sources
else
self
.
source
if
video_url
:
encoded_videos
[
"fallback"
]
=
{
"url"
:
video_url
,
"file_size"
:
0
,
# File size is unknown for fallback URLs
}
transcripts_info
=
self
.
get_transcripts_info
()
transcripts
=
{
lang
:
self
.
runtime
.
handler_url
(
self
,
'transcript'
,
'download'
,
query
=
"lang="
+
lang
,
thirdparty
=
True
)
for
lang
in
self
.
available_translations
(
transcripts_info
,
verify_assets
=
False
)
}
return
{
"only_on_web"
:
self
.
only_on_web
,
"duration"
:
val_video_data
.
get
(
'duration'
,
None
),
"transcripts"
:
transcripts
,
"encoded_videos"
:
encoded_videos
,
}
lms/djangoapps/courseware/tests/test_video_mongo.py
View file @
037ef3be
# -*- coding: utf-8 -*-
"""Video xmodule tests in mongo."""
import
ddt
import
itertools
import
json
from
collections
import
OrderedDict
...
...
@@ -13,7 +15,7 @@ from django.test.utils import override_settings
from
xmodule.video_module
import
VideoDescriptor
,
bumper_utils
,
video_utils
from
xmodule.x_module
import
STUDENT_VIEW
from
xmodule.tests.test_video
import
VideoDescriptorTestBase
from
xmodule.tests.test_video
import
VideoDescriptorTestBase
,
instantiate_descriptor
from
xmodule.tests.test_import
import
DummySystem
from
edxval.api
import
(
...
...
@@ -861,6 +863,119 @@ class TestVideoDescriptorInitialization(BaseTestXmodule):
self
.
assertFalse
(
self
.
item_descriptor
.
download_video
)
@ddt.ddt
class
TestVideoDescriptorStudentViewJson
(
TestCase
):
"""
Tests for the student_view_json method on VideoDescriptor.
"""
TEST_DURATION
=
111.0
TEST_PROFILE
=
"mobile"
TEST_SOURCE_URL
=
"http://www.example.com/source.mp4"
TEST_LANGUAGE
=
"ge"
TEST_ENCODED_VIDEO
=
{
'profile'
:
TEST_PROFILE
,
'bitrate'
:
333
,
'url'
:
'http://example.com/video'
,
'file_size'
:
222
,
}
TEST_EDX_VIDEO_ID
=
'test_edx_video_id'
def
setUp
(
self
):
super
(
TestVideoDescriptorStudentViewJson
,
self
)
.
setUp
()
sample_xml
=
(
"<video display_name='Test Video'> "
+
"<source src='"
+
self
.
TEST_SOURCE_URL
+
"'/> "
+
"<transcript language='"
+
self
.
TEST_LANGUAGE
+
"' src='german_translation.srt' /> "
+
"</video>"
)
self
.
transcript_url
=
"transcript_url"
self
.
video
=
instantiate_descriptor
(
data
=
sample_xml
)
self
.
video
.
runtime
.
handler_url
=
Mock
(
return_value
=
self
.
transcript_url
)
def
setup_val_video
(
self
,
associate_course_in_val
=
False
):
"""
Creates a video entry in VAL.
Arguments:
associate_course - If True, associates the test course with the video in VAL.
"""
create_profile
(
'mobile'
)
create_video
({
'edx_video_id'
:
self
.
TEST_EDX_VIDEO_ID
,
'client_video_id'
:
'test_client_video_id'
,
'duration'
:
self
.
TEST_DURATION
,
'status'
:
'dummy'
,
'encoded_videos'
:
[
self
.
TEST_ENCODED_VIDEO
],
'courses'
:
[
self
.
video
.
location
.
course_key
]
if
associate_course_in_val
else
[],
})
self
.
val_video
=
get_video_info
(
self
.
TEST_EDX_VIDEO_ID
)
# pylint: disable=attribute-defined-outside-init
def
get_result
(
self
,
allow_cache_miss
=
True
):
"""
Returns the result from calling the video's student_view_json method.
Arguments:
allow_cache_miss is passed in the context to the student_view_json method.
"""
context
=
{
"profiles"
:
[
self
.
TEST_PROFILE
],
"allow_cache_miss"
:
"True"
if
allow_cache_miss
else
"False"
}
return
self
.
video
.
student_view_json
(
context
)
def
verify_result_with_fallback_url
(
self
,
result
):
"""
Verifies the result is as expected when returning "fallback" video data (not from VAL).
"""
self
.
assertDictEqual
(
result
,
{
"only_on_web"
:
False
,
"duration"
:
None
,
"transcripts"
:
{
self
.
TEST_LANGUAGE
:
self
.
transcript_url
},
"encoded_videos"
:
{
"fallback"
:
{
"url"
:
self
.
TEST_SOURCE_URL
,
"file_size"
:
0
}},
}
)
def
verify_result_with_val_profile
(
self
,
result
):
"""
Verifies the result is as expected when returning video data from VAL.
"""
self
.
assertDictContainsSubset
(
result
.
pop
(
"encoded_videos"
)[
self
.
TEST_PROFILE
],
self
.
TEST_ENCODED_VIDEO
,
)
self
.
assertDictEqual
(
result
,
{
"only_on_web"
:
False
,
"duration"
:
self
.
TEST_DURATION
,
"transcripts"
:
{
self
.
TEST_LANGUAGE
:
self
.
transcript_url
},
}
)
def
test_only_on_web
(
self
):
self
.
video
.
only_on_web
=
True
result
=
self
.
get_result
()
self
.
assertDictEqual
(
result
,
{
"only_on_web"
:
True
})
def
test_no_edx_video_id
(
self
):
result
=
self
.
get_result
()
self
.
verify_result_with_fallback_url
(
result
)
@ddt.data
(
*
itertools
.
product
([
True
,
False
],
[
True
,
False
],
[
True
,
False
])
)
@ddt.unpack
def
test_with_edx_video_id
(
self
,
allow_cache_miss
,
video_exists_in_val
,
associate_course_in_val
):
self
.
video
.
edx_video_id
=
self
.
TEST_EDX_VIDEO_ID
if
video_exists_in_val
:
self
.
setup_val_video
(
associate_course_in_val
)
result
=
self
.
get_result
(
allow_cache_miss
)
if
video_exists_in_val
and
(
associate_course_in_val
or
allow_cache_miss
):
self
.
verify_result_with_val_profile
(
result
)
else
:
self
.
verify_result_with_fallback_url
(
result
)
@attr
(
'shard_1'
)
class
VideoDescriptorTest
(
TestCase
,
VideoDescriptorTestBase
):
"""
...
...
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