Пример #1
0
    def test_remove_transcript_preferences_not_found(self):
        """
        Test that transcript handler works correctly even when no preferences are found.
        """
        course_id = 'course-v1:dummy+course+id'
        # Verify transcript preferences do not exist
        preferences = get_transcript_preferences(course_id)
        self.assertIsNone(preferences)

        response = self.client.delete(self.get_url_for_course_key(course_id),
                                      content_type='application/json')
        self.assertEqual(response.status_code, 204)

        # Verify transcript preferences do not exist
        preferences = get_transcript_preferences(course_id)
        self.assertIsNone(preferences)
Пример #2
0
def videos_index_html(course):
    """
    Returns an HTML page to display previous video uploads and allow new ones
    """
    is_video_transcript_enabled = VideoTranscriptEnabledFlag.feature_enabled(
        course.id)
    context = {
        'context_course':
        course,
        'image_upload_url':
        reverse_course_url('video_images_handler', unicode(course.id)),
        'video_handler_url':
        reverse_course_url('videos_handler', unicode(course.id)),
        'encodings_download_url':
        reverse_course_url('video_encodings_download', unicode(course.id)),
        'default_video_image_url':
        _get_default_video_image_url(),
        'previous_uploads':
        _get_index_videos(course),
        'concurrent_upload_limit':
        settings.VIDEO_UPLOAD_PIPELINE.get('CONCURRENT_UPLOAD_LIMIT', 0),
        'video_supported_file_formats':
        VIDEO_SUPPORTED_FILE_FORMATS.keys(),
        'video_upload_max_file_size':
        VIDEO_UPLOAD_MAX_FILE_SIZE_GB,
        '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'],
            'min_size':
            settings.VIDEO_IMAGE_SETTINGS['VIDEO_IMAGE_MIN_BYTES'],
            'max_width':
            settings.VIDEO_IMAGE_MAX_WIDTH,
            'max_height':
            settings.VIDEO_IMAGE_MAX_HEIGHT,
            'supported_file_formats':
            settings.VIDEO_IMAGE_SUPPORTED_FILE_FORMATS
        },
        'is_video_transcript_enabled':
        is_video_transcript_enabled,
        'video_transcript_settings':
        None,
        'active_transcript_preferences':
        None
    }

    if is_video_transcript_enabled:
        context['video_transcript_settings'] = {
            'transcript_preferences_handler_url':
            reverse_course_url('transcript_preferences_handler',
                               unicode(course.id)),
            'transcription_plans':
            get_3rd_party_transcription_plans(),
        }
        context['active_transcript_preferences'] = get_transcript_preferences(
            unicode(course.id))

    return render_to_response('videos_index.html', context)
Пример #3
0
    def test_remove_transcript_preferences_not_found(self):
        """
        Test that transcript handler works correctly even when no preferences are found.
        """
        course_id = 'course-v1:dummy+course+id'
        # Verify transcript preferences do not exist
        preferences = get_transcript_preferences(course_id)
        self.assertIsNone(preferences)

        response = self.client.delete(
            self.get_url_for_course_key(course_id),
            content_type='application/json'
        )
        self.assertEqual(response.status_code, 204)

        # Verify transcript preferences do not exist
        preferences = get_transcript_preferences(course_id)
        self.assertIsNone(preferences)
