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

[FC-0059] feat: New fields in library details API view #35091

Merged
32 changes: 24 additions & 8 deletions openedx/core/djangoapps/content_libraries/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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:
Expand Down Expand Up @@ -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
Expand All @@ -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,
Expand All @@ -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,
)


Expand Down Expand Up @@ -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").
"""
Expand Down Expand Up @@ -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(
Expand Down Expand Up @@ -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.

Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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(
Expand Down
6 changes: 5 additions & 1 deletion openedx/core/djangoapps/content_libraries/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,19 +36,23 @@ 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)
has_unpublished_changes = serializers.BooleanField(read_only=True)
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):
"""
Expand Down
4 changes: 2 additions & 2 deletions openedx/core/djangoapps/content_libraries/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -487,7 +487,7 @@ def post(self, request, lib_key_str):
"""
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
Expand Down Expand Up @@ -556,7 +556,7 @@ def post(self, request, lib_key_str):

# 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)},
Expand Down
Loading