Skip to content

Commit

Permalink
feat: return publishing information on get component endpoint [FC-006…
Browse files Browse the repository at this point in the history
…2] (#35476)

* feat: return publishing information on get component endpoint

* feat: read data from component.versioning.draft

* test: update tests

* chore: update openedx-learning

---------

Co-authored-by: Jillian <[email protected]>
Co-authored-by: Chris Chávez <[email protected]>
  • Loading branch information
3 people authored Sep 16, 2024
1 parent e669400 commit a94b5af
Show file tree
Hide file tree
Showing 9 changed files with 65 additions and 14 deletions.
17 changes: 16 additions & 1 deletion openedx/core/djangoapps/content_libraries/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -218,8 +218,12 @@ class LibraryXBlockMetadata:
modified = attr.ib(type=datetime)
display_name = attr.ib("")
last_published = attr.ib(default=None, type=datetime)
last_draft_created = attr.ib(default=None, type=datetime)
last_draft_created_by = attr.ib("")
published_by = attr.ib("")
has_unpublished_changes = attr.ib(False)
tags_count = attr.ib(0)
created = attr.ib(default=None, type=datetime)

@classmethod
def from_component(cls, library_key, component):
Expand All @@ -228,6 +232,14 @@ def from_component(cls, library_key, component):
"""
last_publish_log = component.versioning.last_publish_log

published_by = None
if last_publish_log and last_publish_log.published_by:
published_by = last_publish_log.published_by.username

draft = component.versioning.draft
last_draft_created = draft.created if draft else None
last_draft_created_by = draft.publishable_entity_version.created_by if draft else None

return cls(
usage_key=LibraryUsageLocatorV2(
library_key,
Expand All @@ -238,7 +250,10 @@ def from_component(cls, library_key, component):
created=component.created,
modified=component.versioning.draft.created,
last_published=None if last_publish_log is None else last_publish_log.published_at,
has_unpublished_changes=component.versioning.has_unpublished_changes
published_by=published_by,
last_draft_created=last_draft_created,
last_draft_created_by=last_draft_created_by,
has_unpublished_changes=component.versioning.has_unpublished_changes,
)


Expand Down
5 changes: 5 additions & 0 deletions openedx/core/djangoapps/content_libraries/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,12 @@ class LibraryXBlockMetadataSerializer(serializers.Serializer):

block_type = serializers.CharField(source="usage_key.block_type")
display_name = serializers.CharField(read_only=True)
last_published = serializers.DateTimeField(format=DATETIME_FORMAT, read_only=True)
published_by = serializers.CharField(read_only=True)
last_draft_created = serializers.DateTimeField(format=DATETIME_FORMAT, read_only=True)
last_draft_created_by = serializers.CharField(read_only=True)
has_unpublished_changes = serializers.BooleanField(read_only=True)
created = serializers.DateTimeField(format=DATETIME_FORMAT, read_only=True)

# When creating a new XBlock in a library, the slug becomes the ID part of
# the definition key and usage key:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,11 @@
from unittest import skip

import ddt
from datetime import datetime, timezone
from uuid import uuid4
from django.contrib.auth.models import Group
from django.test.client import Client
from freezegun import freeze_time
from organizations.models import Organization
from rest_framework.test import APITestCase

Expand Down Expand Up @@ -270,12 +272,18 @@ def test_library_blocks(self):
assert self._get_library_blocks(lib_id)['results'] == []

# Add a 'problem' XBlock to the library:
block_data = self._add_block_to_library(lib_id, "problem", "ࠒröblæm1")
create_date = datetime(2024, 6, 6, 6, 6, 6, tzinfo=timezone.utc)
with freeze_time(create_date):
block_data = self._add_block_to_library(lib_id, "problem", "ࠒröblæm1")
self.assertDictContainsEntries(block_data, {
"id": "lb:CL-TEST:téstlꜟط:problem:ࠒröblæm1",
"display_name": "Blank Problem",
"block_type": "problem",
"has_unpublished_changes": True,
"last_published": None,
"published_by": None,
"last_draft_created": create_date.isoformat().replace('+00:00', 'Z'),
"last_draft_created_by": "Bob",
})
block_id = block_data["id"]
# Confirm that the result contains a definition key, but don't check its value,
Expand All @@ -287,10 +295,14 @@ def test_library_blocks(self):
assert self._get_library(lib_id)['has_unpublished_changes'] is True

# Publish the changes:
self._commit_library_changes(lib_id)
publish_date = datetime(2024, 7, 7, 7, 7, 7, tzinfo=timezone.utc)
with freeze_time(publish_date):
self._commit_library_changes(lib_id)
assert self._get_library(lib_id)['has_unpublished_changes'] is False
# And now the block information should also show that block has no unpublished changes:
block_data["has_unpublished_changes"] = False
block_data["last_published"] = publish_date.isoformat().replace('+00:00', 'Z')
block_data["published_by"] = "Bob"
self.assertDictContainsEntries(self._get_library_block(block_id), block_data)
assert self._get_library_blocks(lib_id)['results'] == [block_data]

Expand All @@ -311,13 +323,16 @@ def test_library_blocks(self):
</multiplechoiceresponse>
</problem>
""".strip()
self._set_library_block_olx(block_id, new_olx)
update_date = datetime(2024, 8, 8, 8, 8, 8, tzinfo=timezone.utc)
with freeze_time(update_date):
self._set_library_block_olx(block_id, new_olx)
# now reading it back, we should get that exact OLX (no change to whitespace etc.):
assert self._get_library_block_olx(block_id) == new_olx
# And the display name and "unpublished changes" status of the block should be updated:
self.assertDictContainsEntries(self._get_library_block(block_id), {
"display_name": "New Multi Choice Question",
"has_unpublished_changes": True,
"last_draft_created": update_date.isoformat().replace('+00:00', 'Z')
})

# Now view the XBlock's student_view (including draft changes):
Expand Down Expand Up @@ -358,12 +373,18 @@ def test_library_blocks_studio_view(self):
assert self._get_library_blocks(lib_id)['results'] == []

# Add a 'html' XBlock to the library:
block_data = self._add_block_to_library(lib_id, "html", "html1")
create_date = datetime(2024, 6, 6, 6, 6, 6, tzinfo=timezone.utc)
with freeze_time(create_date):
block_data = self._add_block_to_library(lib_id, "html", "html1")
self.assertDictContainsEntries(block_data, {
"id": "lb:CL-TEST:testlib2:html:html1",
"display_name": "Text",
"block_type": "html",
"has_unpublished_changes": True,
"last_published": None,
"published_by": None,
"last_draft_created": create_date.isoformat().replace('+00:00', 'Z'),
"last_draft_created_by": "Bob",
})
block_id = block_data["id"]

Expand All @@ -372,24 +393,32 @@ def test_library_blocks_studio_view(self):
assert self._get_library(lib_id)['has_unpublished_changes'] is True

# Publish the changes:
self._commit_library_changes(lib_id)
publish_date = datetime(2024, 7, 7, 7, 7, 7, tzinfo=timezone.utc)
with freeze_time(publish_date):
self._commit_library_changes(lib_id)
assert self._get_library(lib_id)['has_unpublished_changes'] is False
# And now the block information should also show that block has no unpublished changes:
block_data["has_unpublished_changes"] = False
block_data["last_published"] = publish_date.isoformat().replace('+00:00', 'Z')
block_data["published_by"] = "Bob"
self.assertDictContainsEntries(self._get_library_block(block_id), block_data)
assert self._get_library_blocks(lib_id)['results'] == [block_data]

# Now update the block's OLX:
orig_olx = self._get_library_block_olx(block_id)
assert '<html' in orig_olx
new_olx = "<html><b>Hello world!</b></html>"
self._set_library_block_olx(block_id, new_olx)

update_date = datetime(2024, 8, 8, 8, 8, 8, tzinfo=timezone.utc)
with freeze_time(update_date):
self._set_library_block_olx(block_id, new_olx)
# now reading it back, we should get that exact OLX (no change to whitespace etc.):
assert self._get_library_block_olx(block_id) == new_olx
# And the display name and "unpublished changes" status of the block should be updated:
self.assertDictContainsEntries(self._get_library_block(block_id), {
"display_name": "Text",
"has_unpublished_changes": True,
"last_draft_created": update_date.isoformat().replace('+00:00', 'Z')
})

# Now view the XBlock's studio view (including draft changes):
Expand Down Expand Up @@ -1019,6 +1048,7 @@ def test_library_paste_clipboard(self):
# the the block in the clipboard
self.assertDictContainsEntries(self._get_library_block(paste_data["id"]), {
**block_data,
"last_draft_created_by": None,
"id": f"lb:CL-TEST:test_lib_paste_clipboard:problem:{pasted_block_id}",
})

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,15 @@
import time
from unittest.mock import patch

from openedx_tagging.core.tagging.models import ObjectTag
from organizations.models import Organization

from openedx.core.djangoapps.content_libraries import api as library_api
from xmodule.modulestore.tests.django_utils import TEST_DATA_SPLIT_MODULESTORE, ModuleStoreTestCase
from xmodule.modulestore.tests.factories import BlockFactory, CourseFactory

from .. import api
from ..helpers.objecttag_export_helpers import TaggedContent, build_object_tree_with_objecttags, iterate_with_level
from openedx_tagging.core.tagging.models import ObjectTag
from organizations.models import Organization


class TestGetAllObjectTagsMixin:
Expand Down
2 changes: 1 addition & 1 deletion requirements/constraints.txt
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ libsass==0.10.0
click==8.1.6

# pinning this version to avoid updates while the library is being developed
openedx-learning==0.11.4
openedx-learning==0.11.5

# Open AI version 1.0.0 dropped support for openai.ChatCompletion which is currently in use in enterprise.
openai<=0.28.1
Expand Down
2 changes: 1 addition & 1 deletion requirements/edx/base.txt
Original file line number Diff line number Diff line change
Expand Up @@ -826,7 +826,7 @@ openedx-filters==1.9.0
# -r requirements/edx/kernel.in
# lti-consumer-xblock
# ora2
openedx-learning==0.11.4
openedx-learning==0.11.5
# 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 @@ -1374,7 +1374,7 @@ openedx-filters==1.9.0
# -r requirements/edx/testing.txt
# lti-consumer-xblock
# ora2
openedx-learning==0.11.4
openedx-learning==0.11.5
# 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 @@ -985,7 +985,7 @@ openedx-filters==1.9.0
# -r requirements/edx/base.txt
# lti-consumer-xblock
# ora2
openedx-learning==0.11.4
openedx-learning==0.11.5
# 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 @@ -1036,7 +1036,7 @@ openedx-filters==1.9.0
# -r requirements/edx/base.txt
# lti-consumer-xblock
# ora2
openedx-learning==0.11.4
openedx-learning==0.11.5
# via
# -c requirements/edx/../constraints.txt
# -r requirements/edx/base.txt
Expand Down

0 comments on commit a94b5af

Please sign in to comment.