Merge pull request #34977 from openedx/hajorg/au-2070-youtube-videos-id

feat: get youtube videos edx_video_id for a course
This commit is contained in:
Jorg Are
2024-06-21 10:47:48 +01:00
committed by GitHub
4 changed files with 131 additions and 0 deletions

View File

@@ -42,6 +42,7 @@ from edxval.api import (
update_video_status
)
from fs.osfs import OSFS
from opaque_keys import InvalidKeyError
from opaque_keys.edx.keys import CourseKey
from path import Path as path
from pytz import UTC
@@ -960,3 +961,32 @@ def _update_pagination_context(request):
request.session['VIDEOS_PER_PAGE'] = videos_per_page
return JsonResponse()
def get_course_youtube_edx_video_ids(course_id):
"""
Get a list of youtube edx_video_ids
"""
error_msg = "Invalid course_key: '%s'." % course_id
try:
course_key = CourseKey.from_string(course_id)
course = modulestore().get_course(course_key)
except InvalidKeyError:
return JsonResponse({'error': error_msg}, status=500)
blocks = []
block_yt_field = 'youtube_id_1_0'
block_edx_id_field = 'edx_video_id'
if hasattr(course, 'get_children'):
for section in course.get_children():
for subsection in section.get_children():
for vertical in subsection.get_children():
for block in vertical.get_children():
blocks.append(block)
edx_video_ids = []
for block in blocks:
if hasattr(block, block_yt_field) and getattr(block, block_yt_field):
if getattr(block, block_edx_id_field):
edx_video_ids.append(getattr(block, block_edx_id_field))
return JsonResponse({'edx_video_ids': edx_video_ids}, status=200)

View File

@@ -12,6 +12,7 @@ from io import StringIO
from unittest.mock import Mock, patch
import dateutil.parser
from common.djangoapps.student.tests.factories import UserFactory
import ddt
import pytz
from django.test import TestCase
@@ -37,6 +38,8 @@ from openedx.core.djangoapps.video_pipeline.config.waffle import (
ENABLE_DEVSTACK_VIDEO_UPLOADS,
)
from openedx.core.djangoapps.waffle_utils.models import WaffleFlagCourseOverrideModel
from xmodule.modulestore.django import modulestore
from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase
from xmodule.modulestore.tests.factories import CourseFactory # lint-amnesty, pylint: disable=wrong-import-order
from ..videos import (
@@ -1662,3 +1665,82 @@ class GetStorageBucketTestCase(TestCase):
self.assertIn("https://vem_test_bucket.s3.amazonaws.com:443/test_root/", upload_url)
self.assertIn(edx_video_id, upload_url)
class CourseYoutubeEdxVideoIds(ModuleStoreTestCase):
"""
This test checks youtube videos in a course
"""
VIEW_NAME = 'youtube_edx_video_ids'
def setUp(self):
super().setUp()
self.course = CourseFactory.create()
self.course_with_no_youtube_videos = CourseFactory.create()
self.store = modulestore()
self.user = UserFactory()
self.client.login(username=self.user.username, password='Password1234')
def get_url_for_course_key(self, course_key, kwargs=None):
"""Return video handler URL for the given course"""
return reverse_course_url(self.VIEW_NAME, course_key, kwargs) # lint-amnesty, pylint: disable=no-member
def test_course_with_youtube_videos(self):
course_key = self.course.id
with self.store.bulk_operations(course_key):
chapter_loc = self.store.create_child(
self.user.id, self.course.location, 'chapter', 'test_chapter'
).location
seq_loc = self.store.create_child(
self.user.id, chapter_loc, 'sequential', 'test_seq'
).location
vert_loc = self.store.create_child(self.user.id, seq_loc, 'vertical', 'test_vert').location
self.store.create_child(
self.user.id,
vert_loc,
'problem',
'test_problem',
fields={"data": "<problem>Test</problem>"}
)
self.store.create_child(
self.user.id, vert_loc, 'video', fields={
"youtube_is_available": False,
"name": "sample_video",
"edx_video_id": "youtube_193_84709099",
}
)
response = self.client.get(self.get_url_for_course_key(course_key))
self.assertEqual(response.status_code, 200)
edx_video_ids = json.loads(response.content.decode('utf-8'))['edx_video_ids']
self.assertEqual(len(edx_video_ids), 1)
def test_course_with_no_youtube_videos(self):
course_key = self.course_with_no_youtube_videos.id
with self.store.bulk_operations(course_key):
chapter_loc = self.store.create_child(
self.user.id, self.course_with_no_youtube_videos.location, 'chapter', 'test_chapter'
).location
seq_loc = self.store.create_child(
self.user.id, chapter_loc, 'sequential', 'test_seq'
).location
vert_loc = self.store.create_child(self.user.id, seq_loc, 'vertical', 'test_vert').location
self.store.create_child(
self.user.id, vert_loc, 'problem', 'test_problem', fields={"data": "<problem>Test</problem>"}
)
self.store.create_child(
self.user.id, vert_loc, 'video', fields={
"youtube_id_1_0": None,
"name": "sample_video",
"edx_video_id": "no_youtube_193_84709099",
}
)
response = self.client.get(self.get_url_for_course_key(course_key))
edx_video_ids = json.loads(response.content.decode('utf-8'))['edx_video_ids']
self.assertEqual(response.status_code, 200)
self.assertEqual(len(edx_video_ids), 0)

View File

@@ -27,6 +27,7 @@ from cms.djangoapps.contentstore.video_storage_handlers import (
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
@@ -41,6 +42,7 @@ __all__ = [
'get_video_features',
'transcript_preferences_handler',
'generate_video_upload_link_handler',
'get_course_youtube_edx_videos_ids',
]
LOGGER = logging.getLogger(__name__)
@@ -236,3 +238,18 @@ 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)

View File

@@ -194,6 +194,8 @@ urlpatterns = oauth2_urlpatterns + [
path('api/val/v0/', include('edxval.urls')),
path('api/tasks/v0/', include('user_tasks.urls')),
path('accessibility', contentstore_views.accessibility, name='accessibility'),
re_path(fr'api/youtube/courses/{COURSELIKE_KEY_PATTERN}/edx-video-ids$',
contentstore_views.get_course_youtube_edx_videos_ids, name='youtube_edx_video_ids'),
]
if not settings.DISABLE_DEPRECATED_SIGNIN_URL: