Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Sync opencraft-release/quince.1 with Upstream 20240325-1711326059 #648

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
11 changes: 9 additions & 2 deletions cms/djangoapps/contentstore/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
from xmodule.contentstore.content import StaticContent
from xmodule.contentstore.django import contentstore
from xmodule.exceptions import NotFoundError
from xmodule.library_content_block import LibraryContentBlock
from xmodule.modulestore.django import modulestore
from xmodule.xml_block import XmlMixin

Expand Down Expand Up @@ -336,8 +337,14 @@ def _import_xml_node_to_parent(
new_xblock = store.update_item(temp_xblock, user_id, allow_not_found=True)
parent_xblock.children.append(new_xblock.location)
store.update_item(parent_xblock, user_id)
for child_node in child_nodes:
_import_xml_node_to_parent(child_node, new_xblock, store, user_id=user_id)
if isinstance(new_xblock, LibraryContentBlock):
# Special case handling for library content. If we need this for other blocks in the future, it can be made into
# an API, and we'd call new_block.studio_post_paste() instead of this code.
# In this case, we want to pull the children from the library and let library_tools assign their IDs.
new_xblock.tools.update_children(new_xblock, version=new_xblock.source_library_version)
else:
for child_node in child_nodes:
_import_xml_node_to_parent(child_node, new_xblock, store, user_id=user_id)
return new_xblock


Expand Down
86 changes: 83 additions & 3 deletions cms/djangoapps/contentstore/views/tests/test_clipboard_paste.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,15 @@
APIs.
"""
import ddt
from django.test import LiveServerTestCase
from opaque_keys.edx.keys import UsageKey
from rest_framework.test import APIClient
from xmodule.modulestore.django import contentstore
from xmodule.modulestore.django import contentstore, modulestore
from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase, upload_file_to_course
from xmodule.modulestore.tests.factories import BlockFactory, CourseFactory, ToyCourseFactory
from xmodule.modulestore.tests.factories import BlockFactory, CourseFactory, LibraryFactory, ToyCourseFactory

from cms.djangoapps.contentstore.utils import reverse_usage_url
from cms.djangoapps.contentstore.tests.utils import AjaxEnabledTestClient

CLIPBOARD_ENDPOINT = "/api/content-staging/v1/clipboard/"
XBLOCK_ENDPOINT = "/xblock/"
Expand Down Expand Up @@ -109,7 +113,7 @@ def test_copy_and_paste_component(self, block_args):
"""
Test copying a component (XBlock) from one course into another
"""
source_course = CourseFactory.create(display_name='Destination Course')
source_course = CourseFactory.create(display_name='Source Course')
source_block = BlockFactory.create(parent_location=source_course.location, **block_args)

dest_course = CourseFactory.create(display_name='Destination Course')
Expand Down Expand Up @@ -204,3 +208,79 @@ def test_paste_with_assets(self):
source_pic2_hash = contentstore().find(source_course.id.make_asset_key("asset", "picture2.jpg")).content_digest
dest_pic2_hash = contentstore().find(dest_course_key.make_asset_key("asset", "picture2.jpg")).content_digest
assert source_pic2_hash != dest_pic2_hash # Because there was a conflict, this file was unchanged.


class ClipboardLibraryContentPasteTestCase(LiveServerTestCase, ModuleStoreTestCase):
"""
Test Clipboard Paste functionality with library content
"""

def setUp(self):
"""
Set up a v2 Content Library and a library content block
"""
super().setUp()
self.client = AjaxEnabledTestClient()
self.client.login(username=self.user.username, password=self.user_password)
self.store = modulestore()

def test_paste_library_content_block_v1(self):
"""
Same as the above test, but uses modulestore (v1) content library
"""
library = LibraryFactory.create()
data = {
'parent_locator': str(library.location),
'category': 'html',
'display_name': 'HTML Content',
}
response = self.client.ajax_post(XBLOCK_ENDPOINT, data)
self.assertEqual(response.status_code, 200)
course = CourseFactory.create(display_name='Course')
orig_lc_block = BlockFactory.create(
parent=course,
category="library_content",
source_library_id=str(library.location.library_key),
display_name="LC Block",
publish_item=False,
)
orig_lc_block.refresh_children()
orig_child = self.store.get_item(orig_lc_block.children[0])
assert orig_child.display_name == "HTML Content"
# Copy a library content block that has children:
copy_response = self.client.post(CLIPBOARD_ENDPOINT, {
"usage_key": str(orig_lc_block.location)
}, format="json")
assert copy_response.status_code == 200

# Paste the Library content block:
paste_response = self.client.ajax_post(XBLOCK_ENDPOINT, {
"parent_locator": str(course.location),
"staged_content": "clipboard",
})
assert paste_response.status_code == 200
dest_lc_block_key = UsageKey.from_string(paste_response.json()["locator"])

# Get the ID of the new child:
dest_lc_block = self.store.get_item(dest_lc_block_key)
dest_child = self.store.get_item(dest_lc_block.children[0])
assert dest_child.display_name == "HTML Content"

# Importantly, the ID of the child must not changed when the library content is synced.
# Otherwise, user state saved against this child will be lost when it syncs.
dest_lc_block.refresh_children()
updated_dest_child = self.store.get_item(dest_lc_block.children[0])
assert dest_child.location == updated_dest_child.location

def _sync_lc_block_from_library(self, attr_name):
"""
Helper method to "sync" a Library Content Block by [re-]fetching its
children from the library.
"""
usage_key = getattr(self, attr_name).location
# It's easiest to do this via the REST API:
handler_url = reverse_usage_url('preview_handler', usage_key, kwargs={'handler': 'upgrade_and_sync'})
response = self.client.post(handler_url)
assert response.status_code == 200
# Now reload the block and make sure the child is in place
setattr(self, attr_name, self.store.get_item(usage_key)) # we must reload after upgrade_and_sync
4 changes: 2 additions & 2 deletions common/test/data/course_after_rename/about/overview.html
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ <h2>Requirements</h2>
<h2>Course Staff</h2>
<article class="teacher">
<div class="teacher-image">
<img src="/static/images/placeholder-faculty.png" align="left" style="margin: 0 20px 0;" alt="Course Staff Image #1" />
<img src="/static/images/placeholder-faculty.png" align="left" alt="Course Staff Image #1" />
</div>

<h3>Staff Member #1</h3>
Expand All @@ -23,7 +23,7 @@ <h3>Staff Member #1</h3>

<article class="teacher">
<div class="teacher-image">
<img src="/static/images/placeholder-faculty.png" align="left" style="margin: 0 20px 0;" alt="Course Staff Image #2" />
<img src="/static/images/placeholder-faculty.png" align="left" alt="Course Staff Image #2" />
</div>

<h3>Staff Member #2</h3>
Expand Down
4 changes: 2 additions & 2 deletions common/test/data/course_before_rename/about/overview.html
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ <h2>Requirements</h2>
<h2>Course Staff</h2>
<article class="teacher">
<div class="teacher-image">
<img src="/static/images/placeholder-faculty.png" align="left" style="margin: 0 20px 0;" alt="Course Staff Image #1" />
<img src="/static/images/placeholder-faculty.png" align="left" alt="Course Staff Image #1" />
</div>

<h3>Staff Member #1</h3>
Expand All @@ -23,7 +23,7 @@ <h3>Staff Member #1</h3>

<article class="teacher">
<div class="teacher-image">
<img src="/static/images/placeholder-faculty.png" align="left" style="margin: 0 20px 0;" alt="Course Staff Image #2" />
<img src="/static/images/placeholder-faculty.png" align="left" alt="Course Staff Image #2" />
</div>

<h3>Staff Member #2</h3>
Expand Down
4 changes: 2 additions & 2 deletions common/test/data/course_info_updates/about/overview.html
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ <h2>Prerequisites</h2>
<h2>Course Staff</h2>
<article class="teacher">
<div class="teacher-image">
<img src="/static/images/placeholder-faculty.png" align="left" style="margin: 0 20px 0;" alt="Course Staff Image #1" />
<img src="/static/images/placeholder-faculty.png" align="left" alt="Course Staff Image #1" />
</div>

<h3>Staff Member #1</h3>
Expand All @@ -23,7 +23,7 @@ <h3>Staff Member #1</h3>

<article class="teacher">
<div class="teacher-image">
<img src="/static/images/placeholder-faculty.png" align="left" style="margin: 0 20px 0;" alt="Course Staff Image #2" />
<img src="/static/images/placeholder-faculty.png" align="left" alt="Course Staff Image #2" />
</div>

<h3>Staff Member #2</h3>
Expand Down
4 changes: 2 additions & 2 deletions common/test/data/manual-testing-complete/about/overview.html
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ <h2>Prerequisites</h2>
<h2>Course Staff</h2>
<article class="teacher">
<div class="teacher-image">
<img src="/static/images/placeholder-faculty.png" align="left" style="margin: 0 20px 0;" alt="Course Staff Image #1" />
<img src="/static/images/placeholder-faculty.png" align="left" alt="Course Staff Image #1" />
</div>

<h3>Staff Member #1</h3>
Expand All @@ -23,7 +23,7 @@ <h3>Staff Member #1</h3>

<article class="teacher">
<div class="teacher-image">
<img src="/static/images/placeholder-faculty.png" align="left" style="margin: 0 20px 0;" alt="Course Staff Image #2" />
<img src="/static/images/placeholder-faculty.png" align="left" alt="Course Staff Image #2" />
</div>

<h3>Staff Member #2</h3>
Expand Down
4 changes: 2 additions & 2 deletions common/test/data/scoreable/about/overview.html
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ <h2>Requirements</h2>
<h2>Course Staff</h2>
<article class="teacher">
<div class="teacher-image">
<img src="/static/images/placeholder-faculty.png" align="left" style="margin: 0 20px 0;" alt="Course Staff Image #1" />
<img src="/static/images/placeholder-faculty.png" align="left" alt="Course Staff Image #1" />
</div>

<h3>Staff Member #1</h3>
Expand All @@ -23,7 +23,7 @@ <h3>Staff Member #1</h3>

<article class="teacher">
<div class="teacher-image">
<img src="/static/images/placeholder-faculty.png" align="left" style="margin: 0 20px 0;" alt="Course Staff Image #2" />
<img src="/static/images/placeholder-faculty.png" align="left" alt="Course Staff Image #2" />
</div>

<h3>Staff Member #2</h3>
Expand Down
12 changes: 11 additions & 1 deletion openedx/core/djangoapps/content_libraries/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,15 @@
from xblock.exceptions import XBlockNotFoundError
from edx_rest_api_client.client import OAuthAPIClient
from openedx.core.djangoapps.content_libraries import permissions
from openedx.core.djangoapps.content_libraries.constants import DRAFT_NAME, COMPLEX
# pylint: disable=unused-import
from openedx.core.djangoapps.content_libraries.constants import (
ALL_RIGHTS_RESERVED,
CC_4_BY,
COMPLEX,
DRAFT_NAME,
PROBLEM,
VIDEO,
)
from openedx.core.djangoapps.content_libraries.library_bundle import LibraryBundle
from openedx.core.djangoapps.content_libraries.libraries_index import ContentLibraryIndexer, LibraryBlockIndexer
from openedx.core.djangoapps.content_libraries.models import (
Expand Down Expand Up @@ -425,6 +433,8 @@ def create_library(

allow_public_read: Allow anyone to view blocks (including source) in Studio?

library_type: Deprecated parameter, not really used. Set to COMPLEX.

Returns a ContentLibraryMetadata instance.
"""
assert isinstance(collection_uuid, UUID)
Expand Down
16 changes: 10 additions & 6 deletions openedx/core/djangoapps/theming/template_loaders.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,17 @@ class ThemeFilesystemLoader(FilesystemLoader):
is_usable = True
_accepts_engine_in_init = True

def __init__(self, engine, dirs=None):
if not dirs:
self.dirs = engine.dirs
def get_dirs(self):
"""
Override get_dirs method.

Make the theme templates a priority, avoiding cashing templates for django ones.
"""
dirs = super().get_dirs()
theme_dirs = self.get_theme_template_sources()
if isinstance(theme_dirs, list):
self.dirs = theme_dirs + self.dirs
super().__init__(engine, self.dirs)
if theme_dirs:
dirs = theme_dirs + dirs
return dirs

@staticmethod
def get_theme_template_sources():
Expand Down
4 changes: 2 additions & 2 deletions xmodule/templates/about/overview.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ data: |
<h2>Course Staff</h2>
<article class="teacher">
<div class="teacher-image">
<img src="/static/images/placeholder-faculty.png" align="left" style="margin: 0 20px 0;" alt="Course Staff Image #1" />
<img src="/static/images/placeholder-faculty.png" align="left" alt="Course Staff Image #1" />
</div>

<h3>Staff Member #1</h3>
Expand All @@ -28,7 +28,7 @@ data: |

<article class="teacher">
<div class="teacher-image">
<img src="/static/images/placeholder-faculty.png" align="left" style="margin: 0 20px 0;" alt="Course Staff Image #2" />
<img src="/static/images/placeholder-faculty.png" align="left" alt="Course Staff Image #2" />
</div>

<h3>Staff Member #2</h3>
Expand Down
6 changes: 0 additions & 6 deletions xmodule/tests/test_vertical.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,10 @@
import pytz
from django.contrib.auth.models import AnonymousUser
from django.test import override_settings
from edx_toggles.toggles.testutils import override_waffle_switch
from fs.memoryfs import MemoryFS
from openedx_filters import PipelineStep
from openedx_filters.learning.filters import VerticalBlockChildRenderStarted, VerticalBlockRenderCompleted

from ..vertical_block import XBLOCK_SKILL_TAG_VERIFICATION_SWITCH
from ..x_module import AUTHOR_VIEW, PUBLIC_VIEW, STUDENT_VIEW
from . import prepare_block_runtime
from .helpers import StubUserService
Expand Down Expand Up @@ -362,7 +360,6 @@ def test_render_studio_view(self):
},
},
)
@override_waffle_switch(XBLOCK_SKILL_TAG_VERIFICATION_SWITCH, True)
def test_vertical_block_child_render_started_filter_execution(self):
"""
Test the VerticalBlockChildRenderStarted filter's effects on student view.
Expand All @@ -385,7 +382,6 @@ def test_vertical_block_child_render_started_filter_execution(self):
},
},
)
@override_waffle_switch(XBLOCK_SKILL_TAG_VERIFICATION_SWITCH, True)
def test_vertical_block_child_render_is_skipped_on_filter_exception(self):
"""
Test VerticalBlockChildRenderStarted filter can be used to skip child blocks.
Expand All @@ -409,7 +405,6 @@ def test_vertical_block_child_render_is_skipped_on_filter_exception(self):
},
},
)
@override_waffle_switch(XBLOCK_SKILL_TAG_VERIFICATION_SWITCH, True)
def test_vertical_block_render_completed_filter_execution(self):
"""
Test the VerticalBlockRenderCompleted filter's execution.
Expand All @@ -432,7 +427,6 @@ def test_vertical_block_render_completed_filter_execution(self):
},
},
)
@override_waffle_switch(XBLOCK_SKILL_TAG_VERIFICATION_SWITCH, True)
def test_vertical_block_render_output_is_changed_on_filter_exception(self):
"""
Test VerticalBlockRenderCompleted filter can be used to prevent vertical block from rendering.
Expand Down
Loading
Loading