Skip to content

Commit

Permalink
feat: Add Library Collections REST endpoints
Browse files Browse the repository at this point in the history
  • Loading branch information
yusuf-musleh committed Aug 23, 2024
1 parent 5fbcc79 commit f58bb67
Show file tree
Hide file tree
Showing 4 changed files with 142 additions and 1 deletion.
6 changes: 5 additions & 1 deletion openedx/core/djangoapps/content_libraries/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@
LIBRARY_BLOCK_UPDATED,
)
from openedx_learning.api import authoring as authoring_api
from openedx_learning.api.authoring_models import Component, MediaType
from openedx_learning.api.authoring_models import Component, MediaType, LearningPackage
from organizations.models import Organization
from xblock.core import XBlock
from xblock.exceptions import XBlockNotFoundError
Expand Down Expand Up @@ -150,6 +150,7 @@ class ContentLibraryMetadata:
Class that represents the metadata about a content library.
"""
key = attr.ib(type=LibraryLocatorV2)
learning_package = attr.ib(type=LearningPackage)
title = attr.ib("")
description = attr.ib("")
num_blocks = attr.ib(0)
Expand Down Expand Up @@ -323,6 +324,7 @@ def get_metadata(queryset, text_search=None):
has_unpublished_changes=False,
has_unpublished_deletes=False,
license=lib.license,
learning_package=lib.learning_package,
)
for lib in queryset
]
Expand Down Expand Up @@ -408,6 +410,7 @@ def get_library(library_key):
license=ref.license,
created=learning_package.created,
updated=learning_package.updated,
learning_package=learning_package
)


Expand Down Expand Up @@ -479,6 +482,7 @@ def create_library(
allow_public_learning=ref.allow_public_learning,
allow_public_read=ref.allow_public_read,
license=library_license,
learning_package=ref.learning_package
)


Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
"""
Collections API Views
"""

from __future__ import annotations

from django.http import Http404

# from rest_framework.generics import GenericAPIView
from rest_framework.response import Response
from rest_framework.viewsets import ModelViewSet
from rest_framework.status import HTTP_405_METHOD_NOT_ALLOWED

from opaque_keys.edx.locator import LibraryLocatorV2

from openedx.core.djangoapps.content_libraries import api, permissions
from openedx.core.djangoapps.content_libraries.serializers import (
ContentLibraryCollectionSerializer,
ContentLibraryCollectionCreateOrUpdateSerializer,
)

from openedx_learning.api.authoring_models import Collection
from openedx_learning.api import authoring as authoring_api


class LibraryCollectionsView(ModelViewSet):
"""
Views to get, create and update Library Collections.
"""

serializer_class = ContentLibraryCollectionSerializer

def retrieve(self, request, lib_key_str, pk=None):
"""
Retrieve the Content Library Collection
"""
try:
collection = authoring_api.get_collection(pk)
except Collection.DoesNotExist as exc:
raise Http404 from exc

# Check if user has permissions to view this collection by checking if
# user has permission to view the Content Library it belongs to
library_key = LibraryLocatorV2.from_string(lib_key_str)
api.require_permission_for_library_key(library_key, request.user, permissions.CAN_VIEW_THIS_CONTENT_LIBRARY)
serializer = self.get_serializer(collection)
return Response(serializer.data)

def list(self, request, lib_key_str):
"""
List Collections that belong to Content Library
"""
# Check if user has permissions to view collections by checking if user
# has permission to view the Content Library they belong to
library_key = LibraryLocatorV2.from_string(lib_key_str)
api.require_permission_for_library_key(library_key, request.user, permissions.CAN_VIEW_THIS_CONTENT_LIBRARY)
content_library = api.get_library(library_key)
collections = authoring_api.get_learning_package_collections(content_library.learning_package.id)
serializer = self.get_serializer(collections, many=True)
return Response(serializer.data)

def create(self, request, lib_key_str):
"""
Create a Collection that belongs to a Content Library
"""
# Check if user has permissions to create a collection in the Content Library
# by checking if user has permission to edit the Content Library
library_key = LibraryLocatorV2.from_string(lib_key_str)
api.require_permission_for_library_key(library_key, request.user, permissions.CAN_EDIT_THIS_CONTENT_LIBRARY)
create_serializer = ContentLibraryCollectionCreateOrUpdateSerializer(data=request.data)
create_serializer.is_valid(raise_exception=True)
content_library = api.get_library(library_key)
collection = authoring_api.create_collection(
content_library.learning_package.id,
create_serializer.validated_data["title"],
request.user.id,
create_serializer.validated_data["description"]
)
serializer = self.get_serializer(collection)
return Response(serializer.data)

def partial_update(self, request, lib_key_str, pk=None):
"""
Update a Collection that belongs to a Content Library
"""
# Check if user has permissions to update a collection in the Content Library
# by checking if user has permission to edit the Content Library
library_key = LibraryLocatorV2.from_string(lib_key_str)
api.require_permission_for_library_key(library_key, request.user, permissions.CAN_EDIT_THIS_CONTENT_LIBRARY)

try:
collection = authoring_api.get_collection(pk)
except Collection.DoesNotExist as exc:
raise Http404 from exc

update_serializer = ContentLibraryCollectionCreateOrUpdateSerializer(
collection, data=request.data, partial=True
)
update_serializer.is_valid(raise_exception=True)
updated_collection = authoring_api.update_collection(pk, **update_serializer.validated_data)
serializer = self.get_serializer(updated_collection)
return Response(serializer.data)

def destroy(self, request, lib_key_str, pk=None):
"""
Deletes a Collection that belongs to a Content Library
Note: (currently not allowed)
"""
return Response(None, status=HTTP_405_METHOD_NOT_ALLOWED)
21 changes: 21 additions & 0 deletions openedx/core/djangoapps/content_libraries/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
from django.core.validators import validate_unicode_slug
from rest_framework import serializers


from openedx_learning.api.authoring_models import Collection
from openedx.core.djangoapps.content_libraries.constants import (
LIBRARY_TYPES,
COMPLEX,
Expand Down Expand Up @@ -245,3 +247,22 @@ class ContentLibraryBlockImportTaskCreateSerializer(serializers.Serializer):
"""

