Skip to content

Commit c752f6d

Browse files
committed
fix: return unit/container information
1 parent d57fd75 commit c752f6d

File tree

3 files changed

+86
-39
lines changed

3 files changed

+86
-39
lines changed

cms/djangoapps/contentstore/rest_api/v2/views/downstreams.py

Lines changed: 45 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -63,11 +63,11 @@
6363
"""
6464

6565
import logging
66+
from itertools import groupby
6667

6768
from attrs import asdict as attrs_asdict
6869
from django.contrib.auth.models import User # pylint: disable=imported-auth-user
6970
from django.utils.translation import gettext_lazy as _
70-
from itertools import groupby
7171
from opaque_keys import InvalidKeyError
7272
from opaque_keys.edx.keys import CourseKey, UsageKey
7373
from rest_framework.exceptions import NotFound, ValidationError
@@ -78,8 +78,8 @@
7878

7979
from cms.djangoapps.contentstore.helpers import import_static_assets_for_library_sync
8080
from cms.djangoapps.contentstore.models import PublishableEntityLink
81-
from cms.djangoapps.contentstore.utils import reverse_course_url, reverse_usage_url
8281
from cms.djangoapps.contentstore.rest_api.v2.serializers import PublishableEntityLinksSerializer
82+
from cms.djangoapps.contentstore.utils import reverse_course_url, reverse_usage_url
8383
from cms.lib.xblock.upstream_sync import (
8484
BadDownstream,
8585
BadUpstream,
@@ -92,6 +92,7 @@
9292
sync_from_upstream,
9393
)
9494
from common.djangoapps.student.auth import has_studio_read_access, has_studio_write_access
95+
from openedx.core.djangoapps.content.course_overviews.models import CourseOverview
9596
from openedx.core.lib.api.view_utils import (
9697
DeveloperErrorViewMixin,
9798
view_auth_classes,
@@ -148,7 +149,7 @@ def get(self, request: _AuthenticatedRequest, course_key_string: str):
148149
@view_auth_classes()
149150
class DownstreamContextListView(DeveloperErrorViewMixin, APIView):
150151
"""
151-
Serves library block->course->unit links
152+
Serves library block->course->container links
152153
"""
153154
def get(self, request: _AuthenticatedRequest, usage_key_string: str) -> Response:
154155
"""
@@ -166,30 +167,54 @@ def get(self, request: _AuthenticatedRequest, usage_key_string: str) -> Response
166167
.values( "downstream_usage_key", "downstream_context_key", "downstream_parent_usage_key")
167168
)
168169

170+
context_key_list = set(link["downstream_context_key"] for link in links)
171+
172+
courses_display_name = dict(
173+
CourseOverview.objects.filter(id__in=context_key_list).values_list('id', 'display_name')
174+
)
175+
169176
result = []
170177
for context_key, links_by_context in groupby(links, lambda link: link["downstream_context_key"]):
171-
# Pre-fetch the course with all of its children:
172-
course = modulestore().get_course(context_key, depth=None)
173-
if course is None:
178+
if context_key not in courses_display_name:
174179
raise BadDownstream(_("Course {context_key} not found").format(context_key=context_key))
180+
175181
course_link = {
176182
"id": str(context_key),
177-
"display_name": course.display_name,
183+
"display_name": courses_display_name[context_key],
178184
"url": reverse_course_url("course_handler", context_key),
179-
"units": []
185+
"containers": []
180186
}
181-
for unit_key, links_by_unit in groupby(links_by_context, lambda link: link["downstream_parent_usage_key"]):
182-
unit_link = {
183-
"id": str(unit_key),
184-
"url": reverse_usage_url("container_handler", unit_key),
185-
"links": []
186-
}
187-
for downstream_link in links_by_unit:
188-
unit_link["links"].append({
189-
"id": str(downstream_link["downstream_usage_key"]),
190-
})
191-
course_link["units"].append(unit_link)
192-
result.append(course_link)
187+
188+
for parent_key, links_by_unit in groupby(links_by_context, lambda link: link["downstream_parent_usage_key"]):
189+
try:
190+
parent = modulestore().get_item(parent_key)
191+
192+
parent_link = {
193+
"id": str(parent_key),
194+
"display_name": parent.display_name,
195+
"url": reverse_usage_url("container_handler", parent_key),
196+
"links": []
197+
}
198+
199+
for downstream_link in links_by_unit:
200+
parent_link["links"].append({
201+
"id": str(downstream_link["downstream_usage_key"]),
202+
})
203+
204+
# Don't include empty containers
205+
if parent_link["links"]:
206+
course_link["containers"].append(parent_link)
207+
208+
except ItemNotFoundError:
209+
logger.exception(
210+
"Unit %s not found in course %s",
211+
parent_key,
212+
context_key
213+
)
214+
215+
# Don't include empty courses
216+
if course_link["containers"]:
217+
result.append(course_link)
193218

194219
return Response(result)
195220

cms/djangoapps/contentstore/rest_api/v2/views/tests/test_downstreams.py