Пример #4
0
def videos_index_html(course, pagination_conf=None):
    """
    Returns an HTML page to display previous video uploads and allow new ones
    """
    is_video_transcript_enabled = VideoTranscriptEnabledFlag.feature_enabled(course.id)
    previous_uploads, pagination_context = _get_index_videos(course, pagination_conf)
    context = {
        'context_course': course,
        'image_upload_url': reverse_course_url('video_images_handler', six.text_type(course.id)),
        'video_handler_url': reverse_course_url('videos_handler', six.text_type(course.id)),
        'encodings_download_url': reverse_course_url('video_encodings_download', six.text_type(course.id)),
        'default_video_image_url': _get_default_video_image_url(),
        'previous_uploads': previous_uploads,
        'concurrent_upload_limit': settings.VIDEO_UPLOAD_PIPELINE.get('CONCURRENT_UPLOAD_LIMIT', 0),
        'video_supported_file_formats': list(VIDEO_SUPPORTED_FILE_FORMATS.keys()),
        'video_upload_max_file_size': VIDEO_UPLOAD_MAX_FILE_SIZE_GB,
        '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'],
            'min_size': settings.VIDEO_IMAGE_SETTINGS['VIDEO_IMAGE_MIN_BYTES'],
            'max_width': settings.VIDEO_IMAGE_MAX_WIDTH,
            'max_height': settings.VIDEO_IMAGE_MAX_HEIGHT,
            'supported_file_formats': settings.VIDEO_IMAGE_SUPPORTED_FILE_FORMATS
        },
        'is_video_transcript_enabled': is_video_transcript_enabled,
        'active_transcript_preferences': None,
        'transcript_credentials': None,
        'transcript_available_languages': get_all_transcript_languages(),
        'video_transcript_settings': {
            'transcript_download_handler_url': reverse('transcript_download_handler'),
            'transcript_upload_handler_url': reverse('transcript_upload_handler'),
            'transcript_delete_handler_url': reverse_course_url('transcript_delete_handler', six.text_type(course.id)),
            'trancript_download_file_format': Transcript.SRT
        },
        'pagination_context': pagination_context
    }

    if is_video_transcript_enabled:
        context['video_transcript_settings'].update({
            'transcript_preferences_handler_url': reverse_course_url(
                'transcript_preferences_handler',
                six.text_type(course.id)
            ),
            'transcript_credentials_handler_url': reverse_course_url(
                'transcript_credentials_handler',
                six.text_type(course.id)
            ),
            'transcription_plans': get_3rd_party_transcription_plans(),
        })
        context['active_transcript_preferences'] = get_transcript_preferences(six.text_type(course.id))
        # Cached state for transcript providers' credentials (org-specific)
        context['transcript_credentials'] = get_transcript_credentials_state_for_org(course.id.org)

    return render_to_response('videos_index.html', context)
Пример #5
0
def videos_index_html(course):
    """
    Returns an HTML page to display previous video uploads and allow new ones
    """
    is_video_transcript_enabled = VideoTranscriptEnabledFlag.feature_enabled(course.id)
    context = {
        'context_course': course,
        'image_upload_url': reverse_course_url('video_images_handler', unicode(course.id)),
        'video_handler_url': reverse_course_url('videos_handler', unicode(course.id)),
        'encodings_download_url': reverse_course_url('video_encodings_download', unicode(course.id)),
        'default_video_image_url': _get_default_video_image_url(),
        'previous_uploads': _get_index_videos(course),
        'concurrent_upload_limit': settings.VIDEO_UPLOAD_PIPELINE.get('CONCURRENT_UPLOAD_LIMIT', 0),
        'video_supported_file_formats': VIDEO_SUPPORTED_FILE_FORMATS.keys(),
        'video_upload_max_file_size': VIDEO_UPLOAD_MAX_FILE_SIZE_GB,
        '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'],
            'min_size': settings.VIDEO_IMAGE_SETTINGS['VIDEO_IMAGE_MIN_BYTES'],
            'max_width': settings.VIDEO_IMAGE_MAX_WIDTH,
            'max_height': settings.VIDEO_IMAGE_MAX_HEIGHT,
            'supported_file_formats': settings.VIDEO_IMAGE_SUPPORTED_FILE_FORMATS
        },
        'is_video_transcript_enabled': is_video_transcript_enabled,
        'active_transcript_preferences': None,
        'transcript_credentials': None,
        'transcript_available_languages': get_all_transcript_languages(),
        'video_transcript_settings': {
            'transcript_download_handler_url': reverse('transcript_download_handler'),
            'transcript_upload_handler_url': reverse('transcript_upload_handler'),
            'transcript_delete_handler_url': reverse_course_url('transcript_delete_handler', unicode(course.id)),
            'trancript_download_file_format': Transcript.SRT
        }
    }

    if is_video_transcript_enabled:
        context['video_transcript_settings'].update({
            'transcript_preferences_handler_url': reverse_course_url(
                'transcript_preferences_handler',
                unicode(course.id)
            ),
            'transcript_credentials_handler_url': reverse_course_url(
                'transcript_credentials_handler',
                unicode(course.id)
            ),
            'transcription_plans': get_3rd_party_transcription_plans(),
        })
        context['active_transcript_preferences'] = get_transcript_preferences(unicode(course.id))
        # Cached state for transcript providers' credentials (org-specific)
        context['transcript_credentials'] = get_transcript_credentials_state_for_org(course.id.org)

    return render_to_response('videos_index.html', context)
Пример #6
0
    def test_remove_transcript_preferences(self):
        """
        Test that transcript handler removes transcript preferences correctly.
        """
        # First add course wide transcript preferences.
        preferences = create_or_update_transcript_preferences(
            unicode(self.course.id))

        # Verify transcript preferences exist
        self.assertIsNotNone(preferences)

        response = self.client.delete(self.get_url_for_course_key(
            self.course.id),
                                      content_type='application/json')

        self.assertEqual(response.status_code, 204)

        # Verify transcript preferences no loger exist
        preferences = get_transcript_preferences(unicode(self.course.id))
        self.assertIsNone(preferences)
