diff --git a/cms/djangoapps/contentstore/rest_api/v1/serializers/__init__.py b/cms/djangoapps/contentstore/rest_api/v1/serializers/__init__.py index c60d33bc4448..2dc803d47bf2 100644 --- a/cms/djangoapps/contentstore/rest_api/v1/serializers/__init__.py +++ b/cms/djangoapps/contentstore/rest_api/v1/serializers/__init__.py @@ -1,10 +1,8 @@ """ 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, diff --git a/cms/djangoapps/contentstore/rest_api/v1/serializers/common.py b/cms/djangoapps/contentstore/rest_api/v1/serializers/common.py deleted file mode 100644 index bc2f8d2da6a2..000000000000 --- a/cms/djangoapps/contentstore/rest_api/v1/serializers/common.py +++ /dev/null @@ -1,19 +0,0 @@ -""" -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() diff --git a/cms/djangoapps/contentstore/rest_api/v1/serializers/course_rerun.py b/cms/djangoapps/contentstore/rest_api/v1/serializers/course_rerun.py deleted file mode 100644 index 317468a87a6b..000000000000 --- a/cms/djangoapps/contentstore/rest_api/v1/serializers/course_rerun.py +++ /dev/null @@ -1,15 +0,0 @@ -""" -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() diff --git a/cms/djangoapps/contentstore/rest_api/v1/serializers/home.py b/cms/djangoapps/contentstore/rest_api/v1/serializers/home.py deleted file mode 100644 index 5abcda673aa7..000000000000 --- a/cms/djangoapps/contentstore/rest_api/v1/serializers/home.py +++ /dev/null @@ -1,62 +0,0 @@ -""" -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() diff --git a/cms/djangoapps/contentstore/rest_api/v1/serializers/settings.py b/cms/djangoapps/contentstore/rest_api/v1/serializers/settings.py index 742d198a7ad4..feec2606205e 100644 --- a/cms/djangoapps/contentstore/rest_api/v1/serializers/settings.py +++ b/cms/djangoapps/contentstore/rest_api/v1/serializers/settings.py @@ -4,11 +4,23 @@ from rest_framework import serializers -from .common import CourseCommonSerializer +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() 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() @@ -26,7 +38,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 = CourseCommonSerializer(required=False, many=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() diff --git a/cms/djangoapps/contentstore/rest_api/v1/urls.py b/cms/djangoapps/contentstore/rest_api/v1/urls.py index 286424f5e1fd..13fec10ddc92 100644 --- a/cms/djangoapps/contentstore/rest_api/v1/urls.py +++ b/cms/djangoapps/contentstore/rest_api/v1/urls.py @@ -1,7 +1,8 @@ """ 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 @@ -9,9 +10,7 @@ CourseDetailsView, CourseTeamView, CourseGradingView, - CourseRerunView, CourseSettingsView, - HomePageView, ProctoredExamSettingsView, ProctoringErrorsView, xblock, @@ -26,11 +25,6 @@ VIDEO_ID_PATTERN = r'(?:(?P[-\w]+))' urlpatterns = [ - path( - 'home', - HomePageView.as_view(), - name="home" - ), re_path( fr'^proctored_exam_settings/{COURSE_ID_PATTERN}$', ProctoredExamSettingsView.as_view(), @@ -98,9 +92,4 @@ HelpUrlsView.as_view(), name="help_urls" ), - re_path( - fr'^course_rerun/{COURSE_ID_PATTERN}$', - CourseRerunView.as_view(), - name="course_rerun" - ), ] diff --git a/cms/djangoapps/contentstore/rest_api/v1/views/__init__.py b/cms/djangoapps/contentstore/rest_api/v1/views/__init__.py index dc5f1f77c3de..044e4653e05d 100644 --- a/cms/djangoapps/contentstore/rest_api/v1/views/__init__.py +++ b/cms/djangoapps/contentstore/rest_api/v1/views/__init__.py @@ -3,10 +3,8 @@ """ 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 diff --git a/cms/djangoapps/contentstore/rest_api/v1/views/course_rerun.py b/cms/djangoapps/contentstore/rest_api/v1/views/course_rerun.py deleted file mode 100644 index fe39858c5380..000000000000 --- a/cms/djangoapps/contentstore/rest_api/v1/views/course_rerun.py +++ /dev/null @@ -1,76 +0,0 @@ -""" 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) diff --git a/cms/djangoapps/contentstore/rest_api/v1/views/home.py b/cms/djangoapps/contentstore/rest_api/v1/views/home.py deleted file mode 100644 index ea0724e8e2df..000000000000 --- a/cms/djangoapps/contentstore/rest_api/v1/views/home.py +++ /dev/null @@ -1,120 +0,0 @@ -""" 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) diff --git a/cms/djangoapps/contentstore/rest_api/v1/views/tests/test_course_rerun.py b/cms/djangoapps/contentstore/rest_api/v1/views/tests/test_course_rerun.py deleted file mode 100644 index e25904ad465f..000000000000 --- a/cms/djangoapps/contentstore/rest_api/v1/views/tests/test_course_rerun.py +++ /dev/null @@ -1,36 +0,0 @@ -""" -Unit tests for course rerun. -""" -from django.urls import reverse -from rest_framework import status - -from cms.djangoapps.contentstore.tests.utils import CourseTestCase -from cms.djangoapps.contentstore.rest_api.v1.mixins import PermissionAccessMixin - - -class CourseRerunViewTest(CourseTestCase, PermissionAccessMixin): - """ - Tests for CourseRerunView. - """ - - def setUp(self): - super().setUp() - self.url = reverse( - "cms.djangoapps.contentstore:v1:course_rerun", - kwargs={"course_id": self.course.id}, - ) - - def test_course_rerun_response(self): - """Check successful response content""" - response = self.client.get(self.url) - expected_response = { - "allow_unicode_course_id": False, - "course_creator_status": "granted", - "display_name": self.course.display_name, - "number": self.course.id.course, - "org": self.course.id.org, - "run": self.course.id.run, - } - - self.assertEqual(response.status_code, status.HTTP_200_OK) - self.assertDictEqual(expected_response, response.data) diff --git a/cms/djangoapps/contentstore/rest_api/v1/views/tests/test_home.py b/cms/djangoapps/contentstore/rest_api/v1/views/tests/test_home.py deleted file mode 100644 index 549c40328cd2..000000000000 --- a/cms/djangoapps/contentstore/rest_api/v1/views/tests/test_home.py +++ /dev/null @@ -1,87 +0,0 @@ -""" -Unit tests for home page view. -""" -import ddt -from django.conf import settings -from django.urls import reverse -from edx_toggles.toggles.testutils import override_waffle_switch -from rest_framework import status - -from cms.djangoapps.contentstore.tests.utils import CourseTestCase -from cms.djangoapps.contentstore.views.course import ENABLE_GLOBAL_STAFF_OPTIMIZATION -from openedx.core.djangoapps.content.course_overviews.tests.factories import CourseOverviewFactory -from xmodule.modulestore.tests.factories import CourseFactory - - -@ddt.ddt -class HomePageViewTest(CourseTestCase): - """ - Tests for HomePageView. - """ - - def setUp(self): - super().setUp() - self.url = reverse("cms.djangoapps.contentstore:v1:home") - - def test_home_page_response(self): - """Check successful response content""" - response = self.client.get(self.url) - expected_response = { - "allow_course_reruns": True, - "allow_to_create_new_org": False, - "allow_unicode_course_id": False, - "allowed_organizations": [], - "archived_courses": [], - "can_create_organizations": True, - "course_creator_status": "granted", - "courses": [{ - "course_key": str(self.course.id), - "display_name": self.course.display_name, - "lms_link": None, - "number": self.course.number, - "org": self.course.org, - "rerun_link": None, - "run": self.course.id.run, - "url": None, - }], - "in_process_course_actions": [], - "libraries": [], - "libraries_enabled": True, - "library_authoring_mfe_url": settings.LIBRARY_AUTHORING_MICROFRONTEND_URL, - "optimization_enabled": False, - "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": settings.STUDIO_NAME, - "studio_short_name": settings.STUDIO_SHORT_NAME, - "studio_request_email": "", - "tech_support_email": "technical@example.com", - "platform_name": settings.PLATFORM_NAME, - "user_is_active": True, - } - - self.assertEqual(response.status_code, status.HTTP_200_OK) - self.assertDictEqual(expected_response, response.data) - - @override_waffle_switch(ENABLE_GLOBAL_STAFF_OPTIMIZATION, True) - def test_org_query_if_passed(self): - """Test home page when org filter passed as a query param""" - foo_course = self.store.make_course_key('foo-org', 'bar-number', 'baz-run') - test_course = CourseFactory.create( - org=foo_course.org, - number=foo_course.course, - run=foo_course.run - ) - CourseOverviewFactory.create(id=test_course.id, org='foo-org') - response = self.client.get(self.url, {"org": "foo-org"}) - self.assertEqual(len(response.data['courses']), 1) - self.assertEqual(response.status_code, status.HTTP_200_OK) - - @override_waffle_switch(ENABLE_GLOBAL_STAFF_OPTIMIZATION, True) - def test_org_query_if_empty(self): - """Test home page with an empty org query param""" - response = self.client.get(self.url) - self.assertEqual(len(response.data['courses']), 0) - self.assertEqual(response.status_code, status.HTTP_200_OK) diff --git a/cms/djangoapps/contentstore/utils.py b/cms/djangoapps/contentstore/utils.py index 97b70e828ce2..321b97be6f78 100644 --- a/cms/djangoapps/contentstore/utils.py +++ b/cms/djangoapps/contentstore/utils.py @@ -24,7 +24,6 @@ from xblock.fields import Scope from cms.djangoapps.contentstore.toggles import exam_setting_view_enabled -from common.djangoapps.course_action_state.models import CourseRerunUIStateManager from common.djangoapps.course_modes.models import CourseMode from common.djangoapps.edxmako.services import MakoService from common.djangoapps.student import auth @@ -60,7 +59,6 @@ from openedx.features.content_type_gating.partitions import CONTENT_TYPE_GATING_SCHEME from openedx.features.course_experience.waffle import ENABLE_COURSE_ABOUT_SIDEBAR_HTML from cms.djangoapps.contentstore.toggles import ( - split_library_view_on_dashboard, use_new_advanced_settings_page, use_new_course_outline_page, use_new_export_page, @@ -70,13 +68,12 @@ use_new_home_page, use_new_import_page, use_new_schedule_details_page, - use_new_text_editor, use_new_unit_page, use_new_updates_page, - use_new_video_editor, use_new_video_uploads_page, use_new_custom_pages, ) +from cms.djangoapps.contentstore.toggles import use_new_text_editor, use_new_video_editor from cms.djangoapps.models.settings.course_grading import CourseGradingModel from xmodule.library_tools import LibraryToolsService from xmodule.modulestore import ModuleStoreEnum # lint-amnesty, pylint: disable=wrong-import-order @@ -1390,109 +1387,6 @@ def get_help_urls(): return help_tokens -def get_home_context(request): - """ - Utils is used to get context of course grading. - It is used for both DRF and django views. - """ - - from cms.djangoapps.contentstore.views.course import ( - get_allowed_organizations, - get_allowed_organizations_for_libraries, - get_courses_accessible_to_user, - user_can_create_organizations, - _accessible_libraries_iter, - _get_course_creator_status, - _format_library_for_view, - _process_courses_list, - ENABLE_GLOBAL_STAFF_OPTIMIZATION, - ) - from cms.djangoapps.contentstore.views.library import ( - LIBRARY_AUTHORING_MICROFRONTEND_URL, - LIBRARIES_ENABLED, - should_redirect_to_library_authoring_mfe, - user_can_create_library, - ) - - optimization_enabled = GlobalStaff().has_user(request.user) and ENABLE_GLOBAL_STAFF_OPTIMIZATION.is_enabled() - - org = request.GET.get('org', '') if optimization_enabled else None - courses_iter, in_process_course_actions = get_courses_accessible_to_user(request, org) - user = request.user - libraries = [] - if not split_library_view_on_dashboard() and LIBRARIES_ENABLED: - libraries = _accessible_libraries_iter(request.user) - - def format_in_process_course_view(uca): - """ - Return a dict of the data which the view requires for each unsucceeded course - """ - return { - 'display_name': uca.display_name, - 'course_key': str(uca.course_key), - 'org': uca.course_key.org, - 'number': uca.course_key.course, - 'run': uca.course_key.run, - 'is_failed': uca.state == CourseRerunUIStateManager.State.FAILED, - 'is_in_progress': uca.state == CourseRerunUIStateManager.State.IN_PROGRESS, - 'dismiss_link': reverse_course_url( - 'course_notifications_handler', - uca.course_key, - kwargs={ - 'action_state_id': uca.id, - }, - ) if uca.state == CourseRerunUIStateManager.State.FAILED else '' - } - - split_archived = settings.FEATURES.get('ENABLE_SEPARATE_ARCHIVED_COURSES', False) - active_courses, archived_courses = _process_courses_list(courses_iter, in_process_course_actions, split_archived) - in_process_course_actions = [format_in_process_course_view(uca) for uca in in_process_course_actions] - - home_context = { - 'courses': active_courses, - 'split_studio_home': split_library_view_on_dashboard(), - 'archived_courses': archived_courses, - 'in_process_course_actions': in_process_course_actions, - 'libraries_enabled': LIBRARIES_ENABLED, - 'redirect_to_library_authoring_mfe': should_redirect_to_library_authoring_mfe(), - 'library_authoring_mfe_url': LIBRARY_AUTHORING_MICROFRONTEND_URL, - 'libraries': [_format_library_for_view(lib, request) for lib in libraries], - 'show_new_library_button': user_can_create_library(user) and not should_redirect_to_library_authoring_mfe(), - 'user': user, - 'request_course_creator_url': reverse('request_course_creator'), - 'course_creator_status': _get_course_creator_status(user), - 'rerun_creator_status': GlobalStaff().has_user(user), - 'allow_unicode_course_id': settings.FEATURES.get('ALLOW_UNICODE_COURSE_ID', False), - 'allow_course_reruns': settings.FEATURES.get('ALLOW_COURSE_RERUNS', True), - 'optimization_enabled': optimization_enabled, - 'active_tab': 'courses', - 'allowed_organizations': get_allowed_organizations(user), - 'allowed_organizations_for_libraries': get_allowed_organizations_for_libraries(user), - 'can_create_organizations': user_can_create_organizations(user), - } - - return home_context - - -def get_course_rerun_context(course_key, course_block, user): - """ - Utils is used to get context of course rerun. - It is used for both DRF and django views. - """ - - from cms.djangoapps.contentstore.views.course import _get_course_creator_status - - course_rerun_context = { - 'source_course_key': course_key, - 'display_name': course_block.display_name, - 'user': user, - 'course_creator_status': _get_course_creator_status(user), - 'allow_unicode_course_id': settings.FEATURES.get('ALLOW_UNICODE_COURSE_ID', False) - } - - return course_rerun_context - - class StudioPermissionsService: """ Service that can provide information about a user's permissions. diff --git a/cms/djangoapps/contentstore/views/course.py b/cms/djangoapps/contentstore/views/course.py index d74a99a8e391..28de4cfde9bb 100644 --- a/cms/djangoapps/contentstore/views/course.py +++ b/cms/djangoapps/contentstore/views/course.py @@ -31,7 +31,6 @@ from organizations.exceptions import InvalidOrganizationException from rest_framework.exceptions import ValidationError -from cms.djangoapps.contentstore.xblock_storage_handlers.view_handlers import create_xblock_info from cms.djangoapps.course_creators.views import add_user_with_status_unrequested, get_course_creator_status from cms.djangoapps.course_creators.models import CourseCreator from cms.djangoapps.models.settings.course_grading import CourseGradingModel @@ -101,7 +100,6 @@ add_instructor, get_course_settings, get_course_grading, - get_home_context, get_lms_link_for_item, get_proctored_exam_settings_url, get_course_outline_url, @@ -110,7 +108,6 @@ get_advanced_settings_url, get_grading_url, get_schedule_details_url, - get_course_rerun_context, initialize_permissions, remove_all_instructors, reverse_course_url, @@ -121,7 +118,15 @@ update_course_discussions_settings, ) from .component import ADVANCED_COMPONENT_TYPES -from .library import LIBRARIES_ENABLED +from cms.djangoapps.contentstore.xblock_storage_handlers.view_handlers import ( + create_xblock_info, +) +from .library import ( + LIBRARIES_ENABLED, + LIBRARY_AUTHORING_MICROFRONTEND_URL, + user_can_create_library, + should_redirect_to_library_authoring_mfe +) log = logging.getLogger(__name__) User = get_user_model() @@ -329,8 +334,13 @@ def course_rerun_handler(request, course_key_string): with modulestore().bulk_operations(course_key): course_block = get_course_and_check_access(course_key, request.user, depth=3) if request.method == 'GET': - course_rerun_context = get_course_rerun_context(course_key, course_block, request.user) - return render_to_response('course-create-rerun.html', course_rerun_context) + return render_to_response('course-create-rerun.html', { + 'source_course_key': course_key, + 'display_name': course_block.display_name, + 'user': request.user, + 'course_creator_status': _get_course_creator_status(request.user), + 'allow_unicode_course_id': settings.FEATURES.get('ALLOW_UNICODE_COURSE_ID', False) + }) @login_required @@ -541,8 +551,62 @@ def course_listing(request): if use_new_home_page(): return redirect(get_studio_home_url()) - home_context = get_home_context(request) - return render_to_response('index.html', home_context) + optimization_enabled = GlobalStaff().has_user(request.user) and ENABLE_GLOBAL_STAFF_OPTIMIZATION.is_enabled() + + org = request.GET.get('org', '') if optimization_enabled else None + courses_iter, in_process_course_actions = get_courses_accessible_to_user(request, org) + user = request.user + libraries = [] + if not split_library_view_on_dashboard() and LIBRARIES_ENABLED: + libraries = _accessible_libraries_iter(request.user) + + def format_in_process_course_view(uca): + """ + Return a dict of the data which the view requires for each unsucceeded course + """ + return { + 'display_name': uca.display_name, + 'course_key': str(uca.course_key), + 'org': uca.course_key.org, + 'number': uca.course_key.course, + 'run': uca.course_key.run, + 'is_failed': uca.state == CourseRerunUIStateManager.State.FAILED, + 'is_in_progress': uca.state == CourseRerunUIStateManager.State.IN_PROGRESS, + 'dismiss_link': reverse_course_url( + 'course_notifications_handler', + uca.course_key, + kwargs={ + 'action_state_id': uca.id, + }, + ) if uca.state == CourseRerunUIStateManager.State.FAILED else '' + } + + split_archived = settings.FEATURES.get('ENABLE_SEPARATE_ARCHIVED_COURSES', False) + active_courses, archived_courses = _process_courses_list(courses_iter, in_process_course_actions, split_archived) + in_process_course_actions = [format_in_process_course_view(uca) for uca in in_process_course_actions] + + return render_to_response('index.html', { + 'courses': active_courses, + 'split_studio_home': split_library_view_on_dashboard(), + 'archived_courses': archived_courses, + 'in_process_course_actions': in_process_course_actions, + 'libraries_enabled': LIBRARIES_ENABLED, + 'redirect_to_library_authoring_mfe': should_redirect_to_library_authoring_mfe(), + 'library_authoring_mfe_url': LIBRARY_AUTHORING_MICROFRONTEND_URL, + 'libraries': [_format_library_for_view(lib, request) for lib in libraries], + 'show_new_library_button': user_can_create_library(user) and not should_redirect_to_library_authoring_mfe(), + 'user': user, + 'request_course_creator_url': reverse('request_course_creator'), + 'course_creator_status': _get_course_creator_status(user), + 'rerun_creator_status': GlobalStaff().has_user(user), + 'allow_unicode_course_id': settings.FEATURES.get('ALLOW_UNICODE_COURSE_ID', False), + 'allow_course_reruns': settings.FEATURES.get('ALLOW_COURSE_RERUNS', True), + 'optimization_enabled': optimization_enabled, + 'active_tab': 'courses', + 'allowed_organizations': get_allowed_organizations(user), + 'allowed_organizations_for_libraries': get_allowed_organizations_for_libraries(user), + 'can_create_organizations': user_can_create_organizations(user), + }) @login_required