From f330e49aafe4f23f0c620c7433b14c650c6516d7 Mon Sep 17 00:00:00 2001 From: Devasia Joseph Date: Thu, 10 Jul 2025 15:52:25 +0530 Subject: [PATCH 1/2] feat: Added disable/enable discussion endpoint to swagger --- cms/djangoapps/contentstore/views/course.py | 32 +++++++++++++++++++++ cms/lib/spectacular.py | 3 +- 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/cms/djangoapps/contentstore/views/course.py b/cms/djangoapps/contentstore/views/course.py index 3de22d7f88..3eb105742d 100644 --- a/cms/djangoapps/contentstore/views/course.py +++ b/cms/djangoapps/contentstore/views/course.py @@ -22,6 +22,7 @@ from django.urls import reverse from django.utils.translation import gettext as _ from django.views.decorators.csrf import ensure_csrf_cookie from django.views.decorators.http import require_GET, require_http_methods +from drf_spectacular.utils import extend_schema, OpenApiParameter, OpenApiRequest, OpenApiResponse from edx_django_utils.monitoring import function_trace from opaque_keys import InvalidKeyError from opaque_keys.edx.keys import CourseKey @@ -1712,6 +1713,37 @@ def group_configurations_detail_handler(request, course_key_string, group_config ) +@extend_schema( + summary="Bulk enable/disable discussions for all units in a course.", + description="Enable or disable discussions for all verticals in the specified course.", + request=OpenApiRequest( + request={ + "type": "object", + "properties": {"discussion_enabled": {"type": "boolean"}}, + "required": ["discussion_enabled"], + } + ), + responses={ + 200: OpenApiResponse( + response={ + "type": "object", + "properties": {"units_updated_and_republished": {"type": "integer"}}, + } + ), + 400: OpenApiResponse(description="Bad request"), + 403: OpenApiResponse(description="Permission denied"), + }, + methods=["PUT"], + parameters=[ + OpenApiParameter( + name="course_key_string", + description="Course key string", + required=True, + type=str, + location=OpenApiParameter.PATH, + ) + ], +) @api_view(['PUT']) @view_auth_classes() @expect_json diff --git a/cms/lib/spectacular.py b/cms/lib/spectacular.py index c7445decc2..0f4364f3b4 100644 --- a/cms/lib/spectacular.py +++ b/cms/lib/spectacular.py @@ -16,7 +16,8 @@ def cms_api_filter(endpoints): path.startswith("/api/contentstore/v0/videos") or path.startswith("/api/contentstore/v0/video_transcripts") or path.startswith("/api/contentstore/v0/file_assets") or - path.startswith("/api/contentstore/v0/youtube_transcripts") + path.startswith("/api/contentstore/v0/youtube_transcripts") or + path.startswith("/api/courses/") and "bulk_enable_disable_discussions" in path ): filtered.append((path, path_regex, method, callback)) return filtered From b665f3037846201e9477fef83a91e7d9b9902457 Mon Sep 17 00:00:00 2001 From: Devasia Joseph Date: Thu, 10 Jul 2025 17:33:52 +0530 Subject: [PATCH 2/2] fix: fixed lint errors --- cms/lib/spectacular.py | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/cms/lib/spectacular.py b/cms/lib/spectacular.py index 0f4364f3b4..0a4ac831d3 100644 --- a/cms/lib/spectacular.py +++ b/cms/lib/spectacular.py @@ -1,4 +1,6 @@ -""" Helper functions for drf-spectacular """ +"""Helper functions for drf-spectacular""" + +import re def cms_api_filter(endpoints): @@ -7,17 +9,15 @@ def cms_api_filter(endpoints): Filter out endpoints that are not part of the CMS API. """ filtered = [] - for (path, path_regex, method, callback) in endpoints: - # Add only paths to the list that are part of the CMS API - if ( - # Don't just replace this with /v1 when switching to a later version of the CMS API. - # That would include some unintended endpoints. - path.startswith("/api/contentstore/v0/xblock") or - path.startswith("/api/contentstore/v0/videos") or - path.startswith("/api/contentstore/v0/video_transcripts") or - path.startswith("/api/contentstore/v0/file_assets") or - path.startswith("/api/contentstore/v0/youtube_transcripts") or - path.startswith("/api/courses/") and "bulk_enable_disable_discussions" in path + CMS_PATH_PATTERN = re.compile( + r"^/api/contentstore/v0/(xblock|videos|video_transcripts|file_assets|youtube_transcripts)" + ) + + for path, path_regex, method, callback in endpoints: + if CMS_PATH_PATTERN.match(path) or ( + path.startswith("/api/courses/") + and "bulk_enable_disable_discussions" in path ): filtered.append((path, path_regex, method, callback)) + return filtered