From e24438602d2af1c5d917a50ddee1ec2b9c537517 Mon Sep 17 00:00:00 2001 From: Qubad786 Date: Fri, 3 Aug 2018 18:44:21 +0500 Subject: [PATCH] Deprecate youtube for existing courses by not sending course_video_upload_token to VEDA. --- .../contentstore/views/tests/test_videos.py | 74 +++++++++++++++++++ cms/djangoapps/contentstore/views/videos.py | 9 ++- .../video_pipeline/config/__init__.py | 0 .../video_pipeline/config/waffle.py | 24 ++++++ 4 files changed, 104 insertions(+), 3 deletions(-) create mode 100644 openedx/core/djangoapps/video_pipeline/config/__init__.py create mode 100644 openedx/core/djangoapps/video_pipeline/config/waffle.py diff --git a/cms/djangoapps/contentstore/views/tests/test_videos.py b/cms/djangoapps/contentstore/views/tests/test_videos.py index 4a6176baa8..bcba7bf85f 100644 --- a/cms/djangoapps/contentstore/views/tests/test_videos.py +++ b/cms/djangoapps/contentstore/views/tests/test_videos.py @@ -8,6 +8,7 @@ import re from datetime import datetime from functools import wraps from StringIO import StringIO +from contextlib import contextmanager import dateutil.parser import ddt @@ -36,8 +37,12 @@ from contentstore.views.videos import ( from contentstore.views.videos import KEY_EXPIRATION_IN_SECONDS, StatusDisplayStrings, convert_video_status from xmodule.modulestore.tests.factories import CourseFactory +from openedx.core.djangoapps.video_pipeline.config.waffle import DEPRECATE_YOUTUBE from openedx.core.djangoapps.profile_images.tests.helpers import make_image_file +from openedx.core.djangoapps.waffle_utils.models import WaffleFlagCourseOverrideModel + from edxval.api import create_or_update_transcript_preferences, get_transcript_preferences +from waffle.testutils import override_flag def override_switch(switch, active): @@ -496,10 +501,12 @@ class VideosHandlerTestCase(VideoUploadTestMixin, CourseTestCase): self.assertIsNotNone(path_match) video_id = path_match.group(1) mock_key_instance = mock_key_instances[i] + mock_key_instance.set_metadata.assert_any_call( 'course_video_upload_token', self.test_token ) + mock_key_instance.set_metadata.assert_any_call( 'client_video_id', file_info['file_name'] @@ -524,6 +531,73 @@ class VideosHandlerTestCase(VideoUploadTestMixin, CourseTestCase): self.assertEqual(response_file['file_name'], file_info['file_name']) self.assertEqual(response_file['upload_url'], mock_key_instance.generate_url()) + @override_settings(AWS_ACCESS_KEY_ID='test_key_id', AWS_SECRET_ACCESS_KEY='test_secret') + @patch('boto.s3.key.Key') + @patch('boto.s3.connection.S3Connection') + @ddt.data( + { + 'global_waffle': True, + 'course_override': WaffleFlagCourseOverrideModel.ALL_CHOICES.off, + 'expect_token': True + }, + { + 'global_waffle': False, + 'course_override': WaffleFlagCourseOverrideModel.ALL_CHOICES.on, + 'expect_token': False + }, + { + 'global_waffle': False, + 'course_override': WaffleFlagCourseOverrideModel.ALL_CHOICES.off, + 'expect_token': True + } + ) + def test_video_upload_token_in_meta(self, data, mock_conn, mock_key): + """ + Test video upload token in s3 metadata. + """ + @contextmanager + def proxy_manager(manager, ignore_manager): + """ + This acts as proxy to the original manager in the arguments given + the original manager is not set to be ignored. + """ + if ignore_manager: + yield + else: + with manager: + yield + + file_data = { + 'file_name': 'first.mp4', + 'content_type': 'video/mp4', + } + mock_conn.return_value = Mock(get_bucket=Mock(return_value=Mock())) + mock_key_instance = Mock( + generate_url=Mock( + return_value='http://example.com/url_{}'.format(file_data['file_name']) + ) + ) + # If extra calls are made, return a dummy + mock_key.side_effect = [mock_key_instance] + + # expected args to be passed to `set_metadata`. + expected_args = ('course_video_upload_token', self.test_token) + + with patch.object(WaffleFlagCourseOverrideModel, 'override_value', return_value=data['course_override']): + with override_flag(DEPRECATE_YOUTUBE, active=data['global_waffle']): + response = self.client.post( + self.url, + json.dumps({'files': [file_data]}), + content_type='application/json' + ) + self.assertEqual(response.status_code, 200) + + with proxy_manager(self.assertRaises(AssertionError), data['expect_token']): + # if we're not expecting token then following should raise assertion error and + # if we're expecting token then we will be able to find the call to set the token + # in s3 metadata. + mock_key_instance.set_metadata.assert_any_call(*expected_args) + def _assert_video_removal(self, url, edx_video_id, deleted_videos): """ Verify that if correct video is removed from a particular course. diff --git a/cms/djangoapps/contentstore/views/videos.py b/cms/djangoapps/contentstore/views/videos.py index da8a065982..7cb981ded9 100644 --- a/cms/djangoapps/contentstore/views/videos.py +++ b/cms/djangoapps/contentstore/views/videos.py @@ -42,6 +42,7 @@ from contentstore.utils import reverse_course_url from contentstore.video_utils import validate_video_image from edxmako.shortcuts import render_to_response from openedx.core.djangoapps.video_config.models import VideoTranscriptEnabledFlag +from openedx.core.djangoapps.video_pipeline.config.waffle import waffle_flags, DEPRECATE_YOUTUBE from openedx.core.djangoapps.waffle_utils import WaffleSwitchNamespace from util.json_request import JsonResponse, expect_json @@ -699,10 +700,12 @@ def videos_post(course, request): ('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. + deprecate_youtube = waffle_flags()[DEPRECATE_YOUTUBE] course_video_upload_token = course.video_upload_pipeline.get('course_video_upload_token') - if 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) diff --git a/openedx/core/djangoapps/video_pipeline/config/__init__.py b/openedx/core/djangoapps/video_pipeline/config/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/openedx/core/djangoapps/video_pipeline/config/waffle.py b/openedx/core/djangoapps/video_pipeline/config/waffle.py new file mode 100644 index 0000000000..81b980a330 --- /dev/null +++ b/openedx/core/djangoapps/video_pipeline/config/waffle.py @@ -0,0 +1,24 @@ +""" +This module contains configuration settings via waffle flags +for the Video Pipeline app. +""" +from openedx.core.djangoapps.waffle_utils import WaffleFlagNamespace, CourseWaffleFlag + +# Videos Namespace +WAFFLE_NAMESPACE = 'videos' + +# Waffle flag telling whether youtube is deprecated. +DEPRECATE_YOUTUBE = 'deprecate_youtube' + + +def waffle_flags(): + """ + Returns the namespaced, cached, audited Waffle flags dictionary for Videos. + """ + namespace = WaffleFlagNamespace(name=WAFFLE_NAMESPACE, log_prefix=u'Videos: ') + return { + DEPRECATE_YOUTUBE: CourseWaffleFlag( + waffle_namespace=namespace, + flag_name=DEPRECATE_YOUTUBE + ) + }