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
Expand Up @@ -40,9 +40,15 @@ def get_course_key(self):

def get_use_new_home_page(self, obj):
"""
Method to get the use_new_home_page switch
Method to indicate whether we should use the new home page.

This used to be based on a waffle flag but the flag is being removed so we
default it to true for now until we can remove the need for it from the consumers
of this serializer and the related APIs.

See https://github.com/openedx/edx-platform/issues/37497
"""
return toggles.use_new_home_page()
return True

def get_use_new_custom_pages(self, obj):
"""
Expand Down
29 changes: 11 additions & 18 deletions cms/djangoapps/contentstore/tests/test_contentstore.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,11 @@
from uuid import uuid4

import ddt
import lxml.html
from django.conf import settings
from django.contrib.auth.models import User # lint-amnesty, pylint: disable=imported-auth-user
from django.test import TestCase
from django.test.utils import override_settings
from django.urls import reverse
from edx_toggles.toggles.testutils import override_waffle_switch, override_waffle_flag
from edxval.api import create_video, get_videos_for_course
from fs.osfs import OSFS
Expand Down Expand Up @@ -1388,17 +1388,6 @@ def assert_course_permission_denied(self):
resp = self.client.ajax_post('/course/', self.course_data)
self.assertEqual(resp.status_code, 403)

@override_waffle_flag(toggles.LEGACY_STUDIO_HOME, True)
def test_course_index_view_with_no_courses(self):
"""Test viewing the index page with no courses"""
resp = self.client.get_html('/home/')
self.assertContains(
resp,
f'<h1 class="page-header">{settings.STUDIO_SHORT_NAME} Home</h1>',
status_code=200,
html=True
)

def test_course_factory(self):
"""Test that the course factory works correctly."""
course = CourseFactory.create()
Expand Down Expand Up @@ -1879,17 +1868,21 @@ def assertInCourseListing(self, course_key):
"""
Asserts that the given course key is NOT in the unsucceeded course action section of the html.
"""
with override_waffle_flag(toggles.LEGACY_STUDIO_HOME, True):
course_listing = lxml.html.fromstring(self.client.get_html('/home/').content)
self.assertEqual(len(self.get_unsucceeded_course_action_elements(course_listing, course_key)), 0)
response = self.client.get(reverse('cms.djangoapps.contentstore:v2:courses'))
assert str(course_key) not in [
course["course_key"]
for course in response.json()["results"]["in_process_course_actions"]
]

def assertInUnsucceededCourseActions(self, course_key):
"""
Asserts that the given course key is in the unsucceeded course action section of the html.
"""
with override_waffle_flag(toggles.LEGACY_STUDIO_HOME, True):
course_listing = lxml.html.fromstring(self.client.get_html('/home/').content)
self.assertEqual(len(self.get_unsucceeded_course_action_elements(course_listing, course_key)), 1)
response = self.client.get(reverse('cms.djangoapps.contentstore:v2:courses'))
assert str(course_key) in [
course["course_key"]
for course in response.json()["results"]["in_process_course_actions"]
]

def verify_rerun_course(self, source_course_key, destination_course_key, destination_display_name):
"""
Expand Down
12 changes: 0 additions & 12 deletions cms/djangoapps/contentstore/tests/test_course_listing.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,9 @@

import ddt
from ccx_keys.locator import CCXLocator
from django.conf import settings
from django.test import RequestFactory
from edx_toggles.toggles.testutils import override_waffle_flag
from opaque_keys.edx.locations import CourseLocator

