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
e8fee2e0
Commit
e8fee2e0
authored
May 19, 2017
by
Mushtaq Ali
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add backend video image validations - EDUCATOR-45
parent
626f2896
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
82 additions
and
6 deletions
+82
-6
cms/djangoapps/contentstore/views/tests/test_videos.py
+0
-0
cms/djangoapps/contentstore/views/videos.py
+55
-4
cms/envs/common.py
+17
-0
cms/envs/test.py
+2
-0
lms/envs/common.py
+2
-0
openedx/core/djangoapps/profile_images/tests/helpers.py
+6
-2
No files found.
cms/djangoapps/contentstore/views/tests/test_videos.py
View file @
e8fee2e0
This diff is collapsed.
Click to expand it.
cms/djangoapps/contentstore/views/videos.py
View file @
e8fee2e0
...
...
@@ -16,6 +16,7 @@ from boto import s3
from
django.conf
import
settings
from
django.contrib.auth.decorators
import
login_required
from
django.contrib.staticfiles.storage
import
staticfiles_storage
from
django.core.files.images
import
get_image_dimensions
from
django.http
import
HttpResponse
,
HttpResponseNotFound
from
django.utils.translation
import
ugettext
as
_
from
django.utils.translation
import
ugettext_noop
...
...
@@ -153,19 +154,69 @@ def videos_handler(request, course_key_string, edx_video_id=None):
return
videos_post
(
course
,
request
)
def
validate_video_image
(
image_file
):
"""
Validates video image file.
Arguments:
image_file: The selected image file.
Returns:
error (String or None): If there is error returns error message otherwise None.
"""
error
=
None
if
not
all
(
hasattr
(
image_file
,
attr
)
for
attr
in
[
'name'
,
'content_type'
,
'size'
]):
error
=
_
(
'The image must have name, content type, and size information.'
)
elif
image_file
.
content_type
not
in
settings
.
VIDEO_IMAGE_SUPPORTED_FILE_FORMATS
.
values
():
error
=
_
(
'This image file type is not supported. Supported file types are {supported_file_formats}.'
)
.
format
(
supported_file_formats
=
settings
.
VIDEO_IMAGE_SUPPORTED_FILE_FORMATS
.
keys
()
)
elif
image_file
.
size
>
settings
.
VIDEO_IMAGE_SETTINGS
[
'VIDEO_IMAGE_MAX_BYTES'
]:
error
=
_
(
'This image file must be smaller than {image_max_size}.'
)
.
format
(
image_max_size
=
settings
.
VIDEO_IMAGE_MAX_FILE_SIZE_MB
)
elif
image_file
.
size
<
settings
.
VIDEO_IMAGE_SETTINGS
[
'VIDEO_IMAGE_MIN_BYTES'
]:
error
=
_
(
'This image file must be larger than {image_min_size}.'
)
.
format
(
image_min_size
=
settings
.
VIDEO_IMAGE_MIN_FILE_SIZE_KB
)
else
:
try
:
image_file_width
,
image_file_height
=
get_image_dimensions
(
image_file
)
except
TypeError
:
return
_
(
'This image file is corrupted.'
)
image_file_aspect_ratio
=
abs
(
image_file_width
/
float
(
image_file_height
)
-
settings
.
VIDEO_IMAGE_ASPECT_RATIO
)
if
image_file_aspect_ratio
>
settings
.
VIDEO_IMAGE_ASPECT_RATIO_ERROR_MARGIN
:
error
=
_
(
'This image file must have an aspect ratio of {video_image_aspect_ratio_text}.'
)
.
format
(
video_image_aspect_ratio_text
=
settings
.
VIDEO_IMAGE_ASPECT_RATIO_TEXT
)
elif
image_file_width
<
settings
.
VIDEO_IMAGE_MIN_WIDTH
or
image_file_height
<
settings
.
VIDEO_IMAGE_MIN_HEIGHT
:
error
=
_
(
'The minimum allowed image resolution is {image_file_min_width}x{image_file_min_height}.'
)
.
format
(
image_file_min_width
=
settings
.
VIDEO_IMAGE_MIN_WIDTH
,
image_file_min_height
=
settings
.
VIDEO_IMAGE_MIN_HEIGHT
)
else
:
try
:
image_file
.
name
.
encode
(
'ascii'
)
except
UnicodeEncodeError
:
error
=
_
(
'The image file name can only contain letters, numbers, hyphens (-), and underscores (_).'
)
return
error
@expect_json
@login_required
@require_POST
def
video_images_handler
(
request
,
course_key_string
,
edx_video_id
=
None
):
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
)
image_file
=
request
.
FILES
[
'file'
]
file_name
=
request
.
FILES
[
'file'
]
.
name
error
=
validate_video_image
(
image_file
)
if
error
:
return
JsonResponse
({
'error'
:
error
},
status
=
400
)
# TODO: Image file validation
with
closing
(
image_file
):
image_url
=
update_video_image
(
edx_video_id
,
course_key_string
,
image_file
,
file_
name
)
image_url
=
update_video_image
(
edx_video_id
,
course_key_string
,
image_file
,
image_file
.
name
)
LOGGER
.
info
(
'VIDEOS: Video image uploaded for edx_video_id [
%
s] in course [
%
s]'
,
edx_video_id
,
course_key_string
)
...
...
cms/envs/common.py
View file @
e8fee2e0
...
...
@@ -1350,3 +1350,20 @@ PROFILE_IMAGE_SIZES_MAP = {
###################### VIDEO IMAGE STORAGE ######################
VIDEO_IMAGE_DEFAULT_FILENAME
=
'images/video-images/default_video_image.png'
VIDEO_IMAGE_SUPPORTED_FILE_FORMATS
=
{
'.bmp'
:
'image/bmp'
,
'.bmp2'
:
'image/x-ms-bmp'
,
# PIL gives x-ms-bmp format
'.gif'
:
'image/gif'
,
'.jpg'
:
'image/jpeg'
,
'.jpeg'
:
'image/jpeg'
,
'.png'
:
'image/png'
}
VIDEO_IMAGE_MAX_FILE_SIZE_MB
=
'2 MB'
VIDEO_IMAGE_MIN_FILE_SIZE_KB
=
'2 KB'
VIDEO_IMAGE_MAX_WIDTH
=
1280
VIDEO_IMAGE_MAX_HEIGHT
=
720
VIDEO_IMAGE_MIN_WIDTH
=
640
VIDEO_IMAGE_MIN_HEIGHT
=
360
VIDEO_IMAGE_ASPECT_RATIO
=
16
/
9.0
VIDEO_IMAGE_ASPECT_RATIO_TEXT
=
'16:9'
VIDEO_IMAGE_ASPECT_RATIO_ERROR_MARGIN
=
0.1
cms/envs/test.py
View file @
e8fee2e0
...
...
@@ -338,6 +338,8 @@ INSTALLED_APPS += ('openedx.core.djangoapps.api_admin',)
########################## VIDEO IMAGE STORAGE ############################
VIDEO_IMAGE_SETTINGS
=
dict
(
VIDEO_IMAGE_MAX_BYTES
=
2
*
1024
*
1024
,
# 2 MB
VIDEO_IMAGE_MIN_BYTES
=
2
*
1024
,
# 2 KB
STORAGE_KWARGS
=
dict
(
location
=
MEDIA_ROOT
,
base_url
=
MEDIA_URL
,
...
...
lms/envs/common.py
View file @
e8fee2e0
...
...
@@ -2567,6 +2567,8 @@ TIME_ZONE_DISPLAYED_FOR_DEADLINES = 'UTC'
########################## VIDEO IMAGE STORAGE ############################
VIDEO_IMAGE_SETTINGS
=
dict
(
VIDEO_IMAGE_MAX_BYTES
=
2
*
1024
*
1024
,
# 2 MB
VIDEO_IMAGE_MIN_BYTES
=
2
*
1024
,
# 2 KB
# Backend storage
# STORAGE_CLASS='storages.backends.s3boto.S3BotoStorage',
# STORAGE_KWARGS=dict(bucket='video-image-bucket'),
...
...
openedx/core/djangoapps/profile_images/tests/helpers.py
View file @
e8fee2e0
...
...
@@ -11,7 +11,7 @@ from PIL import Image
@contextmanager
def
make_image_file
(
dimensions
=
(
320
,
240
),
extension
=
".jpeg"
,
force_size
=
None
,
orientation
=
None
):
def
make_image_file
(
dimensions
=
(
320
,
240
),
prefix
=
'tmp'
,
extension
=
'.jpeg'
,
force_size
=
None
,
orientation
=
None
):
"""
Yields a named temporary file created with the specified image type and
options.
...
...
@@ -21,9 +21,13 @@ def make_image_file(dimensions=(320, 240), extension=".jpeg", force_size=None, o
The temporary file will be closed and deleted automatically upon exiting
the `with` block.
prefix - To add prefix to random image file name, after adding will be like <custom-prefix><random-name>.png
otherwise by default `tmp` is added making file name tmp<random-name>.png.
"""
image
=
Image
.
new
(
'RGB'
,
dimensions
,
"green"
)
image_file
=
NamedTemporaryFile
(
suffix
=
extension
)
image_file
=
NamedTemporaryFile
(
prefix
=
prefix
,
suffix
=
extension
)
try
:
if
orientation
and
orientation
in
xrange
(
1
,
9
):
exif_bytes
=
piexif
.
dump
({
'0th'
:
{
piexif
.
ImageIFD
.
Orientation
:
orientation
}})
...
...
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