diff --git a/cms/djangoapps/contentstore/toggles.py b/cms/djangoapps/contentstore/toggles.py index 87a551d0a8..34b2ae783a 100644 --- a/cms/djangoapps/contentstore/toggles.py +++ b/cms/djangoapps/contentstore/toggles.py @@ -238,7 +238,7 @@ def use_new_home_page(): return ENABLE_NEW_STUDIO_HOME_PAGE.is_enabled() -# .. toggle_name: new_studio_mfe.use_new_custom_pages +# .. toggle_name: contentstore.new_studio_mfe.use_new_custom_pages # .. toggle_implementation: CourseWaffleFlag # .. toggle_default: False # .. toggle_description: This flag enables the use of the new studio custom pages mfe @@ -258,7 +258,7 @@ def use_new_custom_pages(course_key): return ENABLE_NEW_STUDIO_CUSTOM_PAGES.is_enabled(course_key) -# .. toggle_name: new_studio_mfe.use_new_schedule_details_page +# .. toggle_name: contentstore.new_studio_mfe.use_new_schedule_details_page # .. toggle_implementation: CourseWaffleFlag # .. toggle_default: False # .. toggle_description: This flag enables the use of the new studio schedule and details mfe @@ -278,7 +278,7 @@ def use_new_schedule_details_page(course_key): return ENABLE_NEW_STUDIO_SCHEDULE_DETAILS_PAGE.is_enabled(course_key) -# .. toggle_name: new_studio_mfe.use_new_advanced_settings_page +# .. toggle_name: contentstore.new_studio_mfe.use_new_advanced_settings_page # .. toggle_implementation: CourseWaffleFlag # .. toggle_default: False # .. toggle_description: This flag enables the use of the new studio advanced settings page mfe @@ -298,7 +298,7 @@ def use_new_advanced_settings_page(course_key): return ENABLE_NEW_STUDIO_ADVANCED_SETTINGS_PAGE.is_enabled(course_key) -# .. toggle_name: new_studio_mfe.use_new_grading_page +# .. toggle_name: contentstore.new_studio_mfe.use_new_grading_page # .. toggle_implementation: CourseWaffleFlag # .. toggle_default: False # .. toggle_description: This flag enables the use of the new studio grading page mfe @@ -318,7 +318,7 @@ def use_new_grading_page(course_key): return ENABLE_NEW_STUDIO_GRADING_PAGE.is_enabled(course_key) -# .. toggle_name: new_studio_mfe.use_new_updates_page +# .. toggle_name: contentstore.new_studio_mfe.use_new_updates_page # .. toggle_implementation: CourseWaffleFlag # .. toggle_default: False # .. toggle_description: This flag enables the use of the new studio updates page mfe @@ -338,7 +338,7 @@ def use_new_updates_page(course_key): return ENABLE_NEW_STUDIO_UPDATES_PAGE.is_enabled(course_key) -# .. toggle_name: new_studio_mfe.use_new_import_page +# .. toggle_name: contentstore.new_studio_mfe.use_new_import_page # .. toggle_implementation: CourseWaffleFlag # .. toggle_default: False # .. toggle_description: This flag enables the use of the new studio import page mfe @@ -358,7 +358,7 @@ def use_new_import_page(course_key): return ENABLE_NEW_STUDIO_IMPORT_PAGE.is_enabled(course_key) -# .. toggle_name: new_studio_mfe.use_new_export_page +# .. toggle_name: contentstore.new_studio_mfe.use_new_export_page # .. toggle_implementation: CourseWaffleFlag # .. toggle_default: False # .. toggle_description: This flag enables the use of the new studio export page mfe @@ -378,7 +378,7 @@ def use_new_export_page(course_key): return ENABLE_NEW_STUDIO_EXPORT_PAGE.is_enabled(course_key) -# .. toggle_name: new_studio_mfe.use_new_files_uploads_page +# .. toggle_name: contentstore.new_studio_mfe.use_new_files_uploads_page # .. toggle_implementation: CourseWaffleFlag # .. toggle_default: False # .. toggle_description: This flag enables the use of the new studio files and uploads page mfe @@ -398,7 +398,7 @@ def use_new_files_uploads_page(course_key): return ENABLE_NEW_STUDIO_FILES_UPLOADS_PAGE.is_enabled(course_key) -# .. toggle_name: new_studio_mfe.use_new_video_uploads_page +# .. toggle_name: contentstore.new_studio_mfe.use_new_video_uploads_page # .. toggle_implementation: CourseWaffleFlag # .. toggle_default: False # .. toggle_description: This flag enables the use of the new video uploads page mfe @@ -418,7 +418,7 @@ def use_new_video_uploads_page(course_key): return ENABLE_NEW_STUDIO_VIDEO_UPLOADS_PAGE.is_enabled(course_key) -# .. toggle_name: new_studio_mfe.use_new_course_outline_page +# .. toggle_name: contentstore.new_studio_mfe.use_new_course_outline_page # .. toggle_implementation: CourseWaffleFlag # .. toggle_default: False # .. toggle_description: This flag enables the use of the new studio course outline page mfe @@ -438,7 +438,7 @@ def use_new_course_outline_page(course_key): return ENABLE_NEW_STUDIO_COURSE_OUTLINE_PAGE.is_enabled(course_key) -# .. toggle_name: new_studio_mfe.use_new_unit_page +# .. toggle_name: contentstore.new_studio_mfe.use_new_unit_page # .. toggle_implementation: CourseWaffleFlag # .. toggle_default: False # .. toggle_description: This flag enables the use of the new studio course outline page mfe @@ -458,7 +458,7 @@ def use_new_unit_page(course_key): return ENABLE_NEW_STUDIO_UNIT_PAGE.is_enabled(course_key) -# .. toggle_name: new_studio_mfe.use_new_course_team_page +# .. toggle_name: contentstore.new_studio_mfe.use_new_course_team_page # .. toggle_implementation: CourseWaffleFlag # .. toggle_default: False # .. toggle_description: This flag enables the use of the new studio course team page mfe diff --git a/cms/djangoapps/contentstore/utils.py b/cms/djangoapps/contentstore/utils.py index 414f00d002..20c6237ed7 100644 --- a/cms/djangoapps/contentstore/utils.py +++ b/cms/djangoapps/contentstore/utils.py @@ -70,6 +70,7 @@ from cms.djangoapps.contentstore.toggles import ( use_new_unit_page, use_new_updates_page, 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 @@ -402,19 +403,32 @@ def get_course_outline_url(course_locator) -> str: return course_outline_url -def get_unit_url(course_locator) -> str: +def get_unit_url(course_locator, unit_locator) -> str: """ Gets course authoring microfrontend URL for unit page view. """ unit_url = None if use_new_unit_page(course_locator): mfe_base_url = get_course_authoring_url(course_locator) - course_mfe_url = f'{mfe_base_url}/container/' + course_mfe_url = f'{mfe_base_url}/course/{course_locator}/container/{unit_locator}' if mfe_base_url: unit_url = course_mfe_url return unit_url +def get_custom_pages_url(course_locator) -> str: + """ + Gets course authoring microfrontend URL for custom pages view. + """ + custom_pages_url = None + if use_new_custom_pages(course_locator): + mfe_base_url = get_course_authoring_url(course_locator) + course_mfe_url = f'{mfe_base_url}/course/{course_locator}/custom-pages' + if mfe_base_url: + custom_pages_url = course_mfe_url + return custom_pages_url + + def course_import_olx_validation_is_enabled(): """ Check if course olx validation is enabled on course import. diff --git a/cms/djangoapps/contentstore/views/assets.py b/cms/djangoapps/contentstore/views/assets.py index 38f11db62c..d2adb429a8 100644 --- a/cms/djangoapps/contentstore/views/assets.py +++ b/cms/djangoapps/contentstore/views/assets.py @@ -12,6 +12,7 @@ from django.conf import settings from django.contrib.auth.decorators import login_required from django.core.exceptions import PermissionDenied from django.http import HttpResponseBadRequest, HttpResponseNotFound +from django.shortcuts import redirect from django.utils.translation import gettext as _ from django.views.decorators.csrf import ensure_csrf_cookie from django.views.decorators.http import require_http_methods, require_POST @@ -31,7 +32,8 @@ from xmodule.modulestore.django import modulestore # lint-amnesty, pylint: disa from xmodule.modulestore.exceptions import ItemNotFoundError # lint-amnesty, pylint: disable=wrong-import-order from ..exceptions import AssetNotFoundException, AssetSizeTooLargeException -from ..utils import reverse_course_url +from ..toggles import use_new_files_uploads_page +from ..utils import reverse_course_url, get_files_uploads_url __all__ = ['assets_handler'] @@ -104,6 +106,9 @@ def _asset_index(request, course_key): ''' course_block = modulestore().get_course(course_key) + if use_new_files_uploads_page(course_key): + return redirect(get_files_uploads_url(course_key)) + return render_to_response('asset_index.html', { 'language_code': request.LANGUAGE_CODE, 'context_course': course_block, diff --git a/cms/djangoapps/contentstore/views/component.py b/cms/djangoapps/contentstore/views/component.py index 2c97a7e957..05bd39a355 100644 --- a/cms/djangoapps/contentstore/views/component.py +++ b/cms/djangoapps/contentstore/views/component.py @@ -10,6 +10,7 @@ from django.conf import settings from django.contrib.auth.decorators import login_required from django.core.exceptions import PermissionDenied from django.http import Http404, HttpResponseBadRequest +from django.shortcuts import redirect from django.utils.translation import gettext as _ from django.views.decorators.http import require_GET from opaque_keys import InvalidKeyError @@ -34,8 +35,8 @@ except ImportError: content_staging_api = None from xmodule.modulestore.django import modulestore # lint-amnesty, pylint: disable=wrong-import-order from xmodule.modulestore.exceptions import ItemNotFoundError # lint-amnesty, pylint: disable=wrong-import-order - -from ..utils import get_lms_link_for_item, get_sibling_urls, reverse_course_url +from ..toggles import use_new_unit_page +from ..utils import get_lms_link_for_item, get_sibling_urls, reverse_course_url, get_unit_url from ..helpers import get_parent_xblock, is_unit, xblock_type_display_name from cms.djangoapps.contentstore.xblock_storage_handlers.view_handlers import ( add_container_page_publishing_info, @@ -131,7 +132,6 @@ def container_handler(request, usage_key_string): course, xblock, lms_link, preview_lms_link = _get_item_in_course(request, usage_key) except ItemNotFoundError: return HttpResponseBadRequest() - component_templates = get_component_templates(course) ancestor_xblocks = [] parent = get_parent_xblock(xblock) @@ -140,6 +140,9 @@ def container_handler(request, usage_key_string): is_unit_page = is_unit(xblock) unit = xblock if is_unit_page else None + if is_unit_page and use_new_unit_page(course.id): + return redirect(get_unit_url(course.id, unit.location)) + is_first = True block = xblock @@ -199,7 +202,6 @@ def container_handler(request, usage_key_string): user_clipboard = content_staging_api.get_user_clipboard_json(request.user.id, request) else: user_clipboard = {"content": None} - return render_to_response('container.html', { 'language_code': request.LANGUAGE_CODE, 'context_course': course, # Needed only for display of menus at top of page. diff --git a/cms/djangoapps/contentstore/views/course.py b/cms/djangoapps/contentstore/views/course.py index 9af3f0d1c4..4ddac587f0 100644 --- a/cms/djangoapps/contentstore/views/course.py +++ b/cms/djangoapps/contentstore/views/course.py @@ -85,13 +85,27 @@ from ..course_group_config import ( from ..course_info_model import delete_course_update, get_course_updates, update_course_updates from ..courseware_index import CoursewareSearchIndexer, SearchIndexingError from ..tasks import rerun_course as rerun_course_task -from ..toggles import split_library_view_on_dashboard +from ..toggles import ( + split_library_view_on_dashboard, + use_new_course_outline_page, + use_new_home_page, + use_new_updates_page, + use_new_advanced_settings_page, + use_new_grading_page, + use_new_schedule_details_page, +) from ..utils import ( add_instructor, get_course_settings, get_course_grading, get_lms_link_for_item, get_proctored_exam_settings_url, + get_course_outline_url, + get_studio_home_url, + get_updates_url, + get_advanced_settings_url, + get_grading_url, + get_schedule_details_url, initialize_permissions, remove_all_instructors, reverse_course_url, @@ -533,6 +547,8 @@ def course_listing(request): """ List all courses and libraries available to the logged in user """ + if use_new_home_page(): + return redirect(get_studio_home_url()) optimization_enabled = GlobalStaff().has_user(request.user) and ENABLE_GLOBAL_STAFF_OPTIMIZATION.is_enabled() @@ -691,6 +707,8 @@ def course_index(request, course_key): course_block = get_course_and_check_access(course_key, request.user, depth=None) if not course_block: raise Http404 + if use_new_course_outline_page(course_key): + return redirect(get_course_outline_url(course_key)) lms_link = get_lms_link_for_item(course_block.location) reindex_link = None if settings.FEATURES.get('ENABLE_COURSEWARE_INDEX', False): @@ -1066,6 +1084,8 @@ def course_info_handler(request, course_key_string): course_block = get_course_and_check_access(course_key, request.user) if not course_block: raise Http404 + if use_new_updates_page(course_key): + return redirect(get_updates_url(course_key)) if 'text/html' in request.META.get('HTTP_ACCEPT', 'text/html'): return render_to_response( 'course_info.html', @@ -1150,6 +1170,8 @@ def settings_handler(request, course_key_string): # lint-amnesty, pylint: disab with modulestore().bulk_operations(course_key): course_block = get_course_and_check_access(course_key, request.user) if 'text/html' in request.META.get('HTTP_ACCEPT', '') and request.method == 'GET': + if use_new_schedule_details_page(course_key): + return redirect(get_schedule_details_url(course_key)) settings_context = get_course_settings(request, course_key, course_block) return render_to_response('settings.html', settings_context) elif 'application/json' in request.META.get('HTTP_ACCEPT', ''): # pylint: disable=too-many-nested-blocks @@ -1191,6 +1213,8 @@ def grading_handler(request, course_key_string, grader_index=None): raise PermissionDenied() if 'text/html' in request.META.get('HTTP_ACCEPT', '') and request.method == 'GET': + if use_new_grading_page(course_key): + return redirect(get_grading_url(course_key)) grading_context = get_course_grading(course_key) return render_to_response('settings_graders.html', grading_context) elif 'application/json' in request.META.get('HTTP_ACCEPT', ''): @@ -1286,6 +1310,8 @@ def advanced_settings_handler(request, course_key_string): advanced_dict.get('mobile_available')['deprecated'] = True if 'text/html' in request.META.get('HTTP_ACCEPT', '') and request.method == 'GET': + if use_new_advanced_settings_page(course_key): + return redirect(get_advanced_settings_url(course_key)) publisher_enabled = configuration_helpers.get_value_for_org( course_block.location.org, 'ENABLE_PUBLISHER', diff --git a/cms/djangoapps/contentstore/views/import_export.py b/cms/djangoapps/contentstore/views/import_export.py index 1e3d1487cc..bb1616c04e 100644 --- a/cms/djangoapps/contentstore/views/import_export.py +++ b/cms/djangoapps/contentstore/views/import_export.py @@ -19,6 +19,7 @@ from django.core.files import File from django.core.files.storage import FileSystemStorage from django.db import transaction from django.http import Http404, HttpResponse, HttpResponseNotFound, StreamingHttpResponse +from django.shortcuts import redirect from django.utils.translation import gettext as _ from django.views.decorators.cache import cache_control from django.views.decorators.csrf import ensure_csrf_cookie @@ -40,7 +41,8 @@ from xmodule.modulestore.django import modulestore # lint-amnesty, pylint: disa from ..storage import course_import_export_storage from ..tasks import CourseExportTask, CourseImportTask, export_olx, import_olx -from ..utils import reverse_course_url, reverse_library_url +from ..toggles import use_new_export_page, use_new_import_page +from ..utils import reverse_course_url, reverse_library_url, get_export_url, get_import_url __all__ = [ 'import_handler', 'import_status_handler', @@ -89,6 +91,8 @@ def import_handler(request, course_key_string): else: return _write_chunk(request, courselike_key) elif request.method == 'GET': # assume html + if use_new_import_page(courselike_key): + return redirect(get_import_url(courselike_key)) status_url = reverse_course_url( "import_status_handler", courselike_key, kwargs={'filename': "fillerName"} ) @@ -336,6 +340,8 @@ def export_handler(request, course_key_string): export_olx.delay(request.user.id, course_key_string, request.LANGUAGE_CODE) return JsonResponse({'ExportStatus': 1}) elif 'text/html' in requested_format: + if use_new_export_page(course_key): + return redirect(get_export_url(course_key)) return render_to_response('export.html', context) else: # Only HTML request format is supported (no JSON). diff --git a/cms/djangoapps/contentstore/views/tabs.py b/cms/djangoapps/contentstore/views/tabs.py index 4018b11883..20426933f3 100644 --- a/cms/djangoapps/contentstore/views/tabs.py +++ b/cms/djangoapps/contentstore/views/tabs.py @@ -7,6 +7,7 @@ from django.contrib.auth import get_user_model from django.contrib.auth.decorators import login_required from django.core.exceptions import PermissionDenied from django.http import HttpResponseNotFound +from django.shortcuts import redirect from django.views.decorators.csrf import ensure_csrf_cookie from django.views.decorators.http import require_http_methods from opaque_keys.edx.keys import CourseKey, UsageKey @@ -19,7 +20,8 @@ from xmodule.tabs import CourseTab, CourseTabList, InvalidTabsException, StaticT from common.djangoapps.edxmako.shortcuts import render_to_response from common.djangoapps.student.auth import has_course_author_access from common.djangoapps.util.json_request import JsonResponse, JsonResponseBadRequest, expect_json -from ..utils import get_lms_link_for_item, get_pages_and_resources_url +from ..toggles import use_new_custom_pages +from ..utils import get_lms_link_for_item, get_pages_and_resources_url, get_custom_pages_url __all__ = ["tabs_handler", "update_tabs_handler"] @@ -63,7 +65,8 @@ def tabs_handler(request, course_key_string): elif request.method == "GET": # assume html # get all tabs from the tabs list: static tabs (a.k.a. user-created tabs) and built-in tabs # present in the same order they are displayed in LMS - + if use_new_custom_pages(course_key): + return redirect(get_custom_pages_url(course_key)) tabs_to_render = list(get_course_tabs(course_item, request.user)) return render_to_response( diff --git a/cms/djangoapps/contentstore/views/user.py b/cms/djangoapps/contentstore/views/user.py index 42ccb6384c..d97c8c24fa 100644 --- a/cms/djangoapps/contentstore/views/user.py +++ b/cms/djangoapps/contentstore/views/user.py @@ -5,6 +5,7 @@ from django.contrib.auth.decorators import login_required from django.contrib.auth.models import User # lint-amnesty, pylint: disable=imported-auth-user from django.core.exceptions import PermissionDenied from django.http import HttpResponseNotFound +from django.shortcuts import redirect from django.utils.translation import gettext as _ from django.views.decorators.csrf import ensure_csrf_cookie from django.views.decorators.http import require_http_methods, require_POST @@ -20,6 +21,9 @@ from common.djangoapps.student.roles import CourseInstructorRole, CourseStaffRol from common.djangoapps.util.json_request import JsonResponse, expect_json from xmodule.modulestore.django import modulestore # lint-amnesty, pylint: disable=wrong-import-order +from ..toggles import use_new_course_team_page +from ..utils import get_course_team_url + __all__ = ['request_course_creator', 'course_team_handler'] @@ -55,6 +59,8 @@ def course_team_handler(request, course_key_string=None, email=None): if 'application/json' in request.META.get('HTTP_ACCEPT', 'application/json'): return _course_team_user(request, course_key, email) elif request.method == 'GET': # assume html + if use_new_course_team_page(course_key): + return redirect(get_course_team_url(course_key)) return _manage_users(request, course_key) else: return HttpResponseNotFound() diff --git a/cms/djangoapps/contentstore/views/videos.py b/cms/djangoapps/contentstore/views/videos.py index 1410faa7a7..7627c1e3f5 100644 --- a/cms/djangoapps/contentstore/views/videos.py +++ b/cms/djangoapps/contentstore/views/videos.py @@ -17,6 +17,7 @@ from django.conf import settings from django.contrib.auth.decorators import login_required from django.contrib.staticfiles.storage import staticfiles_storage from django.http import FileResponse, HttpResponseNotFound +from django.shortcuts import redirect from django.urls import reverse from django.utils.translation import gettext as _ from django.utils.translation import gettext_noop @@ -57,7 +58,8 @@ from openedx.core.lib.api.view_utils import view_auth_classes from xmodule.video_block.transcripts_utils import Transcript # lint-amnesty, pylint: disable=wrong-import-order from ..models import VideoUploadConfig -from ..utils import reverse_course_url +from ..toggles import use_new_video_uploads_page +from ..utils import reverse_course_url, get_video_uploads_url from ..video_utils import validate_video_image from .course import get_course_and_check_access @@ -700,7 +702,8 @@ def videos_index_html(course, pagination_conf=None): context['active_transcript_preferences'] = get_transcript_preferences(str(course.id)) # Cached state for transcript providers' credentials (org-specific) context['transcript_credentials'] = get_transcript_credentials_state_for_org(course.id.org) - + if use_new_video_uploads_page(course.id): + return redirect(get_video_uploads_url(course.id)) return render_to_response('videos_index.html', context) diff --git a/cms/envs/devstack.py b/cms/envs/devstack.py index 78313ea720..f4dcd3c2c5 100644 --- a/cms/envs/devstack.py +++ b/cms/envs/devstack.py @@ -49,6 +49,11 @@ LMS_ROOT_URL = f'http://{LMS_BASE}' FEATURES['PREVIEW_LMS_BASE'] = "preview." + LMS_BASE FRONTEND_REGISTER_URL = LMS_ROOT_URL + '/register' + +################################## Video Pipeline Settings ######################### + +FEATURES['ENABLE_VIDEO_UPLOAD_PIPELINE'] = True + ########################### PIPELINE ################################# # Skip packaging and optimization in development