Skip to content
Merged
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
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
"""
Serializers for v1 contentstore API.
"""
from .home import CourseHomeSerializer
from .course_details import CourseDetailsSerializer
from .course_team import CourseTeamSerializer
from .course_rerun import CourseRerunSerializer
from .grading import CourseGradingModelSerializer, CourseGradingSerializer
from .proctoring import (
LimitedProctoredExamSettingsSerializer,
Expand Down
19 changes: 19 additions & 0 deletions cms/djangoapps/contentstore/rest_api/v1/serializers/common.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
"""
Common API Serializers
"""

from rest_framework import serializers

from openedx.core.lib.api.serializers import CourseKeyField


class CourseCommonSerializer(serializers.Serializer):
"""Serializer for course renders"""
course_key = CourseKeyField()
display_name = serializers.CharField()
lms_link = serializers.CharField()
number = serializers.CharField()
org = serializers.CharField()
rerun_link = serializers.CharField()
run = serializers.CharField()
url = serializers.CharField()
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
"""
API Serializers for course rerun
"""

from rest_framework import serializers


class CourseRerunSerializer(serializers.Serializer):
""" Serializer for course rerun """
allow_unicode_course_id = serializers.BooleanField()
course_creator_status = serializers.CharField()
display_name = serializers.CharField()
number = serializers.CharField()
org = serializers.CharField()
run = serializers.CharField()
62 changes: 62 additions & 0 deletions cms/djangoapps/contentstore/rest_api/v1/serializers/home.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
"""
API Serializers for course home
"""

from rest_framework import serializers

from openedx.core.lib.api.serializers import CourseKeyField

from .common import CourseCommonSerializer


class UnsucceededCourseSerializer(serializers.Serializer):
"""Serializer for unsucceeded course"""
display_name = serializers.CharField()
course_key = CourseKeyField()
org = serializers.CharField()
number = serializers.CharField()
run = serializers.CharField()
is_failed = serializers.BooleanField()
is_in_progress = serializers.BooleanField()
dismiss_link = serializers.CharField()


class LibraryViewSerializer(serializers.Serializer):
"""Serializer for library view"""
display_name = serializers.CharField()
library_key = serializers.CharField()
url = serializers.CharField()
org = serializers.CharField()
number = serializers.CharField()
can_edit = serializers.BooleanField()


class CourseHomeSerializer(serializers.Serializer):
"""Serializer for course home"""
allow_course_reruns = serializers.BooleanField()
allow_to_create_new_org = serializers.BooleanField()
allow_unicode_course_id = serializers.BooleanField()
allowed_organizations = serializers.ListSerializer(
child=serializers.CharField(),
allow_empty=True
)
archived_courses = CourseCommonSerializer(required=False, many=True)
can_create_organizations = serializers.BooleanField()
course_creator_status = serializers.CharField()
courses = CourseCommonSerializer(required=False, many=True)
in_process_course_actions = UnsucceededCourseSerializer(many=True, required=False, allow_null=True)
libraries = LibraryViewSerializer(many=True, required=False, allow_null=True)
libraries_enabled = serializers.BooleanField()
library_authoring_mfe_url = serializers.CharField()
optimization_enabled = serializers.BooleanField()
redirect_to_library_authoring_mfe = serializers.BooleanField()
request_course_creator_url = serializers.CharField()
rerun_creator_status = serializers.BooleanField()
show_new_library_button = serializers.BooleanField()
split_studio_home = serializers.BooleanField()
studio_name = serializers.CharField()
studio_short_name = serializers.CharField()
studio_request_email = serializers.CharField()
tech_support_email = serializers.CharField()
platform_name = serializers.CharField()
user_is_active = serializers.BooleanField()
18 changes: 3 additions & 15 deletions cms/djangoapps/contentstore/rest_api/v1/serializers/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,23 +4,11 @@

from rest_framework import serializers

from openedx.core.lib.api.serializers import CourseKeyField


class PossiblePreRequisiteCourseSerializer(serializers.Serializer):
""" Serializer for possible pre requisite course """
course_key = CourseKeyField()
display_name = serializers.CharField()
lms_link = serializers.CharField()
number = serializers.CharField()
org = serializers.CharField()
rerun_link = serializers.CharField()
run = serializers.CharField()
url = serializers.CharField()
from .common import CourseCommonSerializer


class CourseSettingsSerializer(serializers.Serializer):
""" Serializer for course settings """
"""Serializer for course settings"""
about_page_editable = serializers.BooleanField()
can_show_certificate_available_date_field = serializers.BooleanField()
course_display_name = serializers.CharField()
Expand All @@ -38,7 +26,7 @@ class CourseSettingsSerializer(serializers.Serializer):
marketing_enabled = serializers.BooleanField()
mfe_proctored_exam_settings_url = serializers.CharField(required=False, allow_null=True, allow_blank=True)
platform_name = serializers.CharField()
possible_pre_requisite_courses = PossiblePreRequisiteCourseSerializer(required=False, many=True)
possible_pre_requisite_courses = CourseCommonSerializer(required=False, many=True)
short_description_editable = serializers.BooleanField()
show_min_grade_warning = serializers.BooleanField()
sidebar_html_enabled = serializers.BooleanField()
Expand Down
15 changes: 13 additions & 2 deletions cms/djangoapps/contentstore/rest_api/v1/urls.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
""" Contenstore API v1 URLs. """

from django.urls import path
from django.urls import re_path
from django.conf import settings
from django.urls import re_path, path

from openedx.core.constants import COURSE_ID_PATTERN

from .views import (
CourseDetailsView,
CourseTeamView,
CourseGradingView,
CourseRerunView,
CourseSettingsView,
HomePageView,
ProctoredExamSettingsView,
ProctoringErrorsView,
xblock,
Expand All @@ -25,6 +26,11 @@
VIDEO_ID_PATTERN = r'(?:(?P<edx_video_id>[-\w]+))'

urlpatterns = [
path(
'home',
HomePageView.as_view(),
name="home"
),
re_path(
fr'^proctored_exam_settings/{COURSE_ID_PATTERN}$',
ProctoredExamSettingsView.as_view(),
Expand Down Expand Up @@ -92,4 +98,9 @@
HelpUrlsView.as_view(),
name="help_urls"
),
re_path(
fr'^course_rerun/{COURSE_ID_PATTERN}$',
CourseRerunView.as_view(),
name="course_rerun"
),
]
2 changes: 2 additions & 0 deletions cms/djangoapps/contentstore/rest_api/v1/views/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@
"""
from .course_details import CourseDetailsView
from .course_team import CourseTeamView
from .course_rerun import CourseRerunView
from .grading import CourseGradingView
from .proctoring import ProctoredExamSettingsView, ProctoringErrorsView
from .home import HomePageView
from .settings import CourseSettingsView
from .xblock import XblockView
from .assets import AssetsView
Expand Down
76 changes: 76 additions & 0 deletions cms/djangoapps/contentstore/rest_api/v1/views/course_rerun.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
""" API Views for course rerun """

import edx_api_doc_tools as apidocs
from opaque_keys.edx.keys import CourseKey
from rest_framework.request import Request
from rest_framework.response import Response
from rest_framework.views import APIView

from cms.djangoapps.contentstore.utils import get_course_rerun_context
from cms.djangoapps.contentstore.rest_api.v1.serializers import CourseRerunSerializer
from common.djangoapps.student.roles import GlobalStaff
from openedx.core.lib.api.view_utils import DeveloperErrorViewMixin, verify_course_exists, view_auth_classes
from xmodule.modulestore.django import modulestore


@view_auth_classes(is_authenticated=True)
class CourseRerunView(DeveloperErrorViewMixin, APIView):
"""
View for course rerun.
"""

@apidocs.schema(
parameters=[
apidocs.string_parameter("course_id", apidocs.ParameterLocation.PATH, description="Course ID"),
],
responses={
200: CourseRerunSerializer,
401: "The requester is not authenticated.",
403: "The requester cannot access the specified course.",
404: "The requested course does not exist.",
},
)
@verify_course_exists()
def get(self, request: Request, course_id: str):
"""
Get an object containing course rerun.

**Example Request**

GET /api/contentstore/v1/course_rerun/{course_id}

**Response Values**

If the request is successful, an HTTP 200 "OK" response is returned.

The HTTP 200 response contains a single dict that contains keys that
are the course's rerun.

**Example Response**

```json
{
"allow_unicode_course_id": False,
"course_creator_status": "granted",
"number": "101",
"display_name": "new edx course",
"org": "edx",
"run": "2023",
}
```
"""

if not GlobalStaff().has_user(request.user):
self.permission_denied(request)

course_key = CourseKey.from_string(course_id)
with modulestore().bulk_operations(course_key):
course_block = modulestore().get_course(course_key)
course_rerun_context = get_course_rerun_context(course_key, course_block, request.user)
course_rerun_context.update({
'org': course_key.org,
'number': course_key.course,
'run': course_key.run,
})
serializer = CourseRerunSerializer(course_rerun_context)
return Response(serializer.data)
120 changes: 120 additions & 0 deletions cms/djangoapps/contentstore/rest_api/v1/views/home.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
""" API Views for course home """

import edx_api_doc_tools as apidocs
from django.conf import settings
from rest_framework.request import Request
from rest_framework.response import Response
from rest_framework.views import APIView
from openedx.core.lib.api.view_utils import view_auth_classes

from ....utils import get_home_context
from ..serializers import CourseHomeSerializer


@view_auth_classes(is_authenticated=True)
class HomePageView(APIView):
"""
View for getting all courses and libraries available to the logged in user.
"""
@apidocs.schema(
parameters=[
apidocs.string_parameter(
"org",
apidocs.ParameterLocation.QUERY,
description="Query param to filter by course org",
)],
responses={
200: CourseHomeSerializer,
401: "The requester is not authenticated.",
},
)
def get(self, request: Request):
"""
Get an object containing all courses and libraries on home page.

**Example Request**

GET /api/contentstore/v1/home

**Response Values**

If the request is successful, an HTTP 200 "OK" response is returned.

The HTTP 200 response contains a single dict that contains keys that
are the course's home.

**Example Response**

```json
{
"allow_course_reruns": true,
"allow_to_create_new_org": true,
"allow_unicode_course_id": false,
"allowed_organizations": [],
"archived_courses": [
{
"course_key": "course-v1:edX+P315+2T2023",
"display_name": "Quantum Entanglement",
"lms_link": "//localhost:18000/courses/course-v1:edX+P315+2T2023",
"number": "P315",
"org": "edX",
"rerun_link": "/course_rerun/course-v1:edX+P315+2T2023",
"run": "2T2023"
"url": "/course/course-v1:edX+P315+2T2023"
},
],
"can_create_organizations": true,
"course_creator_status": "granted",
"courses": [
{
"course_key": "course-v1:edX+E2E-101+course",
"display_name": "E2E Test Course",
"lms_link": "//localhost:18000/courses/course-v1:edX+E2E-101+course",
"number": "E2E-101",
"org": "edX",
"rerun_link": "/course_rerun/course-v1:edX+E2E-101+course",
"run": "course",
"url": "/course/course-v1:edX+E2E-101+course"
},
],
"in_process_course_actions": [],
"libraries": [
{
"display_name": "My First Library",
"library_key": "library-v1:new+CPSPR",
"url": "/library/library-v1:new+CPSPR",
"org": "new",
"number": "CPSPR",
"can_edit": true
}
],
"libraries_enabled": true,
"library_authoring_mfe_url": "//localhost:3001/course/course-v1:edX+P315+2T2023",
"optimization_enabled": true,
"redirect_to_library_authoring_mfe": false,
"request_course_creator_url": "/request_course_creator",
"rerun_creator_status": true,
"show_new_library_button": true,
"split_studio_home": false,
"studio_name": "Studio",
"studio_short_name": "Studio",
"studio_request_email": "",
"tech_support_email": "technical@example.com",
"platform_name": "Your Platform Name Here"
"user_is_active": true,
}
```
"""

home_context = get_home_context(request)
home_context.update({
'allow_to_create_new_org': settings.FEATURES.get('ENABLE_CREATOR_GROUP', True) and request.user.is_staff,
'studio_name': settings.STUDIO_NAME,
'studio_short_name': settings.STUDIO_SHORT_NAME,
'studio_request_email': settings.FEATURES.get('STUDIO_REQUEST_EMAIL', ''),
'tech_support_email': settings.TECH_SUPPORT_EMAIL,
'platform_name': settings.PLATFORM_NAME,
'user_is_active': request.user.is_active,
})
serializer = CourseHomeSerializer(home_context)
return Response(serializer.data)
Loading