4040 400: Downstream block is not linked to upstream content.
4141 404: Downstream block not found or user lacks permission to edit it.
4242
43+ /api/contentstore/v2/upstream/{usage_key_string}/downstream-contexts
44+
45+ GET: List all downstream contexts (Courses) linked to a library block.
46+ 200: A list of Course IDs and their display names, along with the number of times the block
47+ is linked to each.
48+
4349 # NOT YET IMPLEMENTED -- Will be needed for full Libraries Relaunch in ~Teak.
4450 /api/contentstore/v2/downstreams
4551 /api/contentstore/v2/downstreams?course_id=course-v1:A+B+C&ready_to_sync=true
6066import logging
6167
6268from attrs import asdict as attrs_asdict
69+ from collections import Counter
6370from django .contrib .auth .models import User # pylint: disable=imported-auth-user
6471from opaque_keys import InvalidKeyError
6572from opaque_keys .edx .keys import CourseKey , UsageKey
7178
7279from cms .djangoapps .contentstore .helpers import import_static_assets_for_library_sync
7380from cms .djangoapps .contentstore .models import PublishableEntityLink
81+ from cms .djangoapps .contentstore .utils import reverse_course_url
7482from cms .djangoapps .contentstore .rest_api .v2 .serializers import PublishableEntityLinksSerializer
7583from cms .lib .xblock .upstream_sync import (
7684 BadDownstream ,
9199from xmodule .modulestore .django import modulestore
92100from xmodule .modulestore .exceptions import ItemNotFoundError
93101
102+
94103logger = logging .getLogger (__name__ )
95104
96105
@@ -124,7 +133,7 @@ class UpstreamListView(DeveloperErrorViewMixin, APIView):
124133 """
125134 Serves course->library publishable entity links
126135 """
127- def get (self , request : _AuthenticatedRequest , course_key_string : str ):
136+ def get (self , _ : _AuthenticatedRequest , course_key_string : str ):
128137 """
129138 Fetches publishable entity links for given course key
130139 """
@@ -137,6 +146,40 @@ def get(self, request: _AuthenticatedRequest, course_key_string: str):
137146 return Response (serializer .data )
138147
139148
149+ @view_auth_classes ()
150+ class DownstreamContextListView (DeveloperErrorViewMixin , APIView ):
151+ """
152+ Serves library block->courses links
153+ """
154+ def get (self , _ : _AuthenticatedRequest , usage_key_string : str ) -> Response :
155+ """
156+ Fetches downstream context links for given publishable entity
157+ """
158+ try :
159+ usage_key = UsageKey .from_string (usage_key_string )
160+ print (usage_key )
161+ except InvalidKeyError as exc :
162+ raise ValidationError (detail = f"Malformed usage key: { usage_key_string } " ) from exc
163+ links = PublishableEntityLink .get_by_upstream_usage_key (upstream_usage_key = usage_key )
164+ downstream_key_list = [link .downstream_context_key for link in links ]
165+
166+ # Count the number of times each course is linked to the library block
167+ counter = Counter (downstream_key_list )
168+
169+ result = []
170+ for context_key , count in counter .most_common ():
171+ # The following code only can handle the correct display_name for Courses as context
172+ course = modulestore ().get_course (context_key )
173+ result .append ({
174+ "id" : str (context_key ),
175+ "display_name" : course .display_name ,
176+ "url" : reverse_course_url ('course_handler' , context_key ),
177+ "count" : count ,
178+ })
179+
180+ return Response (result )
181+
182+
140183@view_auth_classes (is_authenticated = True )
141184class DownstreamView (DeveloperErrorViewMixin , APIView ):
142185 """
0 commit comments