Skip to content

Commit

Permalink
feat: Create DRF for course settings and course details views out of …
Browse files Browse the repository at this point in the history
…current Django views openedx#32397 (#558)

* revert: Removing the details_settings API


---------

Co-authored-by: ruzniaievdm <[email protected]>
  • Loading branch information
pkulkark and ruzniaievdm authored Sep 18, 2023
1 parent d5e16f5 commit 6e79a53
Show file tree
Hide file tree
Showing 13 changed files with 717 additions and 345 deletions.

This file was deleted.

13 changes: 1 addition & 12 deletions cms/djangoapps/contentstore/rest_api/v0/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,7 @@
from django.urls import re_path

from openedx.core.constants import COURSE_ID_PATTERN
from .views import (
AdvancedCourseSettingsView,
CourseDetailsSettingsView,
CourseTabSettingsView,
CourseTabListView,
CourseTabReorderView
)
from .views import AdvancedCourseSettingsView, CourseTabSettingsView, CourseTabListView, CourseTabReorderView

app_name = "v0"

Expand All @@ -34,9 +28,4 @@
CourseTabReorderView.as_view(),
name="course_tab_reorder",
),
re_path(
fr"^details_settings/{COURSE_ID_PATTERN}$",
CourseDetailsSettingsView.as_view(),
name="course_details_settings",
),
]
1 change: 0 additions & 1 deletion cms/djangoapps/contentstore/rest_api/v0/views/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,4 @@
Views for v0 contentstore API.
"""
from .advanced_settings import AdvancedCourseSettingsView
from .details_settings import CourseDetailsSettingsView
from .tabs import CourseTabSettingsView, CourseTabListView, CourseTabReorderView
69 changes: 0 additions & 69 deletions cms/djangoapps/contentstore/rest_api/v0/views/details_settings.py

This file was deleted.

90 changes: 90 additions & 0 deletions cms/djangoapps/contentstore/rest_api/v1/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

from rest_framework import serializers

from openedx.core.lib.api.serializers import CourseKeyField
from xmodule.course_block import get_available_providers


Expand Down Expand Up @@ -64,3 +65,92 @@ class CourseGradingSerializer(serializers.Serializer):
default_grade_designations = serializers.ListSerializer(
child=serializers.CharField()
)


class InstructorInfoSerializer(serializers.Serializer):
""" Serializer for instructor info """
name = serializers.CharField(allow_blank=True)
title = serializers.CharField(allow_blank=True)
organization = serializers.CharField(allow_blank=True)
image = serializers.CharField(allow_blank=True)
bio = serializers.CharField(allow_blank=True)


class InstructorsSerializer(serializers.Serializer):
""" Serializer for instructors """
instructors = InstructorInfoSerializer(many=True, allow_empty=True)


class CourseDetailsSerializer(serializers.Serializer):
""" Serializer for course details """
about_sidebar_html = serializers.CharField(allow_null=True, allow_blank=True)
banner_image_name = serializers.CharField(allow_blank=True)
banner_image_asset_path = serializers.CharField()
certificate_available_date = serializers.DateTimeField()
certificates_display_behavior = serializers.CharField(allow_null=True)
course_id = serializers.CharField()
course_image_asset_path = serializers.CharField(allow_blank=True)
course_image_name = serializers.CharField(allow_blank=True)
description = serializers.CharField(allow_blank=True)
duration = serializers.CharField(allow_blank=True)
effort = serializers.CharField(allow_null=True, allow_blank=True)
end_date = serializers.DateTimeField(allow_null=True)
enrollment_end = serializers.DateTimeField(allow_null=True)
enrollment_start = serializers.DateTimeField(allow_null=True)
entrance_exam_enabled = serializers.CharField(allow_blank=True)
entrance_exam_id = serializers.CharField(allow_blank=True)
entrance_exam_minimum_score_pct = serializers.CharField(allow_blank=True)
instructor_info = InstructorsSerializer()
intro_video = serializers.CharField(allow_null=True)
language = serializers.CharField(allow_null=True)
learning_info = serializers.ListField(child=serializers.CharField(allow_blank=True))
license = serializers.CharField(allow_null=True)
org = serializers.CharField()
overview = serializers.CharField(allow_blank=True)
pre_requisite_courses = serializers.ListField(child=CourseKeyField())
run = serializers.CharField()
self_paced = serializers.BooleanField()
short_description = serializers.CharField(allow_blank=True)
start_date = serializers.DateTimeField()
subtitle = serializers.CharField(allow_blank=True)
syllabus = serializers.CharField(allow_null=True)
title = serializers.CharField(allow_blank=True)
video_thumbnail_image_asset_path = serializers.CharField()
video_thumbnail_image_name = serializers.CharField(allow_blank=True)


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()


class CourseSettingsSerializer(serializers.Serializer):
""" Serializer for course settings """
about_page_editable = serializers.BooleanField()
can_show_certificate_available_date_field = serializers.BooleanField()
course_display_name = serializers.CharField()
course_display_name_with_default = serializers.CharField()
credit_eligibility_enabled = serializers.BooleanField()
credit_requirements = serializers.DictField(required=False)
enable_extended_course_details = serializers.BooleanField()
enrollment_end_editable = serializers.BooleanField()
is_credit_course = serializers.BooleanField()
is_entrance_exams_enabled = serializers.BooleanField()
is_prerequisite_courses_enabled = serializers.BooleanField()
language_options = serializers.ListField(child=serializers.ListField(child=serializers.CharField()))
lms_link_for_about_page = serializers.URLField()
marketing_enabled = serializers.BooleanField()
mfe_proctored_exam_settings_url = serializers.CharField(required=False, allow_null=True, allow_blank=True)
possible_pre_requisite_courses = PossiblePreRequisiteCourseSerializer(required=False, many=True)
short_description_editable = serializers.BooleanField()
show_min_grade_warning = serializers.BooleanField()
sidebar_html_enabled = serializers.BooleanField()
upgrade_deadline = serializers.DateTimeField(allow_null=True)
use_v2_cert_display_settings = serializers.BooleanField()
108 changes: 108 additions & 0 deletions cms/djangoapps/contentstore/rest_api/v1/tests/test_course_details.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
"""
Unit tests for course details views.
"""
import json
from unittest.mock import patch

import ddt
from django.urls import reverse
from rest_framework import status

from cms.djangoapps.contentstore.tests.utils import CourseTestCase

from ..mixins import PermissionAccessMixin


@ddt.ddt
class CourseDetailsViewTest(CourseTestCase, PermissionAccessMixin):
"""
Tests for CourseDetailsView.
"""

def setUp(self):
super().setUp()
self.url = reverse(
'cms.djangoapps.contentstore:v1:course_details',
kwargs={"course_id": self.course.id},
)

def test_put_permissions_unauthenticated(self):
"""
Test that an error is returned in the absence of auth credentials.
"""
self.client.logout()
response = self.client.put(self.url)
error = self.get_and_check_developer_response(response)
self.assertEqual(error, "Authentication credentials were not provided.")
self.assertEqual(response.status_code, status.HTTP_401_UNAUTHORIZED)

def test_put_permissions_unauthorized(self):
"""
Test that an error is returned if the user is unauthorised.
"""
client, _ = self.create_non_staff_authed_user_client()
response = client.put(self.url)
error = self.get_and_check_developer_response(response)
self.assertEqual(error, "You do not have permission to perform this action.")
self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)

@patch.dict("django.conf.settings.FEATURES", {'ENABLE_PREREQUISITE_COURSES': True})
def test_put_invalid_pre_requisite_course(self):
pre_requisite_course_keys = [str(self.course.id), 'invalid_key']
request_data = {"pre_requisite_courses": pre_requisite_course_keys}
response = self.client.put(path=self.url, data=json.dumps(request_data), content_type="application/json")
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
self.assertEqual(response.json()['error'], 'Invalid prerequisite course key')

def test_put_course_details(self):
request_data = {
"about_sidebar_html": "",
"banner_image_name": "images_course_image.jpg",
"banner_image_asset_path": "/asset-v1:edX+E2E-101+course+type@asset+block@images_course_image.jpg",
"certificate_available_date": "2029-01-02T00:00:00Z",
"certificates_display_behavior": "end",
"course_id": "E2E-101",
"course_image_asset_path": "/static/studio/images/pencils.jpg",
"course_image_name": "bar_course_image_name",
"description": "foo_description",
"duration": "",
"effort": None,
"end_date": "2023-08-01T01:30:00Z",
"enrollment_end": "2023-05-30T01:00:00Z",
"enrollment_start": "2023-05-29T01:00:00Z",
"entrance_exam_enabled": "",
"entrance_exam_id": "",
"entrance_exam_minimum_score_pct": "50",
"intro_video": None,
"language": "creative-commons: ver=4.0 BY NC ND",
"learning_info": [
"foo",
"bar"
],
"license": "creative-commons: ver=4.0 BY NC ND",
"org": "edX",
"overview": "<section class=\"about\"></section>",
"pre_requisite_courses": [],
"run": "course",
"self_paced": None,
"short_description": "",
"start_date": "2023-06-01T01:30:00Z",
"subtitle": "",
"syllabus": None,
"title": "",
"video_thumbnail_image_asset_path": "/asset-v1:edX+E2E-101+course+type@asset+block@images_course_image.jpg",
"video_thumbnail_image_name": "images_course_image.jpg",
"instructor_info": {
"instructors": [
{
"name": "foo bar",
"title": "title",
"organization": "org",
"image": "image",
"bio": ""
}
]
},
}
response = self.client.put(path=self.url, data=json.dumps(request_data), content_type="application/json")
self.assertEqual(response.status_code, status.HTTP_200_OK)
Loading

0 comments on commit 6e79a53

Please sign in to comment.