diff --git a/cms/djangoapps/contentstore/asset_storage_handlers.py b/cms/djangoapps/contentstore/asset_storage_handlers.py index 9cf87e67f8..1c9ba46702 100644 --- a/cms/djangoapps/contentstore/asset_storage_handlers.py +++ b/cms/djangoapps/contentstore/asset_storage_handlers.py @@ -88,6 +88,51 @@ def handle_assets(request, course_key_string=None, asset_key_string=None): return HttpResponseNotFound() +def get_asset_usage_path(request, course_key, asset_key_string): + """ + Get a list of units with ancestors that use given asset. + """ + course_key = CourseKey.from_string(course_key) + if not has_course_author_access(request.user, course_key): + raise PermissionDenied() + asset_location = AssetKey.from_string(asset_key_string) if asset_key_string else None + store = modulestore() + usage_locations = [] + static_path = StaticContent.get_static_path_from_location(asset_location) + verticals = store.get_items( + course_key, + qualifiers={ + 'category': 'vertical' + }, + ) + blocks = [] + + for vertical in verticals: + blocks.extend(vertical.get_children()) + + for block in blocks: + is_video_block = getattr(block, 'category', '') == 'video' + if is_video_block: + handout = getattr(block, 'handout', '') + if handout and str(asset_location) in handout: + unit = block.get_parent() + subsection = unit.get_parent() + subsection_display_name = getattr(subsection, 'display_name', '') + unit_display_name = getattr(unit, 'display_name', '') + xblock_display_name = getattr(block, 'display_name', '') + usage_locations.append(f'{subsection_display_name} - {unit_display_name} / {xblock_display_name}') + else: + data = getattr(block, 'data', '') + if static_path in data or str(asset_location) in data: + unit = block.get_parent() + subsection = unit.get_parent() + subsection_display_name = getattr(subsection, 'display_name', '') + unit_display_name = getattr(unit, 'display_name', '') + xblock_display_name = getattr(block, 'display_name', '') + usage_locations.append(f'{subsection_display_name} - {unit_display_name} / {xblock_display_name}') + return JsonResponse({'usage_locations': usage_locations}) + + def _get_response_format(request): return request.GET.get('format') or request.POST.get('format') or 'html' diff --git a/cms/djangoapps/contentstore/views/assets.py b/cms/djangoapps/contentstore/views/assets.py index af8a2242e8..cca58e8c6b 100644 --- a/cms/djangoapps/contentstore/views/assets.py +++ b/cms/djangoapps/contentstore/views/assets.py @@ -5,14 +5,16 @@ from django.contrib.auth.decorators import login_required from django.views.decorators.csrf import ensure_csrf_cookie from cms.djangoapps.contentstore.asset_storage_handlers import ( handle_assets, + get_asset_usage_path, update_course_run_asset as update_course_run_asset_source_function, get_file_size as get_file_size_source_function, delete_asset as delete_asset_source_function, get_asset_json as get_asset_json_source_function, update_asset as update_asset_source_function, + ) -__all__ = ['assets_handler'] +__all__ = ['assets_handler', 'asset_usage_path_handler'] REQUEST_DEFAULTS = { 'page': 0, @@ -52,6 +54,12 @@ def assets_handler(request, course_key_string=None, asset_key_string=None): return handle_assets(request, course_key_string, asset_key_string) +@login_required +@ensure_csrf_cookie +def asset_usage_path_handler(request, course_key_string, asset_key_string): + return get_asset_usage_path(request, course_key_string, asset_key_string) + + def update_course_run_asset(course_key, upload_file): """Exposes service method in asset_storage_handlers without breaking existing bindings/dependencies""" return update_course_run_asset_source_function(course_key, upload_file) diff --git a/cms/templates/widgets/header.html b/cms/templates/widgets/header.html index dd8f760b3c..85e6495dc3 100644 --- a/cms/templates/widgets/header.html +++ b/cms/templates/widgets/header.html @@ -131,7 +131,7 @@ %endif %if files_uploads_mfe_enabled: