Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,8 @@ SWAGGER = docs/lms-openapi.yaml
docs: swagger guides technical-docs ## build the documentation for this repository
$(MAKE) -C docs html

swagger: ## generate the swagger.yaml file
DJANGO_SETTINGS_MODULE=docs.docs_settings uv run python manage.py lms generate_swagger --generator-class=edx_api_doc_tools.ApiSchemaGenerator -o $(SWAGGER)
swagger: ## generate the OpenAPI schema file
DJANGO_SETTINGS_MODULE=docs.docs_settings uv run python manage.py lms spectacular --file $(SWAGGER)

extract_translations: ## extract localizable strings from sources
uv run i18n_tool extract --no-segment -v
Expand Down
12 changes: 6 additions & 6 deletions cms/djangoapps/contentstore/api/views/course_validation.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import logging

import dateutil
import edx_api_doc_tools as apidocs
from drf_spectacular.utils import OpenApiResponse, extend_schema
from edx_rest_framework_extensions.auth.jwt.authentication import JwtAuthentication
from edx_rest_framework_extensions.auth.session.authentication import SessionAuthenticationAllowInactiveUser
from openedx_authz.constants.permissions import COURSES_VIEW_COURSE
Expand Down Expand Up @@ -378,10 +378,10 @@ class CourseLegacyLibraryContentMigratorView(DeveloperErrorViewMixin, StatusView
)
serializer_class = StatusSerializerWithUuid

