feat: New fields in library v2 details API view (#35091)

This commit is contained in:
Chris Chávez
2024-08-01 13:50:13 -05:00
committed by GitHub
parent a7f6cf160c
commit 2788f2bc3b
3 changed files with 31 additions and 11 deletions

View File

@@ -156,6 +156,9 @@ class ContentLibraryMetadata:
version = attr.ib(0)
type = attr.ib(default=COMPLEX)
last_published = attr.ib(default=None, type=datetime)
last_draft_created = attr.ib(default=None, type=datetime)
last_draft_created_by = attr.ib(default=None, type=datetime)
published_by = attr.ib("")
has_unpublished_changes = attr.ib(False)
# has_unpublished_deletes will be true when the draft version of the library's bundle
# contains deletes of any XBlocks that were in the most recently published version
@@ -168,6 +171,8 @@ class ContentLibraryMetadata:
# Studio, use it in their courses, and copy content out of this library.
allow_public_read = attr.ib(False)
license = attr.ib("")
created = attr.ib(default=None, type=datetime)
updated = attr.ib(default=None, type=datetime)
class AccessLevel:
@@ -350,8 +355,11 @@ def get_library(library_key):
learning_package = ref.learning_package
num_blocks = authoring_api.get_all_drafts(learning_package.id).count()
last_publish_log = authoring_api.get_last_publish(learning_package.id)
has_unpublished_changes = authoring_api.get_entities_with_unpublished_changes(learning_package.id) \
.exists()
last_draft_log = authoring_api.get_entities_with_unpublished_changes(learning_package.id) \
.order_by('-created').first()
last_draft_created = last_draft_log.created if last_draft_log else None
last_draft_created_by = last_draft_log.created_by.username if last_draft_log and last_draft_log.created_by else None
has_unpublished_changes = last_draft_log is not None
# TODO: I'm doing this one to match already-existing behavior, but this is
# something that we should remove. It exists to accomodate some complexities
@@ -377,6 +385,9 @@ def get_library(library_key):
# libraries. The top level version stays for now because LibraryContentBlock
# uses it, but that should hopefully change before the Redwood release.
version = 0 if last_publish_log is None else last_publish_log.pk
published_by = None
if last_publish_log and last_publish_log.published_by:
published_by = last_publish_log.published_by.username
return ContentLibraryMetadata(
key=library_key,
@@ -386,12 +397,17 @@ def get_library(library_key):
num_blocks=num_blocks,
version=version,
last_published=None if last_publish_log is None else last_publish_log.published_at,
published_by=published_by,
last_draft_created=last_draft_created,
last_draft_created_by=last_draft_created_by,
allow_lti=ref.allow_lti,
allow_public_learning=ref.allow_public_learning,
allow_public_read=ref.allow_public_read,
has_unpublished_changes=has_unpublished_changes,
has_unpublished_deletes=has_unpublished_deletes,
license=ref.license,
created=learning_package.created,
updated=learning_package.updated,
)
@@ -735,7 +751,7 @@ def set_library_block_olx(usage_key, new_olx_str):
)
def create_library_block(library_key, block_type, definition_id):
def create_library_block(library_key, block_type, definition_id, user_id=None):
"""
Create a new XBlock in this library of the specified type (e.g. "html").
"""
@@ -777,7 +793,7 @@ def create_library_block(library_key, block_type, definition_id):
if _component_exists(usage_key):
raise LibraryBlockAlreadyExists(f"An XBlock with ID '{usage_key}' already exists")
_create_component_for_block(ref, usage_key)
_create_component_for_block(ref, usage_key, user_id=user_id)
# Now return the metadata about the new block:
LIBRARY_BLOCK_CREATED.send_event(
@@ -816,7 +832,7 @@ def get_or_create_olx_media_type(block_type: str) -> MediaType:
)
def _create_component_for_block(content_lib, usage_key):
def _create_component_for_block(content_lib, usage_key, user_id=None):
"""
Create a Component for an XBlock type, and initialize it.
@@ -847,7 +863,7 @@ def _create_component_for_block(content_lib, usage_key):
local_key=usage_key.block_id,
title=display_name,
created=now,
created_by=None,
created_by=user_id,
)
content = authoring_api.get_or_create_text_content(
learning_package.id,
@@ -951,13 +967,13 @@ def get_allowed_block_types(library_key): # pylint: disable=unused-argument
return info
def publish_changes(library_key):
def publish_changes(library_key, user_id=None):
"""
Publish all pending changes to the specified library.
"""
learning_package = ContentLibrary.objects.get_by_key(library_key).learning_package
authoring_api.publish_all_drafts(learning_package.id)
authoring_api.publish_all_drafts(learning_package.id, published_by=user_id)
CONTENT_LIBRARY_UPDATED.send_event(
content_library=ContentLibraryData(

View File

@@ -36,12 +36,14 @@ class ContentLibraryMetadataSerializer(serializers.Serializer):
org = serializers.SlugField(source="key.org")
slug = serializers.CharField(source="key.slug", validators=(validate_unicode_slug, ))
bundle_uuid = serializers.UUIDField(format='hex_verbose', read_only=True)
#collection_uuid = serializers.UUIDField(format='hex_verbose', write_only=True)
title = serializers.CharField()
description = serializers.CharField(allow_blank=True)
num_blocks = serializers.IntegerField(read_only=True)
version = serializers.IntegerField(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)
allow_lti = serializers.BooleanField(default=False, read_only=True)
allow_public_learning = serializers.BooleanField(default=False)
allow_public_read = serializers.BooleanField(default=False)
@@ -49,6 +51,8 @@ class ContentLibraryMetadataSerializer(serializers.Serializer):
has_unpublished_deletes = serializers.BooleanField(read_only=True)
license = serializers.ChoiceField(choices=LICENSE_OPTIONS, default=ALL_RIGHTS_RESERVED)
can_edit_library = serializers.SerializerMethodField()
created = serializers.DateTimeField(format=DATETIME_FORMAT, read_only=True)
updated = serializers.DateTimeField(format=DATETIME_FORMAT, read_only=True)
def get_can_edit_library(self, obj):
"""

View File

@@ -487,7 +487,7 @@ class LibraryCommitView(APIView):
"""
key = LibraryLocatorV2.from_string(lib_key_str)
api.require_permission_for_library_key(key, request.user, permissions.CAN_EDIT_THIS_CONTENT_LIBRARY)
api.publish_changes(key)
api.publish_changes(key, request.user.id)
return Response({})
@convert_exceptions
@@ -556,7 +556,7 @@ class LibraryBlocksView(GenericAPIView):
# Create a new regular top-level block:
try:
result = api.create_library_block(library_key, **serializer.validated_data)
result = api.create_library_block(library_key, user_id=request.user.id, **serializer.validated_data)
except api.IncompatibleTypesError as err:
raise ValidationError( # lint-amnesty, pylint: disable=raise-missing-from
detail={'block_type': str(err)},