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

Make copied tags editable again after breaking the upstream link to library content [FC-0076] #36228

Merged
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
28 changes: 26 additions & 2 deletions cms/djangoapps/contentstore/signals/handlers.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,17 @@
from django.dispatch import receiver
from edx_toggles.toggles import SettingToggle
from opaque_keys.edx.keys import CourseKey
from openedx_events.content_authoring.data import CourseCatalogData, CourseData, CourseScheduleData, XBlockData
from openedx_events.content_authoring.data import (
CourseCatalogData,
CourseData,
CourseScheduleData,
LibraryBlockData,
XBlockData,
)
from openedx_events.content_authoring.signals import (
COURSE_CATALOG_INFO_CHANGED,
COURSE_IMPORT_COMPLETED,
LIBRARY_BLOCK_DELETED,
XBLOCK_CREATED,
XBLOCK_DELETED,
XBLOCK_UPDATED,
Expand All @@ -38,7 +45,11 @@
from xmodule.modulestore.exceptions import ItemNotFoundError

from ..models import PublishableEntityLink
from ..tasks import create_or_update_upstream_links, handle_create_or_update_xblock_upstream_link
from ..tasks import (
create_or_update_upstream_links,
handle_create_or_update_xblock_upstream_link,
handle_unlink_upstream_block,
)
from .signals import GRADING_POLICY_CHANGED

log = logging.getLogger(__name__)
Expand Down Expand Up @@ -287,3 +298,16 @@ def handle_new_course_import(**kwargs):
force=True,
replace=True
)


@receiver(LIBRARY_BLOCK_DELETED)
def unlink_upstream_block_handler(**kwargs):
"""
Handle unlinking the upstream (library) block from any downstream (course) blocks.
"""
library_block = kwargs.get("library_block", None)
if not library_block or not isinstance(library_block, LibraryBlockData):
log.error("Received null or incorrect data for event")
return

