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
55621365
Commit
55621365
authored
Jun 30, 2017
by
Qubad786
Committed by
Mushtaq Ali
Jul 06, 2017
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add waffle switch to toggle video thumbnail feature.
parent
eabfba48
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
89 additions
and
21 deletions
+89
-21
cms/djangoapps/contentstore/views/tests/test_videos.py
+35
-4
cms/djangoapps/contentstore/views/videos.py
+13
-3
cms/static/js/spec/views/video_thumbnail_spec.js
+17
-6
cms/static/js/views/previous_video_upload.js
+15
-7
cms/static/js/views/previous_video_upload_list.js
+5
-1
cms/templates/js/previous-video-upload-list.underscore
+2
-0
cms/templates/js/previous-video-upload.underscore
+2
-0
No files found.
cms/djangoapps/contentstore/views/tests/test_videos.py
View file @
55621365
...
@@ -6,6 +6,7 @@ import csv
...
@@ -6,6 +6,7 @@ import csv
import
json
import
json
import
re
import
re
from
datetime
import
datetime
from
datetime
import
datetime
from
functools
import
wraps
from
StringIO
import
StringIO
from
StringIO
import
StringIO
import
dateutil.parser
import
dateutil.parser
...
@@ -21,11 +22,10 @@ from contentstore.models import VideoUploadConfig
...
@@ -21,11 +22,10 @@ from contentstore.models import VideoUploadConfig
from
contentstore.tests.utils
import
CourseTestCase
from
contentstore.tests.utils
import
CourseTestCase
from
contentstore.utils
import
reverse_course_url
from
contentstore.utils
import
reverse_course_url
from
contentstore.views.videos
import
(
from
contentstore.views.videos
import
(
KEY_EXPIRATION_IN_SECONDS
,
StatusDisplayStrings
,
convert_video_status
,
_get_default_video_image_url
,
_get_default_video_image_url
,
validate_video_image
validate_video_image
,
VIDEO_IMAGE_UPLOAD_ENABLED
,
WAFFLE_SWITCHES
,
)
)
from
contentstore.views.videos
import
KEY_EXPIRATION_IN_SECONDS
,
StatusDisplayStrings
,
convert_video_status
from
contentstore.views.videos
import
KEY_EXPIRATION_IN_SECONDS
,
StatusDisplayStrings
,
convert_video_status
from
xmodule.modulestore.tests.factories
import
CourseFactory
from
xmodule.modulestore.tests.factories
import
CourseFactory
...
@@ -33,6 +33,24 @@ from xmodule.modulestore.tests.factories import CourseFactory
...
@@ -33,6 +33,24 @@ from xmodule.modulestore.tests.factories import CourseFactory
from
openedx.core.djangoapps.profile_images.tests.helpers
import
make_image_file
from
openedx.core.djangoapps.profile_images.tests.helpers
import
make_image_file
def
override_switch
(
switch
,
active
):
"""
Overrides the given waffle switch to `active` boolean.
Arguments:
switch(str): switch name
active(bool): A boolean representing (to be overridden) value
"""
def
decorate
(
function
):
@wraps
(
function
)
def
inner
(
*
args
,
**
kwargs
):
with
WAFFLE_SWITCHES
.
override
(
switch
,
active
=
active
):
function
(
*
args
,
**
kwargs
)
return
inner
return
decorate
class
VideoUploadTestBase
(
object
):
class
VideoUploadTestBase
(
object
):
"""
"""
Test cases for the video upload feature
Test cases for the video upload feature
...
@@ -576,6 +594,16 @@ class VideoImageTestCase(VideoUploadTestBase, CourseTestCase):
...
@@ -576,6 +594,16 @@ class VideoImageTestCase(VideoUploadTestBase, CourseTestCase):
self
.
assertIn
(
'error'
,
response
)
self
.
assertIn
(
'error'
,
response
)
self
.
assertEqual
(
response
[
'error'
],
error_message
)
self
.
assertEqual
(
response
[
'error'
],
error_message
)
@override_switch
(
VIDEO_IMAGE_UPLOAD_ENABLED
,
False
)
def
test_video_image_upload_disabled
(
self
):
"""
Tests the video image upload when the feature is disabled.
"""
video_image_upload_url
=
self
.
get_url_for_course_key
(
self
.
course
.
id
,
{
'edx_video_id'
:
'test_vid_id'
})
response
=
self
.
client
.
post
(
video_image_upload_url
,
{
'file'
:
'dummy_file'
},
format
=
'multipart'
)
self
.
assertEqual
(
response
.
status_code
,
404
)
@override_switch
(
VIDEO_IMAGE_UPLOAD_ENABLED
,
True
)
def
test_video_image
(
self
):
def
test_video_image
(
self
):
"""
"""
Test video image is saved.
Test video image is saved.
...
@@ -597,6 +625,7 @@ class VideoImageTestCase(VideoUploadTestBase, CourseTestCase):
...
@@ -597,6 +625,7 @@ class VideoImageTestCase(VideoUploadTestBase, CourseTestCase):
self
.
assertNotEqual
(
image_url1
,
image_url2
)
self
.
assertNotEqual
(
image_url1
,
image_url2
)
@override_switch
(
VIDEO_IMAGE_UPLOAD_ENABLED
,
True
)
def
test_video_image_no_file
(
self
):
def
test_video_image_no_file
(
self
):
"""
"""
Test that an error error message is returned if upload request is incorrect.
Test that an error error message is returned if upload request is incorrect.
...
@@ -625,6 +654,7 @@ class VideoImageTestCase(VideoUploadTestBase, CourseTestCase):
...
@@ -625,6 +654,7 @@ class VideoImageTestCase(VideoUploadTestBase, CourseTestCase):
error
=
validate_video_image
(
image_file
)
error
=
validate_video_image
(
image_file
)
self
.
assertEquals
(
error
,
'This image file is corrupted.'
)
self
.
assertEquals
(
error
,
'This image file is corrupted.'
)
@override_switch
(
VIDEO_IMAGE_UPLOAD_ENABLED
,
True
)
def
test_no_video_image
(
self
):
def
test_no_video_image
(
self
):
"""
"""
Test image url is set to None if no video image.
Test image url is set to None if no video image.
...
@@ -800,6 +830,7 @@ class VideoImageTestCase(VideoUploadTestBase, CourseTestCase):
...
@@ -800,6 +830,7 @@ class VideoImageTestCase(VideoUploadTestBase, CourseTestCase):
)
)
)
)
@ddt.unpack
@ddt.unpack
@override_switch
(
VIDEO_IMAGE_UPLOAD_ENABLED
,
True
)
def
test_video_image_validation_message
(
self
,
image_data
,
error_message
):
def
test_video_image_validation_message
(
self
,
image_data
,
error_message
):
"""
"""
Test video image validation gives proper error message.
Test video image validation gives proper error message.
...
...
cms/djangoapps/contentstore/views/videos.py
View file @
55621365
...
@@ -2,10 +2,7 @@
...
@@ -2,10 +2,7 @@
Views related to the video upload feature
Views related to the video upload feature
"""
"""
from
contextlib
import
closing
from
contextlib
import
closing
from
datetime
import
datetime
,
timedelta
import
logging
from
boto
import
s3
import
csv
import
csv
import
logging
import
logging
from
datetime
import
datetime
,
timedelta
from
datetime
import
datetime
,
timedelta
...
@@ -31,6 +28,7 @@ from edxval.api import (
...
@@ -31,6 +28,7 @@ from edxval.api import (
update_video_image
update_video_image
)
)
from
opaque_keys.edx.keys
import
CourseKey
from
opaque_keys.edx.keys
import
CourseKey
from
openedx.core.djangoapps.waffle_utils
import
WaffleSwitchNamespace
from
contentstore.models
import
VideoUploadConfig
from
contentstore.models
import
VideoUploadConfig
from
contentstore.utils
import
reverse_course_url
from
contentstore.utils
import
reverse_course_url
...
@@ -44,6 +42,12 @@ __all__ = ['videos_handler', 'video_encodings_download', 'video_images_handler']
...
@@ -44,6 +42,12 @@ __all__ = ['videos_handler', 'video_encodings_download', 'video_images_handler']
LOGGER
=
logging
.
getLogger
(
__name__
)
LOGGER
=
logging
.
getLogger
(
__name__
)
# Waffle switches namespace for videos
WAFFLE_NAMESPACE
=
'videos'
WAFFLE_SWITCHES
=
WaffleSwitchNamespace
(
name
=
WAFFLE_NAMESPACE
)
# Waffle switch for enabling/disabling video image upload feature
VIDEO_IMAGE_UPLOAD_ENABLED
=
'video_image_upload_enabled'
# Default expiration, in seconds, of one-time URLs used for uploading videos.
# Default expiration, in seconds, of one-time URLs used for uploading videos.
KEY_EXPIRATION_IN_SECONDS
=
86400
KEY_EXPIRATION_IN_SECONDS
=
86400
...
@@ -210,6 +214,11 @@ def validate_video_image(image_file):
...
@@ -210,6 +214,11 @@ def validate_video_image(image_file):
@login_required
@login_required
@require_POST
@require_POST
def
video_images_handler
(
request
,
course_key_string
,
edx_video_id
=
None
):
def
video_images_handler
(
request
,
course_key_string
,
edx_video_id
=
None
):
# respond with a 404 if image upload is not enabled.
if
not
WAFFLE_SWITCHES
.
is_enabled
(
VIDEO_IMAGE_UPLOAD_ENABLED
):
return
HttpResponseNotFound
()
if
'file'
not
in
request
.
FILES
:
if
'file'
not
in
request
.
FILES
:
return
JsonResponse
({
'error'
:
_
(
u'No file provided for video image'
)},
status
=
400
)
return
JsonResponse
({
'error'
:
_
(
u'No file provided for video image'
)},
status
=
400
)
...
@@ -428,6 +437,7 @@ def videos_index_html(course):
...
@@ -428,6 +437,7 @@ def videos_index_html(course):
'video_supported_file_formats'
:
VIDEO_SUPPORTED_FILE_FORMATS
.
keys
(),
'video_supported_file_formats'
:
VIDEO_SUPPORTED_FILE_FORMATS
.
keys
(),
'video_upload_max_file_size'
:
VIDEO_UPLOAD_MAX_FILE_SIZE_GB
,
'video_upload_max_file_size'
:
VIDEO_UPLOAD_MAX_FILE_SIZE_GB
,
'video_image_settings'
:
{
'video_image_settings'
:
{
'video_image_upload_enabled'
:
WAFFLE_SWITCHES
.
is_enabled
(
VIDEO_IMAGE_UPLOAD_ENABLED
),
'max_size'
:
settings
.
VIDEO_IMAGE_SETTINGS
[
'VIDEO_IMAGE_MAX_BYTES'
],
'max_size'
:
settings
.
VIDEO_IMAGE_SETTINGS
[
'VIDEO_IMAGE_MAX_BYTES'
],
'min_size'
:
settings
.
VIDEO_IMAGE_SETTINGS
[
'VIDEO_IMAGE_MIN_BYTES'
],
'min_size'
:
settings
.
VIDEO_IMAGE_SETTINGS
[
'VIDEO_IMAGE_MIN_BYTES'
],
'max_width'
:
settings
.
VIDEO_IMAGE_MAX_WIDTH
,
'max_width'
:
settings
.
VIDEO_IMAGE_MAX_WIDTH
,
...
...
cms/static/js/spec/views/video_thumbnail_spec.js
View file @
55621365
...
@@ -29,11 +29,12 @@ define(
...
@@ -29,11 +29,12 @@ define(
/**
/**
* Creates a list of video records.
* Creates a list of video records.
*
*
* @param {Boolean} videoImageUploadEnabled Boolean indicating if the feature is enabled.
* @param {Object} modelData Model data for video records.
* @param {Object} modelData Model data for video records.
* @param {Integer} numVideos Number of video elements to create.
* @param {Integer} numVideos Number of video elements to create.
* @param {Integer} videoViewIndex Index of video on which videoThumbnailView would be based.
* @param {Integer} videoViewIndex Index of video on which videoThumbnailView would be based.
*/
*/
createVideoListView
=
function
(
modelData
,
numVideos
,
videoViewIndex
)
{
createVideoListView
=
function
(
videoImageUploadEnabled
,
modelData
,
numVideos
,
videoViewIndex
)
{
var
modelData
=
modelData
||
{},
// eslint-disable-line no-redeclare
var
modelData
=
modelData
||
{},
// eslint-disable-line no-redeclare
numVideos
=
numVideos
||
1
,
// eslint-disable-line no-redeclare
numVideos
=
numVideos
||
1
,
// eslint-disable-line no-redeclare
videoViewIndex
=
videoViewIndex
||
0
,
// eslint-disable-line no-redeclare,
videoViewIndex
=
videoViewIndex
||
0
,
// eslint-disable-line no-redeclare,
...
@@ -58,12 +59,17 @@ define(
...
@@ -58,12 +59,17 @@ define(
min_size
:
VIDEO_IMAGE_MIN_BYTES
,
min_size
:
VIDEO_IMAGE_MIN_BYTES
,
max_width
:
VIDEO_IMAGE_MAX_WIDTH
,
max_width
:
VIDEO_IMAGE_MAX_WIDTH
,
max_height
:
VIDEO_IMAGE_MAX_HEIGHT
,
max_height
:
VIDEO_IMAGE_MAX_HEIGHT
,
supported_file_formats
:
VIDEO_IMAGE_SUPPORTED_FILE_FORMATS
supported_file_formats
:
VIDEO_IMAGE_SUPPORTED_FILE_FORMATS
,
video_image_upload_enabled
:
videoImageUploadEnabled
}
}
});
});
$videoListEl
=
videoListView
.
render
().
$el
;
$videoListEl
=
videoListView
.
render
().
$el
;
videoThumbnailView
=
videoListView
.
itemViews
[
videoViewIndex
].
videoThumbnailView
;
$videoThumbnailEl
=
videoThumbnailView
.
render
().
$el
;
if
(
videoImageUploadEnabled
)
{
videoThumbnailView
=
videoListView
.
itemViews
[
videoViewIndex
].
videoThumbnailView
;
$videoThumbnailEl
=
videoThumbnailView
.
render
().
$el
;
}
return
videoListView
;
return
videoListView
;
};
};
...
@@ -113,7 +119,12 @@ define(
...
@@ -113,7 +119,12 @@ define(
setFixtures
(
'<div id="page-prompt"></div><div id="page-notification"></div>'
);
setFixtures
(
'<div id="page-prompt"></div><div id="page-notification"></div>'
);
TemplateHelpers
.
installTemplate
(
'video-thumbnail'
);
TemplateHelpers
.
installTemplate
(
'video-thumbnail'
);
TemplateHelpers
.
installTemplate
(
'previous-video-upload-list'
);
TemplateHelpers
.
installTemplate
(
'previous-video-upload-list'
);
createVideoListView
();
createVideoListView
(
true
);
});
it
(
'Verifies that the ThumbnailView is not initialized on disabling the feature'
,
function
()
{
createVideoListView
(
false
);
expect
(
videoListView
.
itemViews
[
0
].
videoThumbnailView
).
toEqual
(
undefined
);
});
});
it
(
'renders as expected'
,
function
()
{
it
(
'renders as expected'
,
function
()
{
...
@@ -122,7 +133,7 @@ define(
...
@@ -122,7 +133,7 @@ define(
});
});
it
(
'does not show duration if not available'
,
function
()
{
it
(
'does not show duration if not available'
,
function
()
{
createVideoListView
({
duration
:
0
});
createVideoListView
(
true
,
{
duration
:
0
});
expect
(
$videoThumbnailEl
.
find
(
'.thumbnail-wrapper .video-duration'
)).
not
.
toExist
();
expect
(
$videoThumbnailEl
.
find
(
'.thumbnail-wrapper .video-duration'
)).
not
.
toExist
();
});
});
...
...
cms/static/js/views/previous_video_upload.js
View file @
55621365
...
@@ -19,16 +19,21 @@ define(
...
@@ -19,16 +19,21 @@ define(
initialize
:
function
(
options
)
{
initialize
:
function
(
options
)
{
this
.
template
=
HtmlUtils
.
template
(
previousVideoUploadTemplate
);
this
.
template
=
HtmlUtils
.
template
(
previousVideoUploadTemplate
);
this
.
videoHandlerUrl
=
options
.
videoHandlerUrl
;
this
.
videoHandlerUrl
=
options
.
videoHandlerUrl
;
this
.
videoThumbnailView
=
new
VideoThumbnailView
({
this
.
videoImageUploadEnabled
=
options
.
videoImageSettings
.
video_image_upload_enabled
;
model
:
this
.
model
,
imageUploadURL
:
options
.
videoImageUploadURL
,
if
(
this
.
videoImageUploadEnabled
)
{
defaultVideoImageURL
:
options
.
defaultVideoImageURL
,
this
.
videoThumbnailView
=
new
VideoThumbnailView
({
videoImageSettings
:
options
.
videoImageSettings
model
:
this
.
model
,
});
imageUploadURL
:
options
.
videoImageUploadURL
,
defaultVideoImageURL
:
options
.
defaultVideoImageURL
,
videoImageSettings
:
options
.
videoImageSettings
});
}
},
},
render
:
function
()
{
render
:
function
()
{
var
renderedAttributes
=
{
var
renderedAttributes
=
{
videoImageUploadEnabled
:
this
.
videoImageUploadEnabled
,
created
:
DateUtils
.
renderDate
(
this
.
model
.
get
(
'created'
)),
created
:
DateUtils
.
renderDate
(
this
.
model
.
get
(
'created'
)),
status
:
this
.
model
.
get
(
'status'
)
status
:
this
.
model
.
get
(
'status'
)
};
};
...
@@ -38,7 +43,10 @@ define(
...
@@ -38,7 +43,10 @@ define(
_
.
extend
({},
this
.
model
.
attributes
,
renderedAttributes
)
_
.
extend
({},
this
.
model
.
attributes
,
renderedAttributes
)
)
)
);
);
this
.
videoThumbnailView
.
setElement
(
this
.
$
(
'.thumbnail-col'
)).
render
();
if
(
this
.
videoImageUploadEnabled
)
{
this
.
videoThumbnailView
.
setElement
(
this
.
$
(
'.thumbnail-col'
)).
render
();
}
return
this
;
return
this
;
},
},
...
...
cms/static/js/views/previous_video_upload_list.js
View file @
55621365
...
@@ -9,6 +9,7 @@ define(
...
@@ -9,6 +9,7 @@ define(
initialize
:
function
(
options
)
{
initialize
:
function
(
options
)
{
this
.
template
=
this
.
loadTemplate
(
'previous-video-upload-list'
);
this
.
template
=
this
.
loadTemplate
(
'previous-video-upload-list'
);
this
.
encodingsDownloadUrl
=
options
.
encodingsDownloadUrl
;
this
.
encodingsDownloadUrl
=
options
.
encodingsDownloadUrl
;
this
.
videoImageUploadEnabled
=
options
.
videoImageSettings
.
video_image_upload_enabled
;
this
.
itemViews
=
this
.
collection
.
map
(
function
(
model
)
{
this
.
itemViews
=
this
.
collection
.
map
(
function
(
model
)
{
return
new
PreviousVideoUploadView
({
return
new
PreviousVideoUploadView
({
videoImageUploadURL
:
options
.
videoImageUploadURL
,
videoImageUploadURL
:
options
.
videoImageUploadURL
,
...
@@ -23,7 +24,10 @@ define(
...
@@ -23,7 +24,10 @@ define(
render
:
function
()
{
render
:
function
()
{
var
$el
=
this
.
$el
,
var
$el
=
this
.
$el
,
$tabBody
;
$tabBody
;
$el
.
html
(
this
.
template
({
encodingsDownloadUrl
:
this
.
encodingsDownloadUrl
}));
$el
.
html
(
this
.
template
({
encodingsDownloadUrl
:
this
.
encodingsDownloadUrl
,
videoImageUploadEnabled
:
this
.
videoImageUploadEnabled
}));
$tabBody
=
$el
.
find
(
'.js-table-body'
);
$tabBody
=
$el
.
find
(
'.js-table-body'
);
_
.
each
(
this
.
itemViews
,
function
(
view
)
{
_
.
each
(
this
.
itemViews
,
function
(
view
)
{
$tabBody
.
append
(
view
.
render
().
$el
);
$tabBody
.
append
(
view
.
render
().
$el
);
...
...
cms/templates/js/previous-video-upload-list.underscore
View file @
55621365
...
@@ -8,7 +8,9 @@
...
@@ -8,7 +8,9 @@
<div class="assets-table video-table">
<div class="assets-table video-table">
<div class="js-table-head">
<div class="js-table-head">
<div class="video-row">
<div class="video-row">
<% if (videoImageUploadEnabled) { %>
<div class="video-head-col video-col thumbnail-col"><%- gettext("Thumbnail") %></div>
<div class="video-head-col video-col thumbnail-col"><%- gettext("Thumbnail") %></div>
<% } %>
<div class="video-head-col video-col name-col"><%- gettext("Name") %></div>
<div class="video-head-col video-col name-col"><%- gettext("Name") %></div>
<div class="video-head-col video-col date-col"><%- gettext("Date Added") %></div>
<div class="video-head-col video-col date-col"><%- gettext("Date Added") %></div>
<div class="video-head-col video-col video-id-col"><%- gettext("Video ID") %></div>
<div class="video-head-col video-col video-id-col"><%- gettext("Video ID") %></div>
...
...
cms/templates/js/previous-video-upload.underscore
View file @
55621365
<div class="video-row-container">
<div class="video-row-container">
<% if (videoImageUploadEnabled) { %>
<div class="video-col thumbnail-col"></div>
<div class="video-col thumbnail-col"></div>
<% } %>
<div class="video-col name-col"><%- client_video_id %></div>
<div class="video-col name-col"><%- client_video_id %></div>
<div class="video-col date-col"><%- created %></div>
<div class="video-col date-col"><%- created %></div>
<div class="video-col video-id-col"><%- edx_video_id %></div>
<div class="video-col video-id-col"><%- edx_video_id %></div>
...
...
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