Lines changed: 38 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -60,24 +60,27 @@ def setUp(self):
6060
CourseOverviewFactory.create(id=self.course.id, display_name=self.course.display_name)
6161
chapter = BlockFactory.create(category='chapter', parent=self.course)
6262
sequential = BlockFactory.create(category='sequential', parent=chapter)
63-
unit = BlockFactory.create(category='vertical', parent=sequential)
64-
self.regular_video_key = BlockFactory.create(category='video', parent=unit).usage_key
63+
self.unit = BlockFactory.create(category='vertical', parent=sequential)
64+
self.regular_video_key = BlockFactory.create(category='video', parent=self.unit).usage_key
6565
self.downstream_video_key = BlockFactory.create(
66-
category='video', parent=unit, upstream=MOCK_UPSTREAM_REF, upstream_version=123,
66+
category='video', parent=self.unit, upstream=MOCK_UPSTREAM_REF, upstream_version=123,
6767
).usage_key
6868
self.downstream_html_key = BlockFactory.create(
69-
category='html', parent=unit, upstream=MOCK_HTML_UPSTREAM_REF, upstream_version=1,
69+
category='html', parent=self.unit, upstream=MOCK_HTML_UPSTREAM_REF, upstream_version=1,
7070
).usage_key
7171

7272
self.another_course = CourseFactory.create(display_name="Another Course")
7373
CourseOverviewFactory.create(id=self.another_course.id, display_name=self.another_course.display_name)
74-
another_chapter = BlockFactory.create(category='chapter', parent=self.another_course)
75-
another_sequential = BlockFactory.create(category='sequential', parent=another_chapter)
76-
another_unit = BlockFactory.create(category='vertical', parent=another_sequential)
74+
another_chapter = BlockFactory.create(category="chapter", parent=self.another_course)
75+
another_sequential = BlockFactory.create(category="sequential", parent=another_chapter)
76+
self.another_unit = BlockFactory.create(category="vertical", parent=another_sequential)
77+
self.another_video_keys = []
7778
for _ in range(3):
7879
# Adds 3 videos linked to the same upstream
79-
BlockFactory.create(
80-
category='video', parent=another_unit, upstream=MOCK_UPSTREAM_REF, upstream_version=123,
80+
self.another_video_keys.append(
81+
BlockFactory.create(
82+
category="video", parent=self.another_unit, upstream=MOCK_UPSTREAM_REF, upstream_version=123,
83+
).usage_key
8184
)
8285

8386
self.fake_video_key = self.course.id.make_usage_key("video", "NoSuchVideo")
@@ -329,6 +332,7 @@ def test_200_all_upstreams(self):
329332
'created': date_format,
330333
'downstream_context_key': str(self.course.id),
331334
'downstream_usage_key': str(self.downstream_video_key),
335+
'downstream_parent_usage_key': str(self.unit.usage_key),
332336
'id': 1,
333337
'ready_to_sync': False,
334338
'updated': date_format,
@@ -342,6 +346,7 @@ def test_200_all_upstreams(self):
342346
'created': date_format,
343347
'downstream_context_key': str(self.course.id),
344348
'downstream_usage_key': str(self.downstream_html_key),
349+
'downstream_parent_usage_key': str(self.unit.usage_key),
345350
'id': 2,
346351
'ready_to_sync': False,
347352
'updated': date_format,
@@ -373,14 +378,32 @@ def test_200_downstream_context_list(self):
373378
data = response.json()
374379
expected = [
375380
{
376-
'id': str(self.course.id),
377-
'display_name': str(self.course.display_name),
378-
'url': f'/course/{str(self.course.id)}',
381+
"id": str(self.course.id),
382+
"display_name": str(self.course.display_name),
383+
"url": f"/course/{str(self.course.id)}",
384+
"containers": [
385+
{
386+
"id": str(self.unit.usage_key),
387+
"display_name": str(self.unit.display_name),
388+
"url": f"/container/{str(self.unit.usage_key)}",
389+
"links": [
390+
{ "id": str(self.downstream_video_key) },
391+
],
392+
},
393+
],
379394
},
380395
{
381-
'id': str(self.another_course.id),
382-
'display_name': str(self.another_course.display_name),
383-
'url': f'/course/{str(self.another_course.id)}',
396+
"id": str(self.another_course.id),
397+
"display_name": str(self.another_course.display_name),
398+
"url": f"/course/{str(self.another_course.id)}",
399+
"containers": [
400+
{
401+
"id": str(self.another_unit.usage_key),
402+
"display_name": str(self.another_unit.display_name),
403+
"url": f"/container/{str(self.another_unit.usage_key)}",
404+
"links": [ { "id": str(key) } for key in self.another_video_keys ],
405+
},
406+
],
384407
},
385408
]
386409
self.assertListEqual(data, expected)

cms/djangoapps/contentstore/utils.py

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2371,7 +2371,7 @@ def get_xblock_render_context(request, block):
23712371
return ""
23722372

23732373

2374-
def create_or_update_xblock_upstream_link(xblock, course_key: str | CourseKey, created: datetime | None = None):
2374+
def create_or_update_xblock_upstream_link(xblock, course_key: str | CourseKey, created: datetime | None = None) -> None:
23752375
"""
23762376
Create or update upstream->downstream link in database for given xblock.
23772377
"""
@@ -2383,14 +2383,13 @@ def create_or_update_xblock_upstream_link(xblock, course_key: str | CourseKey, c
23832383
except ObjectDoesNotExist:
23842384
log.error(f"Library component not found for {upstream_usage_key}")
23852385
lib_component = None
2386-
2387-
print(f"!!!!!!!!!!!!!!!!! xblock.parent -> {xblock.parent}")
23882386
PublishableEntityLink.update_or_create(
23892387
lib_component,
23902388
upstream_usage_key=xblock.upstream,
23912389
upstream_context_key=str(upstream_usage_key.context_key),
2392-
downstream_context_key=course_key,
23932390
downstream_usage_key=xblock.usage_key,
2391+
downstream_parent_usage_key=xblock.parent,
2392+
downstream_context_key=course_key,
23942393
version_synced=xblock.upstream_version,
23952394
version_declined=xblock.upstream_version_declined,
23962395
created=created,

0 commit comments

Comments
 (0)