course_key = CourseKeyField()


class ContentLibraryCollectionSerializer(serializers.ModelSerializer):
"""
Serializer for a Content Library Collection
"""

class Meta:
model = Collection
fields = '__all__'


class ContentLibraryCollectionCreateOrUpdateSerializer(serializers.Serializer):
"""
Serializer for add/update a Collection in a Content Library
"""

title = serializers.CharField()
description = serializers.CharField()
6 changes: 6 additions & 0 deletions openedx/core/djangoapps/content_libraries/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
from rest_framework import routers

from . import views
from .collections.rest_api.v1 import views as collection_views


# Django application name.
Expand All @@ -18,6 +19,9 @@
import_blocks_router = routers.DefaultRouter()
import_blocks_router.register(r'tasks', views.LibraryImportTaskViewSet, basename='import-block-task')

library_collections_router = routers.DefaultRouter()
library_collections_router.register(r'collections', collection_views.LibraryCollectionsView, basename="library-collections")

# These URLs are only used in Studio. The LMS already provides all the
# API endpoints needed to serve XBlocks from content libraries using the
# standard XBlock REST API (see openedx.core.django_apps.xblock.rest_api.urls)
Expand Down Expand Up @@ -45,6 +49,8 @@
path('import_blocks/', include(import_blocks_router.urls)),
# Paste contents of clipboard into library
path('paste_clipboard/', views.LibraryPasteClipboardView.as_view()),
# Library Collections
path('', include(library_collections_router.urls)),
])),
path('blocks/<str:usage_key_str>/', include([
# Get metadata about a specific XBlock in this library, or delete the block:
Expand Down

0 comments on commit f58bb67

Please sign in to comment.