diff --git a/.github/workflows/integration-tests.yml b/.github/workflows/integration-tests.yml index 1da7c18..305a55f 100644 --- a/.github/workflows/integration-tests.yml +++ b/.github/workflows/integration-tests.yml @@ -20,6 +20,12 @@ jobs: - branch: opencraft-release/nutmeg.2 remote: open-craft release: nutmeg + - branch: opencraft-release/palm.1 + remote: open-craft + release: palm + - branch: open-release/quince.master + remote: openedx + release: quince - branch: master remote: openedx release: master diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 61654e1..185d2fa 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -14,6 +14,13 @@ Change Log Unreleased ********** +[0.4.1] - 2023-11-07 +******************** + +Fixed +======= + +* Compatibility of ``compat`` imports with Palm. [0.4.0] - 2023-05-18 ******************** diff --git a/section_to_course/__init__.py b/section_to_course/__init__.py index 16b866e..f5c4628 100644 --- a/section_to_course/__init__.py +++ b/section_to_course/__init__.py @@ -2,4 +2,4 @@ Factors sections from Open edX courses into their own new course. """ -__version__ = '0.4.0' +__version__ = '0.4.1' diff --git a/section_to_course/api/tests/test_views.py b/section_to_course/api/tests/test_views.py index 53b0ae4..0b07d51 100644 --- a/section_to_course/api/tests/test_views.py +++ b/section_to_course/api/tests/test_views.py @@ -3,7 +3,7 @@ """ # pylint: disable=no-self-use -from common.djangoapps.student.tests.factories import UserFactory +from common.djangoapps.student.tests.factories import TEST_PASSWORD, UserFactory from django.urls import reverse from rest_framework import status from rest_framework.test import APITestCase @@ -47,14 +47,14 @@ def test_rejects_unauthenticated(self): response = self.client.get( reverse('section_to_course:section_autocomplete', kwargs={'course_id': 'course-v1:edX+DemoX+Demo_Course'}) ) - assert response.status_code == status.HTTP_403_FORBIDDEN + assert response.status_code in (status.HTTP_401_UNAUTHORIZED, status.HTTP_403_FORBIDDEN) def test_rejects_unauthorized(self): """ Test that the API rejects unauthorized users. """ user = UserFactory.create() - assert self.client.login(username=user.username, password='test') + assert self.client.login(username=user.username, password=TEST_PASSWORD) response = self.client.get( reverse('section_to_course:section_autocomplete', kwargs={'course_id': 'course-v1:edX+DemoX+Demo_Course'}) ) @@ -65,7 +65,7 @@ def test_rejects_malformed(self): Test that the API rejects malformed course IDs. """ user = UserFactory.create(is_staff=True) - assert self.client.login(username=user.username, password='test') + assert self.client.login(username=user.username, password=TEST_PASSWORD) response = self.client.get( reverse('section_to_course:section_autocomplete', kwargs={'course_id': 'malarkey'}) ) @@ -76,7 +76,7 @@ def test_handles_nonexistent(self): Test that the API rejects malformed course IDs. """ user = UserFactory.create(is_staff=True) - assert self.client.login(username=user.username, password='test') + assert self.client.login(username=user.username, password=TEST_PASSWORD) response = self.client.get( reverse('section_to_course:section_autocomplete', kwargs={'course_id': 'course-v1:edX+DemoX+Demo_Course'}), ) @@ -87,7 +87,7 @@ def test_handles_blank(self): Test that blank terms return all sections. """ user = UserFactory.create(is_staff=True) - assert self.client.login(username=user.username, password='test') + assert self.client.login(username=user.username, password=TEST_PASSWORD) create_subsections() response = self.client.get( reverse('section_to_course:section_autocomplete', kwargs={'course_id': 'course-v1:edX+DemoX+Demo_Course'}), @@ -105,7 +105,7 @@ def test_filters_existing(self): Test that autocomplete filters existing sections. """ user = UserFactory.create(is_staff=True) - assert self.client.login(username=user.username, password='test') + assert self.client.login(username=user.username, password=TEST_PASSWORD) section_data = create_subsections() SectionToCourseLinkFactory(source_course=section_data['course'], source_section=section_data['experimentation']) response = self.client.get( @@ -123,7 +123,7 @@ def test_filters_names(self): Test that autocomplete filters names. """ user = UserFactory.create(is_staff=True) - assert self.client.login(username=user.username, password='test') + assert self.client.login(username=user.username, password=TEST_PASSWORD) create_subsections() response = self.client.get( reverse('section_to_course:section_autocomplete', kwargs={'course_id': 'course-v1:edX+DemoX+Demo_Course'}) @@ -141,7 +141,7 @@ def test_filters_keys(self): Test that autocomplete filters keys. """ user = UserFactory.create(is_staff=True) - assert self.client.login(username=user.username, password='test') + assert self.client.login(username=user.username, password=TEST_PASSWORD) create_subsections() response = self.client.get( reverse('section_to_course:section_autocomplete', kwargs={'course_id': 'course-v1:edX+DemoX+Demo_Course'}) diff --git a/section_to_course/compat.py b/section_to_course/compat.py index a95f7c4..50fe1e4 100644 --- a/section_to_course/compat.py +++ b/section_to_course/compat.py @@ -92,10 +92,15 @@ def duplicate_block( Duplicate a block using the upstream function. """ try: + # Quince and newer from cms.djangoapps.contentstore.utils import duplicate_block as upstream_duplicate_block except ImportError: - # This is no longer needed in Palm. - from cms.djangoapps.contentstore.views.item import duplicate_block as upstream_duplicate_block + try: + # Palm + from cms.djangoapps.contentstore.views.block import duplicate_block as upstream_duplicate_block + except ModuleNotFoundError: + # Nutmeg + from cms.djangoapps.contentstore.views.item import duplicate_block as upstream_duplicate_block return upstream_duplicate_block( parent_usage_key=destination_course.location, duplicate_source_usage_key=source_block_usage_key, @@ -115,10 +120,15 @@ def update_from_source( Update a block's attributes from a source block. See upstream function. """ try: + # Quince and newer from cms.djangoapps.contentstore.utils import update_from_source as upstream_update_from_source except ImportError: - # This is no longer needed in Palm. - from cms.djangoapps.contentstore.views.item import update_from_source as upstream_update_from_source + try: + # Palm + from cms.djangoapps.contentstore.views.block import update_from_source as upstream_update_from_source + except ModuleNotFoundError: + # Nutmeg + from cms.djangoapps.contentstore.views.item import update_from_source as upstream_update_from_source upstream_update_from_source( source_block=source_block, destination_block=destination_block, user_id=user.id, ) diff --git a/section_to_course/tests/test_admin.py b/section_to_course/tests/test_admin.py index ccad190..79a4c5c 100644 --- a/section_to_course/tests/test_admin.py +++ b/section_to_course/tests/test_admin.py @@ -1,7 +1,7 @@ """ Tests for the admin views of the section_to_course app. """ -from common.djangoapps.student.tests.factories import UserFactory # pylint: disable=import-error +from common.djangoapps.student.tests.factories import TEST_PASSWORD, UserFactory # pylint: disable=import-error from django.test import TestCase from django.urls import reverse from django.utils import timezone @@ -31,7 +31,7 @@ def setUp(self): """Set up our admin test cases.""" super().setUp() user = UserFactory.create(is_staff=True, is_superuser=True) - self.client.login(username=user.username, password='test') + self.client.login(username=user.username, password=TEST_PASSWORD) def test_listing(self): """Test that the admin listing page loads."""