From 4e190c34e896717eb68f2e83951d646362b5d055 Mon Sep 17 00:00:00 2001 From: XnpioChV Date: Fri, 31 May 2024 11:56:00 -0500 Subject: [PATCH 1/6] fix: Comment collection uuid in libraries --- openedx/core/djangoapps/content_libraries/serializers.py | 2 +- openedx/core/djangoapps/content_libraries/tests/base.py | 2 +- openedx/core/djangoapps/content_libraries/views.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/openedx/core/djangoapps/content_libraries/serializers.py b/openedx/core/djangoapps/content_libraries/serializers.py index 13c6a756fd31..b11605221364 100644 --- a/openedx/core/djangoapps/content_libraries/serializers.py +++ b/openedx/core/djangoapps/content_libraries/serializers.py @@ -34,7 +34,7 @@ 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) + #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) diff --git a/openedx/core/djangoapps/content_libraries/tests/base.py b/openedx/core/djangoapps/content_libraries/tests/base.py index 2bb94e3d87c7..97207843c9f1 100644 --- a/openedx/core/djangoapps/content_libraries/tests/base.py +++ b/openedx/core/djangoapps/content_libraries/tests/base.py @@ -131,7 +131,7 @@ def _create_library( # We're not actually using this value any more, but we're keeping it # in the API testing for backwards compatibility for just a little # longer. TODO: Remove this once the frontend stops sending it. - "collection_uuid": uuid.uuid4(), + # "collection_uuid": uuid.uuid4(), }, expect_response) def _list_libraries(self, query_params_dict=None, expect_response=200): diff --git a/openedx/core/djangoapps/content_libraries/views.py b/openedx/core/djangoapps/content_libraries/views.py index 38f3e7efd6a1..2edb319a81dc 100644 --- a/openedx/core/djangoapps/content_libraries/views.py +++ b/openedx/core/djangoapps/content_libraries/views.py @@ -260,7 +260,7 @@ def post(self, request): # sending it to us. This whole bit of deserialization is kind of weird # though, with the renames and such. Look into this later for clennup. # Ref: https://github.com/openedx/edx-platform/issues/34283 - data.pop("collection_uuid", None) + # data.pop("collection_uuid", None) try: with atomic(): From a1ee71fdfdb911481f9ff339eecc08382973f053 Mon Sep 17 00:00:00 2001 From: XnpioChV Date: Thu, 6 Jun 2024 13:11:30 -0500 Subject: [PATCH 2/6] feat: Create content in library permission added to API response --- openedx/core/djangoapps/content_libraries/api.py | 9 ++++++++- openedx/core/djangoapps/content_libraries/serializers.py | 1 + openedx/core/djangoapps/content_libraries/tests/base.py | 1 - openedx/core/djangoapps/content_libraries/views.py | 2 +- 4 files changed, 10 insertions(+), 3 deletions(-) diff --git a/openedx/core/djangoapps/content_libraries/api.py b/openedx/core/djangoapps/content_libraries/api.py index 82d648eaeba1..b1c67ce552f8 100644 --- a/openedx/core/djangoapps/content_libraries/api.py +++ b/openedx/core/djangoapps/content_libraries/api.py @@ -167,6 +167,7 @@ class ContentLibraryMetadata: # Allow any user with Studio access to view this library's content in # Studio, use it in their courses, and copy content out of this library. allow_public_read = attr.ib(False) + can_edit_library = attr.ib(False) license = attr.ib("") @@ -316,7 +317,7 @@ def require_permission_for_library_key(library_key, user, permission): raise PermissionDenied -def get_library(library_key): +def get_library(library_key, user=None): """ Get the library with the specified key. Does not check permissions. returns a ContentLibraryMetadata instance. @@ -355,6 +356,11 @@ def get_library(library_key): # uses it, but that should hopefully change before the Redwood release. version = 0 if last_publish_log is None else last_publish_log.pk + can_edit_library = False + + if user: + can_edit_library = user.has_perm(permissions.CAN_EDIT_THIS_CONTENT_LIBRARY, obj=ref) + return ContentLibraryMetadata( key=library_key, title=learning_package.title, @@ -368,6 +374,7 @@ def get_library(library_key): allow_public_read=ref.allow_public_read, has_unpublished_changes=has_unpublished_changes, has_unpublished_deletes=has_unpublished_deletes, + can_edit_library=can_edit_library, license=ref.license, ) diff --git a/openedx/core/djangoapps/content_libraries/serializers.py b/openedx/core/djangoapps/content_libraries/serializers.py index b11605221364..cce7b43e700b 100644 --- a/openedx/core/djangoapps/content_libraries/serializers.py +++ b/openedx/core/djangoapps/content_libraries/serializers.py @@ -46,6 +46,7 @@ class ContentLibraryMetadataSerializer(serializers.Serializer): 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.BooleanField(read_only=True, default=False) class ContentLibraryUpdateSerializer(serializers.Serializer): diff --git a/openedx/core/djangoapps/content_libraries/tests/base.py b/openedx/core/djangoapps/content_libraries/tests/base.py index 97207843c9f1..ee3b34f65a9f 100644 --- a/openedx/core/djangoapps/content_libraries/tests/base.py +++ b/openedx/core/djangoapps/content_libraries/tests/base.py @@ -1,7 +1,6 @@ """ Tests for Learning-Core-based Content Libraries """ -import uuid from contextlib import contextmanager from io import BytesIO from urllib.parse import urlencode diff --git a/openedx/core/djangoapps/content_libraries/views.py b/openedx/core/djangoapps/content_libraries/views.py index 2edb319a81dc..2a1798173016 100644 --- a/openedx/core/djangoapps/content_libraries/views.py +++ b/openedx/core/djangoapps/content_libraries/views.py @@ -286,7 +286,7 @@ def get(self, request, lib_key_str): """ key = LibraryLocatorV2.from_string(lib_key_str) api.require_permission_for_library_key(key, request.user, permissions.CAN_VIEW_THIS_CONTENT_LIBRARY) - result = api.get_library(key) + result = api.get_library(key, user=request.user) return Response(ContentLibraryMetadataSerializer(result).data) @convert_exceptions From c303069324b444647ac3006fee882ba42d7f42e7 Mon Sep 17 00:00:00 2001 From: XnpioChV Date: Tue, 18 Jun 2024 11:12:58 -0500 Subject: [PATCH 3/6] refactor: Get edit library permission on serializer --- openedx/core/djangoapps/content_libraries/api.py | 9 +-------- .../djangoapps/content_libraries/serializers.py | 16 ++++++++++++++-- .../core/djangoapps/content_libraries/views.py | 5 +++-- 3 files changed, 18 insertions(+), 12 deletions(-) diff --git a/openedx/core/djangoapps/content_libraries/api.py b/openedx/core/djangoapps/content_libraries/api.py index b1c67ce552f8..82d648eaeba1 100644 --- a/openedx/core/djangoapps/content_libraries/api.py +++ b/openedx/core/djangoapps/content_libraries/api.py @@ -167,7 +167,6 @@ class ContentLibraryMetadata: # Allow any user with Studio access to view this library's content in # Studio, use it in their courses, and copy content out of this library. allow_public_read = attr.ib(False) - can_edit_library = attr.ib(False) license = attr.ib("") @@ -317,7 +316,7 @@ def require_permission_for_library_key(library_key, user, permission): raise PermissionDenied -def get_library(library_key, user=None): +def get_library(library_key): """ Get the library with the specified key. Does not check permissions. returns a ContentLibraryMetadata instance. @@ -356,11 +355,6 @@ def get_library(library_key, user=None): # uses it, but that should hopefully change before the Redwood release. version = 0 if last_publish_log is None else last_publish_log.pk - can_edit_library = False - - if user: - can_edit_library = user.has_perm(permissions.CAN_EDIT_THIS_CONTENT_LIBRARY, obj=ref) - return ContentLibraryMetadata( key=library_key, title=learning_package.title, @@ -374,7 +368,6 @@ def get_library(library_key, user=None): allow_public_read=ref.allow_public_read, has_unpublished_changes=has_unpublished_changes, has_unpublished_deletes=has_unpublished_deletes, - can_edit_library=can_edit_library, license=ref.license, ) diff --git a/openedx/core/djangoapps/content_libraries/serializers.py b/openedx/core/djangoapps/content_libraries/serializers.py index cce7b43e700b..0fb03ac6e198 100644 --- a/openedx/core/djangoapps/content_libraries/serializers.py +++ b/openedx/core/djangoapps/content_libraries/serializers.py @@ -12,9 +12,11 @@ LICENSE_OPTIONS, ) from openedx.core.djangoapps.content_libraries.models import ( - ContentLibraryPermission, ContentLibraryBlockImportTask + ContentLibraryPermission, ContentLibraryBlockImportTask, + ContentLibrary ) from openedx.core.lib.api.serializers import CourseKeyField +from . import permissions DATETIME_FORMAT = '%Y-%m-%dT%H:%M:%SZ' @@ -46,8 +48,18 @@ class ContentLibraryMetadataSerializer(serializers.Serializer): 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.BooleanField(read_only=True, default=False) + can_edit_library = serializers.SerializerMethodField() + def get_can_edit_library(self, obj): + request = self.context.get('request', None) + user = request.user + can_edit_library = False + library_obj = ContentLibrary.objects.get_by_key(obj.key) + + if user: + can_edit_library = user.has_perm(permissions.CAN_EDIT_THIS_CONTENT_LIBRARY, obj=library_obj) + + return can_edit_library class ContentLibraryUpdateSerializer(serializers.Serializer): """ diff --git a/openedx/core/djangoapps/content_libraries/views.py b/openedx/core/djangoapps/content_libraries/views.py index bfe52b85808c..0cb1f1e22ffc 100644 --- a/openedx/core/djangoapps/content_libraries/views.py +++ b/openedx/core/djangoapps/content_libraries/views.py @@ -282,8 +282,9 @@ def get(self, request, lib_key_str): """ key = LibraryLocatorV2.from_string(lib_key_str) api.require_permission_for_library_key(key, request.user, permissions.CAN_VIEW_THIS_CONTENT_LIBRARY) - result = api.get_library(key, user=request.user) - return Response(ContentLibraryMetadataSerializer(result).data) + result = api.get_library(key) + serializer = ContentLibraryMetadataSerializer(result, context={'request': self.request}) + return Response(serializer.data) @convert_exceptions def patch(self, request, lib_key_str): From 5f0ecef7fdfdc62a5278ab60ffbca150cb9c18f7 Mon Sep 17 00:00:00 2001 From: XnpioChV Date: Tue, 18 Jun 2024 14:56:52 -0500 Subject: [PATCH 4/6] style: Fix tests and nits on lint --- openedx/core/djangoapps/content_libraries/serializers.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/openedx/core/djangoapps/content_libraries/serializers.py b/openedx/core/djangoapps/content_libraries/serializers.py index 0fb03ac6e198..b392104f3e20 100644 --- a/openedx/core/djangoapps/content_libraries/serializers.py +++ b/openedx/core/djangoapps/content_libraries/serializers.py @@ -51,7 +51,13 @@ class ContentLibraryMetadataSerializer(serializers.Serializer): can_edit_library = serializers.SerializerMethodField() def get_can_edit_library(self, obj): + """ + Verifies if the user in request has permission + to edit a library. + """ request = self.context.get('request', None) + if request is None: + return False user = request.user can_edit_library = False library_obj = ContentLibrary.objects.get_by_key(obj.key) @@ -61,6 +67,7 @@ def get_can_edit_library(self, obj): return can_edit_library + class ContentLibraryUpdateSerializer(serializers.Serializer): """ Serializer for updating an existing content library From 837727333b14bb66602a4047bf6edea7d89863aa Mon Sep 17 00:00:00 2001 From: XnpioChV Date: Mon, 24 Jun 2024 09:59:39 -0500 Subject: [PATCH 5/6] refactor: Delete collection_uuid code. --- .../core/djangoapps/content_libraries/serializers.py | 10 +++++----- .../core/djangoapps/content_libraries/tests/base.py | 4 ---- openedx/core/djangoapps/content_libraries/views.py | 8 -------- 3 files changed, 5 insertions(+), 17 deletions(-) diff --git a/openedx/core/djangoapps/content_libraries/serializers.py b/openedx/core/djangoapps/content_libraries/serializers.py index b392104f3e20..df26b07b67f1 100644 --- a/openedx/core/djangoapps/content_libraries/serializers.py +++ b/openedx/core/djangoapps/content_libraries/serializers.py @@ -58,14 +58,14 @@ def get_can_edit_library(self, obj): request = self.context.get('request', None) if request is None: return False + user = request.user - can_edit_library = False - library_obj = ContentLibrary.objects.get_by_key(obj.key) - if user: - can_edit_library = user.has_perm(permissions.CAN_EDIT_THIS_CONTENT_LIBRARY, obj=library_obj) + if not user: + return False - return can_edit_library + library_obj = ContentLibrary.objects.get_by_key(obj.key) + return user.has_perm(permissions.CAN_EDIT_THIS_CONTENT_LIBRARY, obj=library_obj) class ContentLibraryUpdateSerializer(serializers.Serializer): diff --git a/openedx/core/djangoapps/content_libraries/tests/base.py b/openedx/core/djangoapps/content_libraries/tests/base.py index ee3b34f65a9f..ef6cc180f19a 100644 --- a/openedx/core/djangoapps/content_libraries/tests/base.py +++ b/openedx/core/djangoapps/content_libraries/tests/base.py @@ -127,10 +127,6 @@ def _create_library( "description": description, "type": library_type, "license": license_type, - # We're not actually using this value any more, but we're keeping it - # in the API testing for backwards compatibility for just a little - # longer. TODO: Remove this once the frontend stops sending it. - # "collection_uuid": uuid.uuid4(), }, expect_response) def _list_libraries(self, query_params_dict=None, expect_response=200): diff --git a/openedx/core/djangoapps/content_libraries/views.py b/openedx/core/djangoapps/content_libraries/views.py index 0cb1f1e22ffc..fba8d42689cb 100644 --- a/openedx/core/djangoapps/content_libraries/views.py +++ b/openedx/core/djangoapps/content_libraries/views.py @@ -250,14 +250,6 @@ def post(self, request): ) org = Organization.objects.get(short_name=org_name) - # Backwards compatibility: ignore the no-longer used "collection_uuid" - # parameter. This was necessary with Blockstore, but not used for - # Learning Core. TODO: This can be removed once the frontend stops - # sending it to us. This whole bit of deserialization is kind of weird - # though, with the renames and such. Look into this later for clennup. - # Ref: https://github.com/openedx/edx-platform/issues/34283 - # data.pop("collection_uuid", None) - try: with atomic(): result = api.create_library(org=org, **data) From 2d3cff40af6776af318378e96ebecca75c7166cc Mon Sep 17 00:00:00 2001 From: XnpioChV Date: Mon, 24 Jun 2024 10:04:54 -0500 Subject: [PATCH 6/6] style: Nit on code --- openedx/core/djangoapps/content_libraries/serializers.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openedx/core/djangoapps/content_libraries/serializers.py b/openedx/core/djangoapps/content_libraries/serializers.py index df26b07b67f1..ee27e4464365 100644 --- a/openedx/core/djangoapps/content_libraries/serializers.py +++ b/openedx/core/djangoapps/content_libraries/serializers.py @@ -58,7 +58,7 @@ def get_can_edit_library(self, obj): request = self.context.get('request', None) if request is None: return False - + user = request.user if not user: