-
Notifications
You must be signed in to change notification settings - Fork 3.9k
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
feat: REST API for create Library Collection [FC-0062] #35447
Changes from 7 commits
135a7ca
590fc0e
10f3e49
121ed6c
0f173e9
bf367e8
57bb313
44144c4
817e3b4
583f932
b7378ab
0c5e572
3180f76
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -245,3 +245,25 @@ class ContentLibraryBlockImportTaskCreateSerializer(serializers.Serializer): | |
""" | ||
|
||
course_key = CourseKeyField() | ||
|
||
|
||
class LibraryCollectionCreationSerializer(serializers.Serializer): | ||
""" | ||
Serializer to create a new library collection. | ||
""" | ||
|
||
title = serializers.CharField() | ||
description = serializers.CharField(allow_blank=True) | ||
|
||
|
||
class LibraryCollectionMetadataSerializer(serializers.Serializer): | ||
""" | ||
Serializer for Library Collection Metadata. | ||
""" | ||
|
||
# TODO Set this "id" with the LibraryCollectionKey | ||
id = serializers.CharField(read_only=True) | ||
# Rename collection.key to "slug" because "key" is a reserved prop name in React | ||
slug = serializers.CharField(read_only=True) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do we plan to change it in the model? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That wasn't my plan. I've already updated the code to return the slug in the response: 817e3b4 |
||
title = serializers.CharField() | ||
description = serializers.CharField(allow_blank=True) |
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -72,6 +72,7 @@ | |||||||||||||||||||||||||||||||||||||||||||||||||
from django.contrib.auth import authenticate, get_user_model, login | ||||||||||||||||||||||||||||||||||||||||||||||||||
from django.contrib.auth.models import Group | ||||||||||||||||||||||||||||||||||||||||||||||||||
from django.db.transaction import atomic, non_atomic_requests | ||||||||||||||||||||||||||||||||||||||||||||||||||
from django.db.utils import IntegrityError | ||||||||||||||||||||||||||||||||||||||||||||||||||
from django.http import Http404, HttpResponseBadRequest, JsonResponse | ||||||||||||||||||||||||||||||||||||||||||||||||||
from django.shortcuts import get_object_or_404 | ||||||||||||||||||||||||||||||||||||||||||||||||||
from django.urls import reverse | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
@@ -80,6 +81,7 @@ | |||||||||||||||||||||||||||||||||||||||||||||||||
from django.views.decorators.clickjacking import xframe_options_exempt | ||||||||||||||||||||||||||||||||||||||||||||||||||
from django.views.decorators.csrf import csrf_exempt | ||||||||||||||||||||||||||||||||||||||||||||||||||
from django.views.generic.base import TemplateResponseMixin, View | ||||||||||||||||||||||||||||||||||||||||||||||||||
from django.utils.text import slugify | ||||||||||||||||||||||||||||||||||||||||||||||||||
from pylti1p3.contrib.django import DjangoCacheDataStorage, DjangoDbToolConf, DjangoMessageLaunch, DjangoOIDCLogin | ||||||||||||||||||||||||||||||||||||||||||||||||||
from pylti1p3.exception import LtiException, OIDCException | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||
|
@@ -88,6 +90,7 @@ | |||||||||||||||||||||||||||||||||||||||||||||||||
from organizations.api import ensure_organization | ||||||||||||||||||||||||||||||||||||||||||||||||||
from organizations.exceptions import InvalidOrganizationException | ||||||||||||||||||||||||||||||||||||||||||||||||||
from organizations.models import Organization | ||||||||||||||||||||||||||||||||||||||||||||||||||
from openedx_learning.api import authoring as authoring_api | ||||||||||||||||||||||||||||||||||||||||||||||||||
from rest_framework import status | ||||||||||||||||||||||||||||||||||||||||||||||||||
from rest_framework.exceptions import NotFound, PermissionDenied, ValidationError | ||||||||||||||||||||||||||||||||||||||||||||||||||
from rest_framework.generics import GenericAPIView | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
@@ -113,6 +116,8 @@ | |||||||||||||||||||||||||||||||||||||||||||||||||
LibraryXBlockStaticFilesSerializer, | ||||||||||||||||||||||||||||||||||||||||||||||||||
ContentLibraryAddPermissionByEmailSerializer, | ||||||||||||||||||||||||||||||||||||||||||||||||||
LibraryPasteClipboardSerializer, | ||||||||||||||||||||||||||||||||||||||||||||||||||
LibraryCollectionCreationSerializer, | ||||||||||||||||||||||||||||||||||||||||||||||||||
LibraryCollectionMetadataSerializer, | ||||||||||||||||||||||||||||||||||||||||||||||||||
) | ||||||||||||||||||||||||||||||||||||||||||||||||||
import openedx.core.djangoapps.site_configuration.helpers as configuration_helpers | ||||||||||||||||||||||||||||||||||||||||||||||||||
from openedx.core.lib.api.view_utils import view_auth_classes | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
@@ -154,6 +159,10 @@ def wrapped_fn(*args, **kwargs): | |||||||||||||||||||||||||||||||||||||||||||||||||
return wrapped_fn | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||
# Library Views | ||||||||||||||||||||||||||||||||||||||||||||||||||
# ============= | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||
class LibraryApiPaginationDocs: | ||||||||||||||||||||||||||||||||||||||||||||||||||
""" | ||||||||||||||||||||||||||||||||||||||||||||||||||
API docs for query params related to paginating ContentLibraryMetadata objects. | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
@@ -829,6 +838,46 @@ def retrieve(self, request, lib_key_str, pk=None): | |||||||||||||||||||||||||||||||||||||||||||||||||
return Response(ContentLibraryBlockImportTaskSerializer(import_task).data) | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||
# Library Collections Views | ||||||||||||||||||||||||||||||||||||||||||||||||||
# ============= | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||
@method_decorator(non_atomic_requests, name="dispatch") | ||||||||||||||||||||||||||||||||||||||||||||||||||
@view_auth_classes() | ||||||||||||||||||||||||||||||||||||||||||||||||||
class LibraryCollectionsRootView(GenericAPIView): | ||||||||||||||||||||||||||||||||||||||||||||||||||
""" | ||||||||||||||||||||||||||||||||||||||||||||||||||
Views to list and create library collections. | ||||||||||||||||||||||||||||||||||||||||||||||||||
""" | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||
# TODO Implement list collections | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||
def post(self, request, lib_key_str): | ||||||||||||||||||||||||||||||||||||||||||||||||||
""" | ||||||||||||||||||||||||||||||||||||||||||||||||||
Create a new collection 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) | ||||||||||||||||||||||||||||||||||||||||||||||||||
serializer = LibraryCollectionCreationSerializer(data=request.data) | ||||||||||||||||||||||||||||||||||||||||||||||||||
serializer.is_valid(raise_exception=True) | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||
library = api.get_library(library_key) | ||||||||||||||||||||||||||||||||||||||||||||||||||
title = serializer.validated_data['title'] | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||
key = slugify(title) | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||
try: | ||||||||||||||||||||||||||||||||||||||||||||||||||
result = authoring_api.create_collection( | ||||||||||||||||||||||||||||||||||||||||||||||||||
learning_package_id=library.learning_package_id, | ||||||||||||||||||||||||||||||||||||||||||||||||||
key=key, | ||||||||||||||||||||||||||||||||||||||||||||||||||
title=title, | ||||||||||||||||||||||||||||||||||||||||||||||||||
description=serializer.validated_data['description'], | ||||||||||||||||||||||||||||||||||||||||||||||||||
created_by=request.user.id, | ||||||||||||||||||||||||||||||||||||||||||||||||||
) | ||||||||||||||||||||||||||||||||||||||||||||||||||
except IntegrityError: | ||||||||||||||||||||||||||||||||||||||||||||||||||
return Response(status=status.HTTP_409_CONFLICT) | ||||||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. As the user can't directly edit the slug, do you think it is worth an approach like this?
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||
return Response(LibraryCollectionMetadataSerializer(result).data) | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||
# LTI 1.3 Views | ||||||||||||||||||||||||||||||||||||||||||||||||||
# ============= | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -119,7 +119,7 @@ openedx-calc # Library supporting mathematical calculatio | |
openedx-django-require | ||
openedx-events # Open edX Events from Hooks Extension Framework (OEP-50) | ||
openedx-filters # Open edX Filters from Hooks Extension Framework (OEP-50) | ||
openedx-learning # Open edX Learning core (experimental) | ||
git+https://github.com/open-craft/openedx-learning.git@jill/collection-key#egg=openedx-learning # Open edX Learning core (experimental) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. TODO: Bump version |
||
openedx-mongodbproxy | ||
openedx-django-wiki | ||
path | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note: This is also being solved here (#35321) with a different approach.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@rpenido Do you think I should revert this and let #35321 sort it out?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes! I think you don't need to worry about it here. cc @pomegranited
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done: 3180f76