Files
edx-platform/cms/djangoapps/contentstore/views/videos.py

256 lines
8.2 KiB
Python

"""
Views related to the video upload feature
"""
import logging
from django.contrib.auth.decorators import login_required
from django.views.decorators.http import require_GET, require_http_methods, require_POST
from edx_toggles.toggles import WaffleSwitch
from rest_framework.decorators import api_view
from cms.djangoapps.contentstore.video_storage_handlers import (
handle_videos,
handle_generate_video_upload_link,
handle_video_images,
check_video_images_upload_enabled,
enabled_video_features,
handle_transcript_preferences,
get_video_encodings_download,
validate_transcript_preferences as validate_transcript_preferences_source_function,
convert_video_status as convert_video_status_source_function,
get_all_transcript_languages as get_all_transcript_languages_source_function,
videos_index_html as videos_index_html_source_function,
videos_index_json as videos_index_json_source_function,
videos_post as videos_post_source_function,
storage_service_bucket as storage_service_bucket_source_function,
storage_service_key as storage_service_key_source_function,
send_video_status_update as send_video_status_update_source_function,
is_status_update_request as is_status_update_request_source_function,
get_course_youtube_edx_video_ids,
)
from common.djangoapps.util.json_request import expect_json
from openedx.core.djangoapps.waffle_utils import CourseWaffleFlag
from openedx.core.lib.api.view_utils import view_auth_classes
__all__ = [
'videos_handler',
'video_encodings_download',
'video_images_handler',
'video_images_upload_enabled',
'get_video_features',
'transcript_preferences_handler',
'generate_video_upload_link_handler',
'get_course_youtube_edx_videos_ids',
]
LOGGER = logging.getLogger(__name__)
# Waffle switches namespace for videos
WAFFLE_NAMESPACE = 'videos'
# Waffle switch for enabling/disabling video image upload feature
VIDEO_IMAGE_UPLOAD_ENABLED = WaffleSwitch( # lint-amnesty, pylint: disable=toggle-missing-annotation
f'{WAFFLE_NAMESPACE}.video_image_upload_enabled', __name__
)
# Waffle flag namespace for studio
WAFFLE_STUDIO_FLAG_NAMESPACE = 'studio'
ENABLE_VIDEO_UPLOAD_PAGINATION = CourseWaffleFlag( # lint-amnesty, pylint: disable=toggle-missing-annotation
f'{WAFFLE_STUDIO_FLAG_NAMESPACE}.enable_video_upload_pagination', __name__
)
# Default expiration, in seconds, of one-time URLs used for uploading videos.
KEY_EXPIRATION_IN_SECONDS = 86400
VIDEO_SUPPORTED_FILE_FORMATS = {
'.mp4': 'video/mp4',
'.mov': 'video/quicktime',
}
VIDEO_UPLOAD_MAX_FILE_SIZE_GB = 5
# maximum time for video to remain in upload state
MAX_UPLOAD_HOURS = 24
VIDEOS_PER_PAGE = 100
@expect_json
@login_required
@require_http_methods(("GET", "POST", "DELETE"))
def videos_handler(request, course_key_string, edx_video_id=None):
"""
The restful handler for video uploads.
GET
html: return an HTML page to display previous video uploads and allow
new ones
json: return json representing the videos that have been uploaded and
their statuses
POST
json: create a new video upload; the actual files should not be provided
to this endpoint but rather PUT to the respective upload_url values
contained in the response. Example payload:
{
"files": [{
"file_name": "video.mp4",
"content_type": "video/mp4"
}]
}
DELETE
soft deletes a video for particular course
"""
return handle_videos(request, course_key_string, edx_video_id)
@api_view(['POST'])
@view_auth_classes()
@expect_json
def generate_video_upload_link_handler(request, course_key_string):
"""
API for creating a video upload. Returns an edx_video_id and a presigned URL that can be used
to upload the video to AWS S3.
"""
return handle_generate_video_upload_link(request, course_key_string)
@expect_json
@login_required
@require_POST
def video_images_handler(request, course_key_string, edx_video_id=None):
"""Function to handle image files"""
return handle_video_images(request, course_key_string, edx_video_id)
@login_required
@require_GET
def video_images_upload_enabled(request):
"""Function to check if images can be uploaded"""
return check_video_images_upload_enabled(request)
@login_required
@require_GET
def get_video_features(request):
""" Return a dict with info about which video features are enabled """
return enabled_video_features(request)
def validate_transcript_preferences(provider, cielo24_fidelity, cielo24_turnaround,
three_play_turnaround, video_source_language, preferred_languages):
"""
Exposes helper method without breaking existing bindings/dependencies
"""
return validate_transcript_preferences_source_function(provider, cielo24_fidelity, cielo24_turnaround,
three_play_turnaround, video_source_language,
preferred_languages)
@expect_json
@login_required
@require_http_methods(('POST', 'DELETE'))
def transcript_preferences_handler(request, course_key_string):
"""
JSON view handler to post the transcript preferences.
Arguments:
request: WSGI request object
course_key_string: string for course key
Returns: valid json response or 400 with error message
"""
return handle_transcript_preferences(request, course_key_string)
@login_required
@require_GET
def video_encodings_download(request, course_key_string):
"""
Returns a CSV report containing the encoded video URLs for video uploads
in the following format:
Video ID,Name,Status,Profile1 URL,Profile2 URL
aaaaaaaa-aaaa-4aaa-aaaa-aaaaaaaaaaaa,video.mp4,Complete,http://example.com/prof1.mp4,http://example.com/prof2.mp4
"""
return get_video_encodings_download(request, course_key_string)
def convert_video_status(video, is_video_encodes_ready=False):
"""
Exposes helper method without breaking existing bindings/dependencies
"""
return convert_video_status_source_function(video, is_video_encodes_ready)
def get_all_transcript_languages():
"""
Exposes helper method without breaking existing bindings/dependencies
"""
return get_all_transcript_languages_source_function()
def videos_index_html(course, pagination_conf=None):
"""
Exposes helper method without breaking existing bindings/dependencies
"""
return videos_index_html_source_function(course, pagination_conf)
def videos_index_json(course):
"""
Exposes helper method without breaking existing bindings/dependencies
"""
return videos_index_json_source_function(course)
def videos_post(course, request):
"""
Exposes helper method without breaking existing bindings/dependencies
"""
return videos_post_source_function(course, request)
def storage_service_bucket():
"""
Exposes helper method without breaking existing bindings/dependencies
"""
return storage_service_bucket_source_function()
def storage_service_key(bucket, file_name):
"""
Exposes helper method without breaking existing bindings/dependencies
"""
return storage_service_key_source_function(bucket, file_name)
def send_video_status_update(updates):
"""
Exposes helper method without breaking existing bindings/dependencies
"""
return send_video_status_update_source_function(updates)
def is_status_update_request(request_data):
"""
Exposes helper method without breaking existing bindings/dependencies
"""
return is_status_update_request_source_function(request_data)
@api_view(['GET'])
@view_auth_classes()
@require_GET
def get_course_youtube_edx_videos_ids(request, course_key_string):
"""
Get an object containing course videos.
**Example Request**
GET /api/contentstore/v1/videos/youtube_ids{course_id}
**Response Values**
If the request is successful, an HTTP 200 "OK" response is returned.
The HTTP 200 response contains a list of youtube edx_video_ids for a given course.
"""
return get_course_youtube_edx_video_ids(course_key_string)