handle_unlink_upstream_block.delay(str(library_block.usage_key))
21 changes: 21 additions & 0 deletions cms/djangoapps/contentstore/tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@
from common.djangoapps.util.monitoring import monitor_import_failure
from openedx.core.djangoapps.content.learning_sequences.api import key_supports_outlines
from openedx.core.djangoapps.content_libraries import api as v2contentlib_api
from openedx.core.djangoapps.content_tagging.api import make_copied_tags_editable
from openedx.core.djangoapps.course_apps.toggles import exams_ida_enabled
from openedx.core.djangoapps.discussions.config.waffle import ENABLE_NEW_STRUCTURE_DISCUSSIONS
from openedx.core.djangoapps.discussions.models import DiscussionsConfiguration, Provider
Expand Down Expand Up @@ -1466,3 +1467,23 @@ def create_or_update_upstream_links(
for xblock in xblocks:
create_or_update_xblock_upstream_link(xblock, course_key_str, created)
course_status.update_status(LearningContextLinksStatusChoices.COMPLETED)


@shared_task
@set_code_owner_attribute
def handle_unlink_upstream_block(upstream_usage_key_string: str) -> None:
"""
Handle updates needed to downstream blocks when the upstream link is severed.
"""
ensure_cms("handle_unlink_upstream_block may only be executed in a CMS context")

try:
upstream_usage_key = UsageKey.from_string(upstream_usage_key_string)
except (InvalidKeyError):
LOGGER.exception(f'Invalid upstream usage_key: {upstream_usage_key_string}')
return

for link in PublishableEntityLink.objects.filter(
upstream_usage_key=upstream_usage_key,
):
make_copied_tags_editable(str(link.downstream_usage_key))
25 changes: 24 additions & 1 deletion cms/djangoapps/contentstore/views/tests/test_clipboard_paste.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,13 @@
import ddt
from opaque_keys.edx.keys import UsageKey
from rest_framework.test import APIClient
from openedx_events.content_authoring.signals import (
LIBRARY_BLOCK_DELETED,
XBLOCK_CREATED,
XBLOCK_DELETED,
XBLOCK_UPDATED,
)
from openedx_events.tests.utils import OpenEdxEventsTestMixin
from openedx_tagging.core.tagging.models import Tag
from organizations.models import Organization
from xmodule.modulestore.django import contentstore, modulestore
Expand Down Expand Up @@ -393,10 +400,16 @@ def test_paste_with_assets(self):
assert source_pic2_hash != dest_pic2_hash # Because there was a conflict, this file was unchanged.


class ClipboardPasteFromV2LibraryTestCase(ModuleStoreTestCase):
class ClipboardPasteFromV2LibraryTestCase(OpenEdxEventsTestMixin, ModuleStoreTestCase):
"""
Test Clipboard Paste functionality with a "new" (as of Sumac) library
"""
ENABLED_OPENEDX_EVENTS = [
LIBRARY_BLOCK_DELETED.event_type,
XBLOCK_CREATED.event_type,
XBLOCK_DELETED.event_type,
XBLOCK_UPDATED.event_type,
]

def setUp(self):
"""
Expand Down Expand Up @@ -477,6 +490,16 @@ def test_paste_from_library_read_only_tags(self):
assert object_tag.value in self.lib_block_tags
assert object_tag.is_copied

# If we delete the upstream library block...
library_api.delete_library_block(self.lib_block_key)

# ...the copied tags remain, but should no longer be marked as "copied"
object_tags = tagging_api.get_object_tags(new_block_key)
assert len(object_tags) == len(self.lib_block_tags)
for object_tag in object_tags:
assert object_tag.value in self.lib_block_tags
assert not object_tag.is_copied

Comment on lines +493 to +502
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since we depend on openedx-events for this to work, it would be safe to explicitly enable the required events to make sure that the test passes (had an issue before with a test case that failed only in CI but passed locally, most probably due to some events being disabled in some previous test in CI).

You can inherit from OpenEdxEventsTestMixin (Note that it should be added before ModuleStoreTestCase) and enable below events.

class ClipboardPasteFromV2LibraryTestCase(OpenEdxEventsTestMixin, ModuleStoreTestCase):
    """
    Test Clipboard Paste functionality with a "new" (as of Sumac) library
    """

    ENABLED_OPENEDX_EVENTS = [
        LIBRARY_BLOCK_DELETED.event_type,
        XBLOCK_UPDATED.event_type,
    ]

def test_paste_from_library_copies_asset(self):
"""
Assets from a library component copied into a subdir of Files & Uploads.
Expand Down
1 change: 1 addition & 0 deletions openedx/core/djangoapps/content_tagging/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -441,3 +441,4 @@ def tag_object(
get_object_tags = oel_tagging.get_object_tags
add_tag_to_taxonomy = oel_tagging.add_tag_to_taxonomy
copy_tags_as_read_only = oel_tagging.copy_tags
make_copied_tags_editable = oel_tagging.unmark_copied_tags
2 changes: 1 addition & 1 deletion requirements/constraints.txt
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ optimizely-sdk<5.0
# Date: 2023-09-18
# pinning this version to avoid updates while the library is being developed
# Issue for unpinning: https://github.com/openedx/edx-platform/issues/35269
openedx-learning==0.18.2
openedx-learning==0.18.3

# Date: 2023-11-29
# Open AI version 1.0.0 dropped support for openai.ChatCompletion which is currently in use in enterprise.
Expand Down
2 changes: 1 addition & 1 deletion requirements/edx/base.txt
Original file line number Diff line number Diff line change
Expand Up @@ -827,7 +827,7 @@ openedx-filters==1.12.0
# ora2
openedx-forum==0.1.6
# via -r requirements/edx/kernel.in
openedx-learning==0.18.2
openedx-learning==0.18.3
# via
# -c requirements/edx/../constraints.txt
# -r requirements/edx/kernel.in
Expand Down
2 changes: 1 addition & 1 deletion requirements/edx/development.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1381,7 +1381,7 @@ openedx-forum==0.1.6
# via
# -r requirements/edx/doc.txt
# -r requirements/edx/testing.txt
openedx-learning==0.18.2
openedx-learning==0.18.3
# via
# -c requirements/edx/../constraints.txt
# -r requirements/edx/doc.txt
Expand Down
2 changes: 1 addition & 1 deletion requirements/edx/doc.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1000,7 +1000,7 @@ openedx-filters==1.12.0
# ora2
openedx-forum==0.1.6
# via -r requirements/edx/base.txt
openedx-learning==0.18.2
openedx-learning==0.18.3
# via
# -c requirements/edx/../constraints.txt
# -r requirements/edx/base.txt
Expand Down
2 changes: 1 addition & 1 deletion requirements/edx/testing.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1048,7 +1048,7 @@ openedx-filters==1.12.0
# ora2
openedx-forum==0.1.6
# via -r requirements/edx/base.txt
openedx-learning==0.18.2
openedx-learning==0.18.3
# via
# -c requirements/edx/../constraints.txt
# -r requirements/edx/base.txt
Expand Down
Loading