@apidocs.schema(
@extend_schema(
responses={
200: CourseLegacyLibraryContentSerializer(many=True),
401: "The requester is not authenticated.",
401: OpenApiResponse(description="The requester is not authenticated."),
},
)
@authz_permission_required(COURSES_VIEW_COURSE.identifier, LegacyAuthoringPermission.WRITE)
Expand All @@ -393,10 +393,10 @@ def list(self, _, course_key): # pylint: disable=arguments-differ
serializer = CourseLegacyLibraryContentSerializer(blocks, many=True)
return Response(serializer.data)

@apidocs.schema(
@extend_schema(
responses={
200: "In case of success, a 200.",
401: "The requester is not authenticated.",
200: OpenApiResponse(description="In case of success, a 200."),
401: OpenApiResponse(description="The requester is not authenticated."),
},
)
@course_author_access_required
Expand Down
35 changes: 19 additions & 16 deletions cms/djangoapps/contentstore/rest_api/v0/views/advanced_settings.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
""" API Views for course advanced settings """

import edx_api_doc_tools as apidocs
from django import forms
from drf_spectacular.types import OpenApiTypes
from drf_spectacular.utils import OpenApiParameter, OpenApiResponse, extend_schema
from opaque_keys.edx.keys import CourseKey
from rest_framework.exceptions import ValidationError
from rest_framework.request import Request
Expand Down Expand Up @@ -36,25 +37,27 @@ def clean_filter_fields(self):
return set(self.cleaned_data['filter_fields'].split(','))
return None

@apidocs.schema(
@extend_schema(
parameters=[
apidocs.string_parameter("course_id", apidocs.ParameterLocation.PATH, description="Course ID"),
apidocs.string_parameter(
OpenApiParameter("course_id", OpenApiTypes.STR, OpenApiParameter.PATH, description="Course ID"),
OpenApiParameter(
"filter_fields",
apidocs.ParameterLocation.QUERY,
OpenApiTypes.STR,
OpenApiParameter.QUERY,
description="Comma separated list of fields to filter",
),
apidocs.string_parameter(
OpenApiParameter(
"fetch_all",
apidocs.ParameterLocation.QUERY,
OpenApiTypes.STR,
OpenApiParameter.QUERY,
description="Specifies whether to fetch all settings or only enabled ones",
),
],
responses={
200: CourseAdvancedSettingsSerializer,
401: "The requester is not authenticated.",
403: "The requester cannot access the specified course.",
404: "The requested course does not exist.",
401: OpenApiResponse(description="The requester is not authenticated."),
403: OpenApiResponse(description="The requester cannot access the specified course."),
404: OpenApiResponse(description="The requested course does not exist."),
},
)
@verify_course_exists()
Expand Down Expand Up @@ -130,14 +133,14 @@ def get(self, request: Request, course_id: str):
filter_fields=filter_query_data.cleaned_data['filter_fields'],
))

@apidocs.schema(
body=CourseAdvancedSettingsSerializer,
parameters=[apidocs.string_parameter("course_id", apidocs.ParameterLocation.PATH, description="Course ID")],
@extend_schema(
request=CourseAdvancedSettingsSerializer,
parameters=[OpenApiParameter("course_id", OpenApiTypes.STR, OpenApiParameter.PATH, description="Course ID")],
responses={
200: CourseAdvancedSettingsSerializer,
401: "The requester is not authenticated.",
403: "The requester cannot access the specified course.",
404: "The requested course does not exist.",
401: OpenApiResponse(description="The requester is not authenticated."),
403: OpenApiResponse(description="The requester cannot access the specified course."),
404: OpenApiResponse(description="The requested course does not exist."),
},
)
@verify_course_exists()
Expand Down
10 changes: 5 additions & 5 deletions cms/djangoapps/contentstore/rest_api/v0/views/api_heartbeat.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
""" View For Getting the Status of The Authoring API """
import edx_api_doc_tools as apidocs
from drf_spectacular.utils import OpenApiResponse, extend_schema
from rest_framework import status
from rest_framework.request import Request
from rest_framework.response import Response
Expand All @@ -13,12 +13,12 @@ class APIHeartBeatView(DeveloperErrorViewMixin, APIView):
View for getting the Authoring API's status
"""

@apidocs.schema(
@extend_schema(
parameters=[],
responses={
200: "The API is online",
401: "The requester is not authenticated.",
403: "The API is not availible",
200: OpenApiResponse(description="The API is online"),
401: OpenApiResponse(description="The requester is not authenticated."),
403: OpenApiResponse(description="The API is not availible"),
},
)
@view_auth_classes(is_authenticated=True)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
""" API Views for course advanced settings """

import edx_api_doc_tools as apidocs
from drf_spectacular.types import OpenApiTypes
from drf_spectacular.utils import OpenApiParameter, OpenApiResponse, extend_schema
from opaque_keys.edx.keys import CourseKey
from openedx_authz.constants.permissions import COURSES_EDIT_GRADING_SETTINGS
from rest_framework.request import Request
Expand All @@ -21,16 +22,16 @@ class AuthoringGradingView(DeveloperErrorViewMixin, APIView):
"""
View for getting and setting the advanced settings for a course.
"""
@apidocs.schema(
body=CourseGradingModelSerializer,
@extend_schema(
request=CourseGradingModelSerializer,
parameters=[
apidocs.string_parameter("course_id", apidocs.ParameterLocation.PATH, description="Course ID"),
OpenApiParameter("course_id", OpenApiTypes.STR, OpenApiParameter.PATH, description="Course ID"),
],
responses={
200: CourseGradingModelSerializer,
401: "The requester is not authenticated.",
403: "The requester cannot access the specified course.",
404: "The requested course does not exist.",
401: OpenApiResponse(description="The requester is not authenticated."),
403: OpenApiResponse(description="The requester cannot access the specified course."),
404: OpenApiResponse(description="The requested course does not exist."),
},
)
@verify_course_exists()
Expand Down
59 changes: 30 additions & 29 deletions cms/djangoapps/contentstore/rest_api/v0/views/course_optimizer.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
"""API Views for Course Optimizer."""

import edx_api_doc_tools as apidocs
from drf_spectacular.types import OpenApiTypes
from drf_spectacular.utils import OpenApiParameter, OpenApiResponse, extend_schema
from opaque_keys import InvalidKeyError
from opaque_keys.edx.keys import CourseKey
from rest_framework import status
Expand Down Expand Up @@ -31,15 +32,15 @@ class LinkCheckView(DeveloperErrorViewMixin, APIView):
"""
View for queueing a celery task to scan a course for broken links.
"""
@apidocs.schema(
@extend_schema(
parameters=[
apidocs.string_parameter("course_id", apidocs.ParameterLocation.PATH, description="Course ID"),
OpenApiParameter("course_id", OpenApiTypes.STR, OpenApiParameter.PATH, description="Course ID"),
],
responses={
200: "Celery task queued.",
401: "The requester is not authenticated.",
403: "The requester cannot access the specified course.",
404: "The requested course does not exist.",
200: OpenApiResponse(description="Celery task queued."),
401: OpenApiResponse(description="The requester is not authenticated."),
403: OpenApiResponse(description="The requester cannot access the specified course."),
404: OpenApiResponse(description="The requested course does not exist."),
},
)
@verify_course_exists()
Expand Down Expand Up @@ -70,15 +71,15 @@ class LinkCheckStatusView(DeveloperErrorViewMixin, APIView):
"""
View for checking the status of the celery task and returning the results.
"""
@apidocs.schema(
@extend_schema(
parameters=[
apidocs.string_parameter("course_id", apidocs.ParameterLocation.PATH, description="Course ID"),
OpenApiParameter("course_id", OpenApiTypes.STR, OpenApiParameter.PATH, description="Course ID"),
],
responses={
200: "OK",
401: "The requester is not authenticated.",
403: "The requester cannot access the specified course.",
404: "The requested course does not exist.",
200: OpenApiResponse(description="OK"),
401: OpenApiResponse(description="The requester is not authenticated."),
403: OpenApiResponse(description="The requester cannot access the specified course."),
404: OpenApiResponse(description="The requested course does not exist."),
},
)
def get(self, request: Request, course_id: str):
Expand Down Expand Up @@ -222,19 +223,19 @@ class RerunLinkUpdateView(DeveloperErrorViewMixin, APIView):
View for queueing a celery task to update course links to the latest re-run.
"""

@apidocs.schema(
@extend_schema(
parameters=[
apidocs.string_parameter(
"course_id", apidocs.ParameterLocation.PATH, description="Course ID"
OpenApiParameter(
"course_id", OpenApiTypes.STR, OpenApiParameter.PATH, description="Course ID"
)
],
body=CourseRerunLinkUpdateRequestSerializer,
request=CourseRerunLinkUpdateRequestSerializer,
responses={
200: "Celery task queued.",
400: "Bad request - invalid action or missing data.",
401: "The requester is not authenticated.",
403: "The requester cannot access the specified course.",
404: "The requested course does not exist.",
200: OpenApiResponse(description="Celery task queued."),
400: OpenApiResponse(description="Bad request - invalid action or missing data."),
401: OpenApiResponse(description="The requester is not authenticated."),
403: OpenApiResponse(description="The requester cannot access the specified course."),
404: OpenApiResponse(description="The requested course does not exist."),
},
)
@verify_course_exists()
Expand Down Expand Up @@ -326,17 +327,17 @@ class RerunLinkUpdateStatusView(DeveloperErrorViewMixin, APIView):
View for checking the status of the course link update task and returning the results.
"""

@apidocs.schema(
@extend_schema(
parameters=[
apidocs.string_parameter(
"course_id", apidocs.ParameterLocation.PATH, description="Course ID"
OpenApiParameter(
"course_id", OpenApiTypes.STR, OpenApiParameter.PATH, description="Course ID"
),
],
responses={
200: "OK",
401: "The requester is not authenticated.",
403: "The requester cannot access the specified course.",
404: "The requested course does not exist.",
200: OpenApiResponse(description="OK"),
401: OpenApiResponse(description="The requester is not authenticated."),
403: OpenApiResponse(description="The requester cannot access the specified course."),
404: OpenApiResponse(description="The requested course does not exist."),
},
)
def get(self, request: Request, course_id: str):
Expand Down
45 changes: 23 additions & 22 deletions cms/djangoapps/contentstore/rest_api/v0/views/tabs.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
""" API Views for course tabs """

import edx_api_doc_tools as apidocs
from django.utils.translation import gettext_lazy as _
from drf_spectacular.types import OpenApiTypes
from drf_spectacular.utils import OpenApiParameter, OpenApiResponse, extend_schema
from opaque_keys.edx.keys import CourseKey
from openedx_authz.constants.permissions import (
COURSES_MANAGE_PAGES_AND_RESOURCES,
Expand All @@ -28,13 +29,13 @@ class CourseTabListView(DeveloperErrorViewMixin, APIView):
API view to list course tabs.
"""

@apidocs.schema(
parameters=[apidocs.string_parameter("course_id", apidocs.ParameterLocation.PATH, description="Course ID")],
@extend_schema(
parameters=[OpenApiParameter("course_id", OpenApiTypes.STR, OpenApiParameter.PATH, description="Course ID")],
responses={
200: CourseTabSerializer,
401: "The requester is not authenticated.",
403: "The requester cannot access the specified course.",
404: "The requested course does not exist.",
401: OpenApiResponse(description="The requester is not authenticated."),
403: OpenApiResponse(description="The requester cannot access the specified course."),
404: OpenApiResponse(description="The requested course does not exist."),
},
)
@verify_course_exists()
Expand Down Expand Up @@ -119,18 +120,18 @@ def handle_exception(self, exc):
return self._make_error_response(400, str(exc))
return super().handle_exception(exc)

@apidocs.schema(
body=CourseTabUpdateSerializer(help_text=_("Change the visibility of tabs in a course.")),
@extend_schema(
request=CourseTabUpdateSerializer(help_text=_("Change the visibility of tabs in a course.")),
parameters=[
apidocs.string_parameter("course_id", apidocs.ParameterLocation.PATH, description="Course ID"),
apidocs.string_parameter("tab_id", apidocs.ParameterLocation.QUERY, description="Tab ID"),
apidocs.string_parameter("tab_location", apidocs.ParameterLocation.QUERY, description="Tab usage key"),
OpenApiParameter("course_id", OpenApiTypes.STR, OpenApiParameter.PATH, description="Course ID"),
OpenApiParameter("tab_id", OpenApiTypes.STR, OpenApiParameter.QUERY, description="Tab ID"),
OpenApiParameter("tab_location", OpenApiTypes.STR, OpenApiParameter.QUERY, description="Tab usage key"),
],
responses={
204: "In case of success, a 204 is returned with no content.",
401: "The requester is not authenticated.",
403: "The requester cannot access the specified course.",
404: "The requested course does not exist.",
204: OpenApiResponse(description="In case of success, a 204 is returned with no content."),
401: OpenApiResponse(description="The requester is not authenticated."),
403: OpenApiResponse(description="The requester cannot access the specified course."),
404: OpenApiResponse(description="The requested course does not exist."),
},
)
@verify_course_exists()
Expand Down Expand Up @@ -200,16 +201,16 @@ def handle_exception(self, exc: Exception) -> Response:
return self._make_error_response(400, str(exc))
return super().handle_exception(exc)

@apidocs.schema(
body=TabIDLocatorSerializer(many=True),
@extend_schema(
request=TabIDLocatorSerializer(many=True),
parameters=[
apidocs.string_parameter("course_id", apidocs.ParameterLocation.PATH, description="Course ID"),
OpenApiParameter("course_id", OpenApiTypes.STR, OpenApiParameter.PATH, description="Course ID"),
],
responses={
204: "In case of success, a 204 is returned with no content.",
401: "The requester is not authenticated.",
403: "The requester cannot access the specified course.",
404: "The requested course does not exist.",
204: OpenApiResponse(description="In case of success, a 204 is returned with no content."),
401: OpenApiResponse(description="The requester is not authenticated."),
403: OpenApiResponse(description="The requester cannot access the specified course."),
404: OpenApiResponse(description="The requested course does not exist."),
},
)
@verify_course_exists()
Expand Down
15 changes: 8 additions & 7 deletions cms/djangoapps/contentstore/rest_api/v1/views/certificates.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
""" API Views for course certificates """

import edx_api_doc_tools as apidocs
from drf_spectacular.types import OpenApiTypes
from drf_spectacular.utils import OpenApiParameter, OpenApiResponse, extend_schema
from opaque_keys.edx.keys import CourseKey
from openedx_authz.constants.permissions import COURSES_MANAGE_CERTIFICATES, COURSES_VIEW_CERTIFICATES
from rest_framework.request import Request
Expand All @@ -21,17 +22,17 @@ class CourseCertificatesView(DeveloperErrorViewMixin, APIView):
View for course certificate page.
"""

@apidocs.schema(
@extend_schema(
parameters=[
apidocs.string_parameter(
"course_id", apidocs.ParameterLocation.PATH, description="Course ID"
OpenApiParameter(
"course_id", OpenApiTypes.STR, OpenApiParameter.PATH, description="Course ID"
),
],
responses={
200: CourseCertificatesSerializer,
401: "The requester is not authenticated.",
403: "The requester cannot access the specified course.",
404: "The requested course does not exist.",
401: OpenApiResponse(description="The requester is not authenticated."),
403: OpenApiResponse(description="The requester cannot access the specified course."),
404: OpenApiResponse(description="The requested course does not exist."),
},
)
@verify_course_exists()
Expand Down
Loading
Loading