from cms.djangoapps.contentstore import toggles
from cms.djangoapps.contentstore.tests.utils import AjaxEnabledTestClient
from cms.djangoapps.contentstore.utils import delete_course
from cms.djangoapps.contentstore.views.course import (
Expand Down Expand Up @@ -89,15 +86,6 @@ def tearDown(self):
self.client.logout()
ModuleStoreTestCase.tearDown(self) # pylint: disable=non-parent-method-called

@override_waffle_flag(toggles.LEGACY_STUDIO_HOME, True)
def test_empty_course_listing(self):
"""
Test on empty course listing, studio name is properly displayed
"""
message = f"Are you staff on an existing {settings.STUDIO_SHORT_NAME} course?"
response = self.client.get('/home')
self.assertContains(response, message)

def test_get_course_list(self):
"""
Test getting courses with new access group format e.g. 'instructor_edx.course.run'
Expand Down
104 changes: 1 addition & 103 deletions cms/djangoapps/contentstore/tests/test_i18n.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,9 @@
Tests for validate Internationalization and XBlock i18n service.
"""
import gettext
from unittest import mock, skip
from unittest import mock

from django.utils import translation
from edx_toggles.toggles.testutils import override_waffle_flag

from django.utils.translation import get_language
from xblock.core import XBlock
Expand All @@ -14,10 +13,7 @@
from xmodule.modulestore.tests.factories import CourseFactory, BlockFactory
from xmodule.tests.test_export import PureXBlock

from cms.djangoapps.contentstore import toggles
from cms.djangoapps.contentstore.tests.utils import AjaxEnabledTestClient
from cms.djangoapps.contentstore.views.preview import _prepare_runtime_for_preview
from common.djangoapps.student.tests.factories import UserFactory


class FakeTranslations(XBlockI18nService):
Expand Down Expand Up @@ -166,101 +162,3 @@ def test_i18n_service_callable(self):
Test: i18n service should be callable in studio.
"""
self.assertTrue(callable(self.block.runtime._services.get('i18n'))) # pylint: disable=protected-access


class InternationalizationTest(ModuleStoreTestCase):
"""
Tests to validate Internationalization.
"""

CREATE_USER = False

def setUp(self):
"""
These tests need a user in the DB so that the django Test Client
can log them in.
They inherit from the ModuleStoreTestCase class so that the mongodb collection
will be cleared out before each test case execution and deleted
afterwards.
"""
super().setUp()

self.uname = 'testuser'
self.email = 'test+courses@edx.org'
self.password = self.TEST_PASSWORD

# Create the use so we can log them in.
self.user = UserFactory.create(username=self.uname, email=self.email, password=self.password)

# Note that we do not actually need to do anything
# for registration if we directly mark them active.
self.user.is_active = True
# Staff has access to view all courses
self.user.is_staff = True
self.user.save()

self.course_data = {
'org': 'MITx',
'number': '999',
'display_name': 'Robot Super Course',
}

@override_waffle_flag(toggles.LEGACY_STUDIO_HOME, True)
def test_course_plain_english(self):
"""Test viewing the index page with no courses"""
self.client = AjaxEnabledTestClient() # lint-amnesty, pylint: disable=attribute-defined-outside-init
self.client.login(username=self.uname, password=self.password)

resp = self.client.get_html('/home/')
self.assertContains(resp,
'<h1 class="page-header">𝓢𝓽𝓾𝓭𝓲𝓸 Home</h1>',
status_code=200,
html=True)

@override_waffle_flag(toggles.LEGACY_STUDIO_HOME, True)
def test_course_explicit_english(self):
"""Test viewing the index page with no courses"""
self.client = AjaxEnabledTestClient() # lint-amnesty, pylint: disable=attribute-defined-outside-init
self.client.login(username=self.uname, password=self.password)

resp = self.client.get_html(
'/home/',
{},
HTTP_ACCEPT_LANGUAGE='en',
)

self.assertContains(resp,
'<h1 class="page-header">𝓢𝓽𝓾𝓭𝓲𝓸 Home</h1>',
status_code=200,
html=True)

# ****
# NOTE:
# ****
#
# This test will break when we replace this fake 'test' language
# with actual Esperanto. This test will need to be updated with
# actual Esperanto at that time.
# Test temporarily disable since it depends on creation of dummy strings
@skip
def test_course_with_accents(self):
"""Test viewing the index page with no courses"""
self.client = AjaxEnabledTestClient() # lint-amnesty, pylint: disable=attribute-defined-outside-init
self.client.login(username=self.uname, password=self.password)

resp = self.client.get_html(
'/home/',
{},
HTTP_ACCEPT_LANGUAGE='eo'
)

TEST_STRING = (
'<h1 class="title-1">'
'My \xc7\xf6\xfcrs\xe9s L#'
'</h1>'
)

self.assertContains(resp,
TEST_STRING,
status_code=200,
html=True)
21 changes: 10 additions & 11 deletions cms/djangoapps/contentstore/tests/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
import datetime
import time
from unittest import mock
from urllib.parse import quote_plus
from urllib.parse import quote_plus, unquote

from ddt import data, ddt, unpack
from django.conf import settings
Expand All @@ -24,6 +24,7 @@
from cms.djangoapps.contentstore import toggles
from cms.djangoapps.contentstore.tests.test_course_settings import CourseTestCase
from cms.djangoapps.contentstore.tests.utils import AjaxEnabledTestClient, parse_json, registration, user
from cms.djangoapps.contentstore.utils import get_studio_home_url
from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase # lint-amnesty, pylint: disable=wrong-import-order
from xmodule.modulestore.tests.factories import CourseFactory # lint-amnesty, pylint: disable=wrong-import-order

Expand Down Expand Up @@ -114,12 +115,6 @@ def setUp(self):
# clear the cache so ratelimiting won't affect these tests
cache.clear()

def check_page_get(self, url, expected):
resp = self.client.get_html(url)
self.assertEqual(resp.status_code, expected)
return resp

@override_waffle_flag(toggles.LEGACY_STUDIO_HOME, True)
def test_private_pages_auth(self):
"""Make sure pages that do require login work."""
auth_pages = (
Expand All @@ -143,18 +138,21 @@ def test_private_pages_auth(self):
print('Not logged in')
for page in auth_pages:
print(f"Checking '{page}'")
self.check_page_get(page, expected=302)
resp = self.client.get_html(page)
assert resp.status_code == 302
assert resp.url == unquote(reverse("login", query={"next": page}))

# Logged in should work.
self.login(self.email, self.pw)

print('Logged in')
for page in simple_auth_pages:
print(f"Checking '{page}'")
self.check_page_get(page, expected=200)
resp = self.client.get_html(page)
assert resp.status_code == 302
assert resp.url == get_studio_home_url()

@override_settings(SESSION_INACTIVITY_TIMEOUT_IN_SECONDS=1)
@override_waffle_flag(toggles.LEGACY_STUDIO_HOME, True)
def test_inactive_session_timeout(self):
"""
Verify that an inactive session times out and redirects to the
Expand All @@ -168,7 +166,8 @@ def test_inactive_session_timeout(self):
# make sure we can access courseware immediately
course_url = '/home/'
resp = self.client.get_html(course_url)
self.assertEqual(resp.status_code, 200)
assert resp.status_code == 302
assert resp.url == get_studio_home_url()

# then wait a bit and see if we get timed out
time.sleep(2)
Expand Down
19 changes: 0 additions & 19 deletions cms/djangoapps/contentstore/toggles.py
Original file line number Diff line number Diff line change
Expand Up @@ -162,25 +162,6 @@ def individualize_anonymous_user_id(course_id):
return INDIVIDUALIZE_ANONYMOUS_USER_ID.is_enabled(course_id)


# .. toggle_name: legacy_studio.home
# .. toggle_implementation: WaffleFlag
# .. toggle_default: False
# .. toggle_description: Temporarily fall back to the old Studio logged-in landing page.
# .. toggle_use_cases: temporary
# .. toggle_creation_date: 2025-03-14
# .. toggle_target_removal_date: 2025-09-14
# .. toggle_tickets: https://github.com/openedx/edx-platform/issues/36275
# .. toggle_warning: In Ulmo, this toggle will be removed. Only the new (React-based) experience will be available.
LEGACY_STUDIO_HOME = WaffleFlag('legacy_studio.home', __name__)


def use_new_home_page():
"""
Returns a boolean if new studio home page mfe is enabled
"""
return not LEGACY_STUDIO_HOME.is_enabled()


# .. toggle_name: legacy_studio.custom_pages
# .. toggle_implementation: WaffleFlag
# .. toggle_default: False
Expand Down
18 changes: 10 additions & 8 deletions cms/djangoapps/contentstore/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@

from bs4 import BeautifulSoup
from django.conf import settings
from django.core.exceptions import ObjectDoesNotExist, ValidationError
from django.core.exceptions import ImproperlyConfigured, ObjectDoesNotExist, ValidationError
from django.urls import reverse
from django.utils import translation
from django.utils.text import Truncator
Expand Down Expand Up @@ -50,7 +50,6 @@
use_new_files_uploads_page,
use_new_grading_page,
use_new_group_configurations_page,
use_new_home_page,
use_new_import_page,
use_new_schedule_details_page,
use_new_textbooks_page,
Expand Down Expand Up @@ -298,12 +297,15 @@ def get_studio_home_url():
"""
Gets course authoring microfrontend URL for Studio Home view.
"""
studio_home_url = None
if use_new_home_page():
mfe_base_url = settings.COURSE_AUTHORING_MICROFRONTEND_URL
if mfe_base_url:
studio_home_url = f'{mfe_base_url}/home'
return studio_home_url
mfe_base_url = settings.COURSE_AUTHORING_MICROFRONTEND_URL
if mfe_base_url:
studio_home_url = f'{mfe_base_url}/home'
return studio_home_url

raise ImproperlyConfigured(
"The COURSE_AUTHORING_MICROFRONTEND_URL must be configured. "
"Please set it to the base url for your authoring MFE."
)


def get_schedule_details_url(course_locator) -> str:
Expand Down
Loading
Loading