Пример #7
0
    def test_remove_transcript_preferences(self):
        """
        Test that transcript handler removes transcript preferences correctly.
        """
        # First add course wide transcript preferences.
        preferences = create_or_update_transcript_preferences(unicode(self.course.id))

        # Verify transcript preferences exist
        self.assertIsNotNone(preferences)

        response = self.client.delete(
            self.get_url_for_course_key(self.course.id),
            content_type='application/json'
        )

        self.assertEqual(response.status_code, 204)

        # Verify transcript preferences no loger exist
        preferences = get_transcript_preferences(unicode(self.course.id))
        self.assertIsNone(preferences)
Пример #8
0
def videos_post(course, request):
    """
    Input (JSON):
    {
        "files": [{
            "file_name": "video.mp4",
            "content_type": "video/mp4"
        }]
    }

    Returns (JSON):
    {
        "files": [{
            "file_name": "video.mp4",
            "upload_url": "http://example.com/put_video"
        }]
    }

    The returned array corresponds exactly to the input array.
    """
    error = None
    data = request.json
    if 'files' not in data:
        error = "Request object is not JSON or does not contain 'files'"
    elif any(
            'file_name' not in file or 'content_type' not in file
            for file in data['files']
    ):
        error = "Request 'files' entry does not contain 'file_name' and 'content_type'"
    elif any(
            file['content_type'] not in VIDEO_SUPPORTED_FILE_FORMATS.values()
            for file in data['files']
    ):
        error = "Request 'files' entry contain unsupported content_type"

    if error:
        return JsonResponse({'error': error}, status=400)

    bucket = storage_service_bucket()
    req_files = data['files']
    resp_files = []

    for req_file in req_files:
        file_name = req_file['file_name']

        try:
            file_name.encode('ascii')
        except UnicodeEncodeError:
            error_msg = u'The file name for %s must contain only ASCII characters.' % file_name
            return JsonResponse({'error': error_msg}, status=400)

        edx_video_id = unicode(uuid4())
        key = storage_service_key(bucket, file_name=edx_video_id)

        metadata_list = [
            ('client_video_id', file_name),
            ('course_key', unicode(course.id)),
        ]

        deprecate_youtube = waffle_flags()[DEPRECATE_YOUTUBE]
        course_video_upload_token = course.video_upload_pipeline.get('course_video_upload_token')

        # Only include `course_video_upload_token` if youtube has not been deprecated
        # for this course.
        if not deprecate_youtube.is_enabled(course.id) and course_video_upload_token:
            metadata_list.append(('course_video_upload_token', course_video_upload_token))

        is_video_transcript_enabled = VideoTranscriptEnabledFlag.feature_enabled(course.id)
        if is_video_transcript_enabled:
            transcript_preferences = get_transcript_preferences(unicode(course.id))
            if transcript_preferences is not None:
                metadata_list.append(('transcript_preferences', json.dumps(transcript_preferences)))

        for metadata_name, value in metadata_list:
            key.set_metadata(metadata_name, value)
        upload_url = key.generate_url(
            KEY_EXPIRATION_IN_SECONDS,
            'PUT',
            headers={'Content-Type': req_file['content_type']}
        )

        # persist edx_video_id in VAL
        create_video({
            'edx_video_id': edx_video_id,
            'status': 'upload',
            'client_video_id': file_name,
            'duration': 0,
            'encoded_videos': [],
            'courses': [unicode(course.id)]
        })

        resp_files.append({'file_name': file_name, 'upload_url': upload_url, 'edx_video_id': edx_video_id})

    return JsonResponse({'files': resp_files}, status=200)
Пример #9
0
def videos_post(course, request):
    """
    Input (JSON):
    {
        "files": [{
            "file_name": "video.mp4",
            "content_type": "video/mp4"
        }]
    }

    Returns (JSON):
    {
        "files": [{
            "file_name": "video.mp4",
            "upload_url": "http://example.com/put_video"
        }]
    }

    The returned array corresponds exactly to the input array.
    """
    error = None
    data = request.json
    if 'files' not in data:
        error = "Request object is not JSON or does not contain 'files'"
    elif any(
            'file_name' not in file or 'content_type' not in file
            for file in data['files']
    ):
        error = "Request 'files' entry does not contain 'file_name' and 'content_type'"
    elif any(
            file['content_type'] not in VIDEO_SUPPORTED_FILE_FORMATS.values()
            for file in data['files']
    ):
        error = "Request 'files' entry contain unsupported content_type"

    if error:
        return JsonResponse({'error': error}, status=400)

    req_files = data['files']
    resp_files = []

    for req_file in req_files:
        file_name = req_file['file_name']

        try:
            file_name.encode('ascii')
        except UnicodeEncodeError:
            error_msg = 'The file name for %s must contain only ASCII characters.' % file_name
            return JsonResponse({'error': error_msg}, status=400)

        edx_video_id = unicode(uuid4())

        metadata_list = [
            ('client_video_id', file_name),
            ('course_key', unicode(course.id)),
        ]

        # Only include `course_video_upload_token` if its set, as it won't be required if video uploads
        # are enabled by default.
        course_video_upload_token = course.video_upload_pipeline.get('course_video_upload_token')
        if course_video_upload_token:
            metadata_list.append(('course_video_upload_token', course_video_upload_token))

        is_video_transcript_enabled = VideoTranscriptEnabledFlag.feature_enabled(course.id)
        if is_video_transcript_enabled:
            transcript_preferences = get_transcript_preferences(unicode(course.id))
            if transcript_preferences is not None:
                metadata_list.append(('transcript_preferences', json.dumps(transcript_preferences)))

        upload_url = settings.VIDEO_UPLOAD_PREAUTH_URL+edx_video_id

        # persist edx_video_id in VAL
        create_video({
            'edx_video_id': edx_video_id,
            'status': 'upload',
            'client_video_id': file_name,
            'duration': 0,
            'encoded_videos': [],
            'courses': [unicode(course.id)]
        })

        resp_files.append({'file_name': file_name, 'upload_url': upload_url, 'edx_video_id': edx_video_id})

    return JsonResponse({'files': resp_files}, status=200)
Пример #10
0
def videos_post(course, request):
    """
    Input (JSON):
    {
        "files": [{
            "file_name": "video.mp4",
            "content_type": "video/mp4"
        }]
    }

    Returns (JSON):
    {
        "files": [{
            "file_name": "video.mp4",
            "upload_url": "http://example.com/put_video"
        }]
    }

    The returned array corresponds exactly to the input array.
    """
    error = None
    data = request.json
    if 'files' not in data:
        error = "Request object is not JSON or does not contain 'files'"
    elif any(
            'file_name' not in file or 'content_type' not in file
            for file in data['files']
    ):
        error = "Request 'files' entry does not contain 'file_name' and 'content_type'"
    elif any(
            file['content_type'] not in VIDEO_SUPPORTED_FILE_FORMATS.values()
            for file in data['files']
    ):
        error = "Request 'files' entry contain unsupported content_type"

    if error:
        return JsonResponse({'error': error}, status=400)

    bucket = storage_service_bucket()
    req_files = data['files']
    resp_files = []

    for req_file in req_files:
        file_name = req_file['file_name']

        try:
            file_name.encode('ascii')
        except UnicodeEncodeError:
            error_msg = 'The file name for %s must contain only ASCII characters.' % file_name
            return JsonResponse({'error': error_msg}, status=400)

        edx_video_id = unicode(uuid4())
        key = storage_service_key(bucket, file_name=edx_video_id)

        metadata_list = [
            ('client_video_id', file_name),
            ('course_key', unicode(course.id)),
        ]

        # Only include `course_video_upload_token` if its set, as it won't be required if video uploads
        # are enabled by default.
        course_video_upload_token = course.video_upload_pipeline.get('course_video_upload_token')
        if course_video_upload_token:
            metadata_list.append(('course_video_upload_token', course_video_upload_token))

        is_video_transcript_enabled = VideoTranscriptEnabledFlag.feature_enabled(course.id)
        if is_video_transcript_enabled:
            transcript_preferences = get_transcript_preferences(unicode(course.id))
            if transcript_preferences is not None:
                metadata_list.append(('transcript_preferences', json.dumps(transcript_preferences)))

        for metadata_name, value in metadata_list:
            key.set_metadata(metadata_name, value)
        upload_url = key.generate_url(
            KEY_EXPIRATION_IN_SECONDS,
            'PUT',
            headers={'Content-Type': req_file['content_type']}
        )

        # persist edx_video_id in VAL
        create_video({
            'edx_video_id': edx_video_id,
            'status': 'upload',
            'client_video_id': file_name,
            'duration': 0,
            'encoded_videos': [],
            'courses': [unicode(course.id)]
        })

        resp_files.append({'file_name': file_name, 'upload_url': upload_url, 'edx_video_id': edx_video_id})

    return JsonResponse({'files': resp_files}, status=200)