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
44235108
Commit
44235108
authored
Mar 26, 2015
by
Christopher Lee
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #7480 from edx/clee/MA-169_MA-77
Clee/ma 169 ma 77
parents
c2dcbd70
e8dfac09
Hide whitespace changes
Inline
Side-by-side
Showing
13 changed files
with
334 additions
and
17 deletions
+334
-17
cms/djangoapps/contentstore/tasks.py
+6
-0
cms/djangoapps/contentstore/tests/test_contentstore.py
+28
-0
cms/djangoapps/contentstore/views/tests/test_videos.py
+1
-0
cms/djangoapps/contentstore/views/videos.py
+1
-0
lms/djangoapps/mobile_api/admin.py
+9
-0
lms/djangoapps/mobile_api/migrations/0001_initial.py
+78
-0
lms/djangoapps/mobile_api/migrations/__init__.py
+0
-0
lms/djangoapps/mobile_api/models.py
+25
-1
lms/djangoapps/mobile_api/tests.py
+32
-0
lms/djangoapps/mobile_api/video_outlines/serializers.py
+23
-12
lms/djangoapps/mobile_api/video_outlines/tests.py
+126
-2
lms/djangoapps/mobile_api/video_outlines/views.py
+4
-1
requirements/edx/github.txt
+1
-1
No files found.
cms/djangoapps/contentstore/tasks.py
View file @
44235108
...
...
@@ -14,6 +14,8 @@ from course_action_state.models import CourseRerunState
from
contentstore.utils
import
initialize_permissions
from
opaque_keys.edx.keys
import
CourseKey
from
edxval.api
import
copy_course_videos
@task
()
def
rerun_course
(
source_course_key_string
,
destination_course_key_string
,
user_id
,
fields
=
None
):
...
...
@@ -37,6 +39,10 @@ def rerun_course(source_course_key_string, destination_course_key_string, user_i
# update state: Succeeded
CourseRerunState
.
objects
.
succeeded
(
course_key
=
destination_course_key
)
# call edxval to attach videos to the rerun
copy_course_videos
(
source_course_key
,
destination_course_key
)
return
"succeeded"
except
DuplicateCourseError
as
exc
:
...
...
cms/djangoapps/contentstore/tests/test_contentstore.py
View file @
44235108
...
...
@@ -25,6 +25,8 @@ from openedx.core.lib.tempdir import mkdtemp_clean
from
contentstore.tests.utils
import
parse_json
,
AjaxEnabledTestClient
,
CourseTestCase
from
contentstore.views.component
import
ADVANCED_COMPONENT_TYPES
from
edxval.api
import
create_video
,
get_videos_for_course
from
xmodule.contentstore.django
import
contentstore
from
xmodule.contentstore.utils
import
restore_asset_from_trashcan
,
empty_asset_trashcan
from
xmodule.exceptions
import
InvalidVersionError
...
...
@@ -1712,11 +1714,37 @@ class RerunCourseTest(ContentStoreTestCase):
self
.
assertInCourseListing
(
source_course_key
)
self
.
assertInCourseListing
(
destination_course_key
)
def
test_rerun_course_no_videos_in_val
(
self
):
"""
Test when rerunning a course with no videos, VAL copies nothing
"""
source_course
=
CourseFactory
.
create
()
destination_course_key
=
self
.
post_rerun_request
(
source_course
.
id
)
self
.
verify_rerun_course
(
source_course
.
id
,
destination_course_key
,
self
.
destination_course_data
[
'display_name'
])
videos
=
list
(
get_videos_for_course
(
destination_course_key
))
self
.
assertEqual
(
0
,
len
(
videos
))
self
.
assertInCourseListing
(
destination_course_key
)
def
test_rerun_course_success
(
self
):
source_course
=
CourseFactory
.
create
()
create_video
(
dict
(
edx_video_id
=
"tree-hugger"
,
courses
=
[
source_course
.
id
],
status
=
'test'
,
duration
=
2
,
encoded_videos
=
[]
)
)
destination_course_key
=
self
.
post_rerun_request
(
source_course
.
id
)
self
.
verify_rerun_course
(
source_course
.
id
,
destination_course_key
,
self
.
destination_course_data
[
'display_name'
])
# Verify that the VAL copies videos to the rerun
source_videos
=
list
(
get_videos_for_course
(
source_course
.
id
))
target_videos
=
list
(
get_videos_for_course
(
destination_course_key
))
self
.
assertEqual
(
1
,
len
(
source_videos
))
self
.
assertEqual
(
source_videos
,
target_videos
)
def
test_rerun_of_rerun
(
self
):
source_course
=
CourseFactory
.
create
()
rerun_course_key
=
self
.
post_rerun_request
(
source_course
.
id
)
...
...
cms/djangoapps/contentstore/views/tests/test_videos.py
View file @
44235108
...
...
@@ -315,6 +315,7 @@ class VideosHandlerTestCase(VideoUploadTestMixin, CourseTestCase):
self
.
assertEqual
(
val_info
[
"client_video_id"
],
file_info
[
"file_name"
])
self
.
assertEqual
(
val_info
[
"status"
],
"upload"
)
self
.
assertEqual
(
val_info
[
"duration"
],
0
)
self
.
assertEqual
(
val_info
[
"courses"
],
[
unicode
(
self
.
course
.
id
)])
# Ensure response is correct
response_file
=
response_obj
[
"files"
][
i
]
...
...
cms/djangoapps/contentstore/views/videos.py
View file @
44235108
...
...
@@ -341,6 +341,7 @@ def videos_post(course, request):
"client_video_id"
:
file_name
,
"duration"
:
0
,
"encoded_videos"
:
[],
"courses"
:
[
course
.
id
]
})
resp_files
.
append
({
"file_name"
:
file_name
,
"upload_url"
:
upload_url
})
...
...
lms/djangoapps/mobile_api/admin.py
0 → 100644
View file @
44235108
"""
Django admin dashboard configuration for LMS XBlock infrastructure.
"""
from
django.contrib
import
admin
from
config_models.admin
import
ConfigurationModelAdmin
from
mobile_api.models
import
MobileApiConfig
admin
.
site
.
register
(
MobileApiConfig
,
ConfigurationModelAdmin
)
lms/djangoapps/mobile_api/migrations/0001_initial.py
0 → 100644
View file @
44235108
# -*- coding: utf-8 -*-
from
south.utils
import
datetime_utils
as
datetime
from
south.db
import
db
from
south.v2
import
SchemaMigration
from
django.db
import
models
class
Migration
(
SchemaMigration
):
def
forwards
(
self
,
orm
):
# Adding model 'MobileApiConfig'
db
.
create_table
(
'mobile_api_mobileapiconfig'
,
(
(
'id'
,
self
.
gf
(
'django.db.models.fields.AutoField'
)(
primary_key
=
True
)),
(
'change_date'
,
self
.
gf
(
'django.db.models.fields.DateTimeField'
)(
auto_now_add
=
True
,
blank
=
True
)),
(
'changed_by'
,
self
.
gf
(
'django.db.models.fields.related.ForeignKey'
)(
to
=
orm
[
'auth.User'
],
null
=
True
,
on_delete
=
models
.
PROTECT
)),
(
'enabled'
,
self
.
gf
(
'django.db.models.fields.BooleanField'
)(
default
=
False
)),
(
'video_profiles'
,
self
.
gf
(
'django.db.models.fields.TextField'
)(
blank
=
True
)),
))
db
.
send_create_signal
(
'mobile_api'
,
[
'MobileApiConfig'
])
if
not
db
.
dry_run
:
orm
.
MobileApiConfig
.
objects
.
create
(
video_profiles
=
"mobile_low,mobile_high,youtube"
,
)
def
backwards
(
self
,
orm
):
# Deleting model 'MobileApiConfig'
db
.
delete_table
(
'mobile_api_mobileapiconfig'
)
models
=
{
'auth.group'
:
{
'Meta'
:
{
'object_name'
:
'Group'
},
'id'
:
(
'django.db.models.fields.AutoField'
,
[],
{
'primary_key'
:
'True'
}),
'name'
:
(
'django.db.models.fields.CharField'
,
[],
{
'unique'
:
'True'
,
'max_length'
:
'80'
}),
'permissions'
:
(
'django.db.models.fields.related.ManyToManyField'
,
[],
{
'to'
:
"orm['auth.Permission']"
,
'symmetrical'
:
'False'
,
'blank'
:
'True'
})
},
'auth.permission'
:
{
'Meta'
:
{
'ordering'
:
"('content_type__app_label', 'content_type__model', 'codename')"
,
'unique_together'
:
"(('content_type', 'codename'),)"
,
'object_name'
:
'Permission'
},
'codename'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'100'
}),
'content_type'
:
(
'django.db.models.fields.related.ForeignKey'
,
[],
{
'to'
:
"orm['contenttypes.ContentType']"
}),
'id'
:
(
'django.db.models.fields.AutoField'
,
[],
{
'primary_key'
:
'True'
}),
'name'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'50'
})
},
'auth.user'
:
{
'Meta'
:
{
'object_name'
:
'User'
},
'date_joined'
:
(
'django.db.models.fields.DateTimeField'
,
[],
{
'default'
:
'datetime.datetime.now'
}),
'email'
:
(
'django.db.models.fields.EmailField'
,
[],
{
'max_length'
:
'75'
,
'blank'
:
'True'
}),
'first_name'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'30'
,
'blank'
:
'True'
}),
'groups'
:
(
'django.db.models.fields.related.ManyToManyField'
,
[],
{
'to'
:
"orm['auth.Group']"
,
'symmetrical'
:
'False'
,
'blank'
:
'True'
}),
'id'
:
(
'django.db.models.fields.AutoField'
,
[],
{
'primary_key'
:
'True'
}),
'is_active'
:
(
'django.db.models.fields.BooleanField'
,
[],
{
'default'
:
'True'
}),
'is_staff'
:
(
'django.db.models.fields.BooleanField'
,
[],
{
'default'
:
'False'
}),
'is_superuser'
:
(
'django.db.models.fields.BooleanField'
,
[],
{
'default'
:
'False'
}),
'last_login'
:
(
'django.db.models.fields.DateTimeField'
,
[],
{
'default'
:
'datetime.datetime.now'
}),
'last_name'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'30'
,
'blank'
:
'True'
}),
'password'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'128'
}),
'user_permissions'
:
(
'django.db.models.fields.related.ManyToManyField'
,
[],
{
'to'
:
"orm['auth.Permission']"
,
'symmetrical'
:
'False'
,
'blank'
:
'True'
}),
'username'
:
(
'django.db.models.fields.CharField'
,
[],
{
'unique'
:
'True'
,
'max_length'
:
'30'
})
},
'contenttypes.contenttype'
:
{
'Meta'
:
{
'ordering'
:
"('name',)"
,
'unique_together'
:
"(('app_label', 'model'),)"
,
'object_name'
:
'ContentType'
,
'db_table'
:
"'django_content_type'"
},
'app_label'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'100'
}),
'id'
:
(
'django.db.models.fields.AutoField'
,
[],
{
'primary_key'
:
'True'
}),
'model'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'100'
}),
'name'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'100'
})
},
'mobile_api.mobileapiconfig'
:
{
'Meta'
:
{
'object_name'
:
'MobileApiConfig'
},
'change_date'
:
(
'django.db.models.fields.DateTimeField'
,
[],
{
'auto_now_add'
:
'True'
,
'blank'
:
'True'
}),
'changed_by'
:
(
'django.db.models.fields.related.ForeignKey'
,
[],
{
'to'
:
"orm['auth.User']"
,
'null'
:
'True'
,
'on_delete'
:
'models.PROTECT'
}),
'enabled'
:
(
'django.db.models.fields.BooleanField'
,
[],
{
'default'
:
'False'
}),
'id'
:
(
'django.db.models.fields.AutoField'
,
[],
{
'primary_key'
:
'True'
}),
'video_profiles'
:
(
'django.db.models.fields.TextField'
,
[],
{
'blank'
:
'True'
})
}
}
complete_apps
=
[
'mobile_api'
]
lms/djangoapps/mobile_api/migrations/__init__.py
0 → 100644
View file @
44235108
lms/djangoapps/mobile_api/models.py
View file @
44235108
"""
A models.py is required to make this an app (until we move to Django 1.7)
ConfigurationModel for the mobile_api djangoapp.
"""
from
django.db.models.fields
import
TextField
from
config_models.models
import
ConfigurationModel
class
MobileApiConfig
(
ConfigurationModel
):
"""
Configuration for the video upload feature.
The order in which the comma-separated list of names of profiles are given
is in priority order.
"""
video_profiles
=
TextField
(
blank
=
True
,
help_text
=
"A comma-separated list of names of profiles to include for videos returned from the mobile API."
)
@classmethod
def
get_video_profiles
(
cls
):
"""
Get the list of profiles in priority order when requesting from VAL
"""
return
[
profile
.
strip
()
for
profile
in
cls
.
current
()
.
video_profiles
.
split
(
","
)
if
profile
]
# pylint: disable=no-member
lms/djangoapps/mobile_api/tests.py
View file @
44235108
# -*- coding: utf-8 -*-
"""
Tests for mobile API utilities.
"""
import
ddt
from
django.test
import
TestCase
from
mobile_api.models
import
MobileApiConfig
from
.utils
import
mobile_course_access
,
mobile_view
...
...
@@ -25,3 +27,33 @@ class TestMobileAPIDecorators(TestCase):
self
.
assertIn
(
"Test docstring of decorated function."
,
decorated_func
.
__doc__
)
self
.
assertEquals
(
decorated_func
.
__name__
,
"decorated_func"
)
self
.
assertTrue
(
decorated_func
.
__module__
.
endswith
(
"tests"
))
class
TestMobileApiConfig
(
TestCase
):
"""
Tests MobileAPIConfig
"""
def
test_video_profile_list
(
self
):
"""Check that video_profiles config is returned in order as a list"""
MobileApiConfig
(
video_profiles
=
"mobile_low,mobile_high,youtube"
)
.
save
()
video_profile_list
=
MobileApiConfig
.
get_video_profiles
()
self
.
assertEqual
(
video_profile_list
,
[
u'mobile_low'
,
u'mobile_high'
,
u'youtube'
]
)
def
test_video_profile_list_with_whitespace
(
self
):
"""Check video_profiles config with leading and trailing whitespace"""
MobileApiConfig
(
video_profiles
=
" mobile_low , mobile_high,youtube "
)
.
save
()
video_profile_list
=
MobileApiConfig
.
get_video_profiles
()
self
.
assertEqual
(
video_profile_list
,
[
u'mobile_low'
,
u'mobile_high'
,
u'youtube'
]
)
def
test_empty_video_profile
(
self
):
"""Test an empty video_profile"""
MobileApiConfig
(
video_profiles
=
""
)
.
save
()
video_profile_list
=
MobileApiConfig
.
get_video_profiles
()
self
.
assertEqual
(
video_profile_list
,
[])
lms/djangoapps/mobile_api/video_outlines/serializers.py
View file @
44235108
...
...
@@ -10,7 +10,7 @@ from courseware.module_render import get_module_for_descriptor
from
util.module_utils
import
get_dynamic_descriptor_children
from
edxval.api
import
(
get_video_info_for_course_and_profile
,
ValInternalError
get_video_info_for_course_and_profile
s
,
ValInternalError
)
...
...
@@ -18,7 +18,7 @@ class BlockOutline(object):
"""
Serializes course videos, pulling data from VAL and the video modules.
"""
def
__init__
(
self
,
course_id
,
start_block
,
block_types
,
request
):
def
__init__
(
self
,
course_id
,
start_block
,
block_types
,
request
,
video_profiles
):
"""Create a BlockOutline using `start_block` as a starting point."""
self
.
start_block
=
start_block
self
.
block_types
=
block_types
...
...
@@ -26,8 +26,8 @@ class BlockOutline(object):
self
.
request
=
request
# needed for making full URLS
self
.
local_cache
=
{}
try
:
self
.
local_cache
[
'course_videos'
]
=
get_video_info_for_course_and_profile
(
unicode
(
course_id
),
"mobile_low"
self
.
local_cache
[
'course_videos'
]
=
get_video_info_for_course_and_profile
s
(
unicode
(
course_id
),
video_profiles
)
except
ValInternalError
:
# pragma: nocover
self
.
local_cache
[
'course_videos'
]
=
{}
...
...
@@ -159,7 +159,7 @@ def find_urls(course_id, block, child_to_parent, request):
return
unit_url
,
section_url
def
video_summary
(
course
,
course_id
,
video_descriptor
,
request
,
local_cache
):
def
video_summary
(
video_profiles
,
course_id
,
video_descriptor
,
request
,
local_cache
):
"""
returns summary dict for the given video module
"""
...
...
@@ -182,19 +182,29 @@ def video_summary(course, course_id, video_descriptor, request, local_cache):
ret
.
update
(
always_available_data
)
return
ret
# First try to check VAL for the URLs we want.
val_video_info
=
local_cache
[
'course_videos'
]
.
get
(
video_descriptor
.
edx_video_id
,
{})
if
val_video_info
:
video_url
=
val_video_info
[
'url'
]
# Get encoded videos
video_data
=
local_cache
[
'course_videos'
]
.
get
(
video_descriptor
.
edx_video_id
,
{})
# Get highest priority video to populate backwards compatible field
default_encoded_video
=
{}
if
video_data
:
for
profile
in
video_profiles
:
default_encoded_video
=
video_data
[
'profiles'
]
.
get
(
profile
,
{})
if
default_encoded_video
:
break
if
default_encoded_video
:
video_url
=
default_encoded_video
[
'url'
]
# Then fall back to VideoDescriptor fields for video URLs
elif
video_descriptor
.
html5_sources
:
video_url
=
video_descriptor
.
html5_sources
[
0
]
else
:
video_url
=
video_descriptor
.
source
#
If we have the video information from VAL, we also have duration and size.
duration
=
v
al_video_info
.
get
(
'duration'
,
None
)
size
=
val_video_inf
o
.
get
(
'file_size'
,
0
)
#
Get duration/size, else default
duration
=
v
ideo_data
.
get
(
'duration'
,
None
)
size
=
default_encoded_vide
o
.
get
(
'file_size'
,
0
)
# Transcripts...
transcript_langs
=
video_descriptor
.
available_translations
(
verify_assets
=
False
)
...
...
@@ -219,6 +229,7 @@ def video_summary(course, course_id, video_descriptor, request, local_cache):
"size"
:
size
,
"transcripts"
:
transcripts
,
"language"
:
video_descriptor
.
get_default_transcript_language
(),
"encoded_videos"
:
video_data
.
get
(
'profiles'
)
}
ret
.
update
(
always_available_data
)
return
ret
lms/djangoapps/mobile_api/video_outlines/tests.py
View file @
44235108
...
...
@@ -9,6 +9,7 @@ from uuid import uuid4
from
collections
import
namedtuple
from
edxval
import
api
from
mobile_api.models
import
MobileApiConfig
from
xmodule.modulestore.tests.factories
import
ItemFactory
from
xmodule.video_module
import
transcripts_utils
from
xmodule.modulestore.django
import
modulestore
...
...
@@ -58,6 +59,8 @@ class TestVideoAPITestCase(MobileAPITestCase):
self
.
edx_video_id
=
'testing-123'
self
.
video_url
=
'http://val.edx.org/val/video.mp4'
self
.
video_url_high
=
'http://val.edx.org/val/video_high.mp4'
self
.
youtube_url
=
'http://val.edx.org/val/youtube.mp4'
self
.
html5_video_url
=
'http://video.edx.org/html5/video.mp4'
api
.
create_profile
({
...
...
@@ -67,6 +70,12 @@ class TestVideoAPITestCase(MobileAPITestCase):
'height'
:
720
})
api
.
create_profile
({
'profile_name'
:
'mobile_high'
,
'extension'
:
'mp4'
,
'width'
:
750
,
'height'
:
590
})
api
.
create_profile
({
'profile_name'
:
'mobile_low'
,
'extension'
:
'mp4'
,
'width'
:
640
,
...
...
@@ -92,9 +101,19 @@ class TestVideoAPITestCase(MobileAPITestCase):
'url'
:
self
.
video_url
,
'file_size'
:
12345
,
'bitrate'
:
250
}
},
{
'profile'
:
'mobile_high'
,
'url'
:
self
.
video_url_high
,
'file_size'
:
99999
,
'bitrate'
:
250
},
]})
# Set requested profiles
MobileApiConfig
(
video_profiles
=
"mobile_low,mobile_high,youtube"
)
.
save
()
class
TestVideoAPIMixin
(
object
):
"""
...
...
@@ -450,6 +469,112 @@ class TestVideoSummaryList(
self
.
assertEqual
(
course_outline
[
0
][
"summary"
][
"category"
],
"video"
)
self
.
assertTrue
(
course_outline
[
0
][
"summary"
][
"only_on_web"
])
def
test_mobile_api_config
(
self
):
"""
Tests VideoSummaryList with different MobileApiConfig video_profiles
"""
self
.
login_and_enroll
()
edx_video_id
=
"testing_mobile_high"
api
.
create_video
({
'edx_video_id'
:
edx_video_id
,
'status'
:
'test'
,
'client_video_id'
:
u"test video omega
\u03a9
"
,
'duration'
:
12
,
'courses'
:
[
unicode
(
self
.
course
.
id
)],
'encoded_videos'
:
[
{
'profile'
:
'youtube'
,
'url'
:
self
.
youtube_url
,
'file_size'
:
2222
,
'bitrate'
:
4444
},
{
'profile'
:
'mobile_high'
,
'url'
:
self
.
video_url_high
,
'file_size'
:
111
,
'bitrate'
:
333
},
]})
ItemFactory
.
create
(
parent
=
self
.
other_unit
,
category
=
"video"
,
display_name
=
u"testing mobile high video"
,
edx_video_id
=
edx_video_id
,
)
expected_output
=
{
'category'
:
u'video'
,
'video_thumbnail_url'
:
None
,
'language'
:
u'en'
,
'name'
:
u'testing mobile high video'
,
'video_url'
:
self
.
video_url_high
,
'duration'
:
12.0
,
'transcripts'
:
{
'en'
:
'http://testserver/api/mobile/v0.5/video_outlines/transcripts/{}/testing_mobile_high_video/en'
.
format
(
self
.
course
.
id
)
# pylint: disable=line-too-long
},
'only_on_web'
:
False
,
'encoded_videos'
:
{
u'mobile_high'
:
{
'url'
:
self
.
video_url_high
,
'file_size'
:
111
},
u'youtube'
:
{
'url'
:
self
.
youtube_url
,
'file_size'
:
2222
}
},
'size'
:
111
}
# Testing when video_profiles='mobile_low,mobile_high,youtube'
course_outline
=
self
.
api_response
()
.
data
course_outline
[
0
][
'summary'
]
.
pop
(
"id"
)
self
.
assertEqual
(
course_outline
[
0
][
'summary'
],
expected_output
)
# Testing when there is no mobile_low, and that mobile_high doesn't show
MobileApiConfig
(
video_profiles
=
"mobile_low,youtube"
)
.
save
()
course_outline
=
self
.
api_response
()
.
data
expected_output
[
'encoded_videos'
]
.
pop
(
'mobile_high'
)
expected_output
[
'video_url'
]
=
self
.
youtube_url
expected_output
[
'size'
]
=
2222
course_outline
[
0
][
'summary'
]
.
pop
(
"id"
)
self
.
assertEqual
(
course_outline
[
0
][
'summary'
],
expected_output
)
# Testing where youtube is the default video over mobile_high
MobileApiConfig
(
video_profiles
=
"youtube,mobile_high"
)
.
save
()
course_outline
=
self
.
api_response
()
.
data
expected_output
[
'encoded_videos'
][
'mobile_high'
]
=
{
'url'
:
self
.
video_url_high
,
'file_size'
:
111
}
course_outline
[
0
][
'summary'
]
.
pop
(
"id"
)
self
.
assertEqual
(
course_outline
[
0
][
'summary'
],
expected_output
)
def
test_video_not_in_val
(
self
):
self
.
login_and_enroll
()
self
.
_create_video_with_subs
()
ItemFactory
.
create
(
parent
=
self
.
other_unit
,
category
=
"video"
,
edx_video_id
=
"some_non_existent_id_in_val"
,
display_name
=
u"some non existent video in val"
,
html5_sources
=
[
self
.
html5_video_url
]
)
summary
=
self
.
api_response
()
.
data
[
1
][
'summary'
]
self
.
assertEqual
(
summary
[
'name'
],
"some non existent video in val"
)
self
.
assertIsNone
(
summary
[
'encoded_videos'
])
self
.
assertIsNone
(
summary
[
'duration'
])
self
.
assertEqual
(
summary
[
'size'
],
0
)
self
.
assertEqual
(
summary
[
'video_url'
],
self
.
html5_video_url
)
def
test_course_list
(
self
):
self
.
login_and_enroll
()
self
.
_create_video_with_subs
()
...
...
@@ -488,7 +613,6 @@ class TestVideoSummaryList(
self
.
assertFalse
(
course_outline
[
1
][
'summary'
][
'only_on_web'
])
self
.
assertEqual
(
course_outline
[
1
][
'path'
][
2
][
'name'
],
self
.
other_unit
.
display_name
)
self
.
assertEqual
(
course_outline
[
1
][
'path'
][
2
][
'id'
],
unicode
(
self
.
other_unit
.
location
))
self
.
assertEqual
(
course_outline
[
2
][
'summary'
][
'video_url'
],
self
.
html5_video_url
)
self
.
assertEqual
(
course_outline
[
2
][
'summary'
][
'size'
],
0
)
self
.
assertFalse
(
course_outline
[
2
][
'summary'
][
'only_on_web'
])
...
...
lms/djangoapps/mobile_api/video_outlines/views.py
View file @
44235108
...
...
@@ -9,6 +9,7 @@ general XBlock representation in this rather specialized formatting.
from
functools
import
partial
from
django.http
import
Http404
,
HttpResponse
from
mobile_api.models
import
MobileApiConfig
from
rest_framework
import
generics
from
rest_framework.response
import
Response
...
...
@@ -78,12 +79,14 @@ class VideoSummaryList(generics.ListAPIView):
@mobile_course_access
(
depth
=
None
)
def
list
(
self
,
request
,
course
,
*
args
,
**
kwargs
):
video_profiles
=
MobileApiConfig
.
get_video_profiles
()
video_outline
=
list
(
BlockOutline
(
course
.
id
,
course
,
{
"video"
:
partial
(
video_summary
,
course
)},
{
"video"
:
partial
(
video_summary
,
video_profiles
)},
request
,
video_profiles
,
)
)
return
Response
(
video_outline
)
...
...
requirements/edx/github.txt
View file @
44235108
...
...
@@ -35,7 +35,7 @@ git+https://github.com/mitocw/django-cas.git@60a5b8e5a62e63e0d5d224a87f0b489201a
-e git+https://github.com/edx/ease.git@97de68448e5495385ba043d3091f570a699d5b5f#egg=ease
-e git+https://github.com/edx/i18n-tools.git@193cebd9aa784f8899ef496f2aa050b08eff402b#egg=i18n-tools
-e git+https://github.com/edx/edx-oauth2-provider.git@0.4.2#egg=oauth2-provider
-e git+https://github.com/edx/edx-val.git@
fbec6efc86abb36f55de947baacc2092881dcde2
#egg=edx-val
-e git+https://github.com/edx/edx-val.git@
64aa7637e3459fb3000a85a9e156880a40307dd1
#egg=edx-val
-e git+https://github.com/pmitros/RecommenderXBlock.git@9b07e807c89ba5761827d0387177f71aa57ef056#egg=recommender-xblock
-e git+https://github.com/edx/edx-milestones.git@547f2250ee49e73ce8d7ff4e78ecf1b049892510#egg=edx-milestones
-e git+https://github.com/edx/edx-search.git@21ac6b06b3bfe789dcaeaf4e2ab5b00a688324d4#egg=edx-search
...
...
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