From c748d563e40fac173117c8853cc7b28bef7b1507 Mon Sep 17 00:00:00 2001 From: Navin Karkera Date: Fri, 24 Jan 2025 09:30:17 +0530 Subject: [PATCH] feat: entity link view --- .../rest_api/v2/serializers/__init__.py | 1 + .../rest_api/v2/serializers/downstreams.py | 33 +++++++++++++++++++ .../contentstore/rest_api/v2/urls.py | 8 ++++- .../rest_api/v2/views/downstreams.py | 31 ++++++++++++++--- 4 files changed, 68 insertions(+), 5 deletions(-) create mode 100644 cms/djangoapps/contentstore/rest_api/v2/serializers/downstreams.py diff --git a/cms/djangoapps/contentstore/rest_api/v2/serializers/__init__.py b/cms/djangoapps/contentstore/rest_api/v2/serializers/__init__.py index 6e102bab44a1..83bc02b685e4 100644 --- a/cms/djangoapps/contentstore/rest_api/v2/serializers/__init__.py +++ b/cms/djangoapps/contentstore/rest_api/v2/serializers/__init__.py @@ -1,3 +1,4 @@ """Module for v2 serializers.""" +from cms.djangoapps.contentstore.rest_api.v2.serializers.downstreams import PublishableEntityLinksSerializer from cms.djangoapps.contentstore.rest_api.v2.serializers.home import CourseHomeTabSerializerV2 diff --git a/cms/djangoapps/contentstore/rest_api/v2/serializers/downstreams.py b/cms/djangoapps/contentstore/rest_api/v2/serializers/downstreams.py new file mode 100644 index 000000000000..fe778119f646 --- /dev/null +++ b/cms/djangoapps/contentstore/rest_api/v2/serializers/downstreams.py @@ -0,0 +1,33 @@ +""" +Serializers for upstream -> downstream entity links. +""" + +from rest_framework import serializers + +DATETIME_FORMAT = '%Y-%m-%dT%H:%M:%SZ' + + +class PublishableEntityLinksSerializer(serializers.Serializer): + """ + Serializer for publishable entity links. + """ + upstream_usage_key = serializers.CharField(read_only=True) + upstream_context_key = serializers.CharField(read_only=True) + upstream_context_title = serializers.CharField(read_only=True) + upstream_version = serializers.IntegerField(read_only=True) + downstream_usage_key = serializers.CharField(read_only=True) + downstream_context_title = serializers.CharField(read_only=True) + downstream_context_key = serializers.CharField(read_only=True) + version_synced = serializers.IntegerField(read_only=True) + version_declined = serializers.IntegerField(read_only=True) + created = serializers.DateTimeField(format=DATETIME_FORMAT, read_only=True) + updated = serializers.DateTimeField(format=DATETIME_FORMAT, read_only=True) + ready_to_sync = serializers.SerializerMethodField() + + def get_ready_to_sync(self, obj): + """Calculate ready_to_sync field""" + return bool( + obj.upstream_version and + obj.upstream_version > (obj.version_synced or 0) and + obj.upstream_version > (obj.version_declined or 0) + ) diff --git a/cms/djangoapps/contentstore/rest_api/v2/urls.py b/cms/djangoapps/contentstore/rest_api/v2/urls.py index 3e653d07fbcf..690e78799336 100644 --- a/cms/djangoapps/contentstore/rest_api/v2/urls.py +++ b/cms/djangoapps/contentstore/rest_api/v2/urls.py @@ -3,7 +3,8 @@ from django.conf import settings from django.urls import path, re_path -from cms.djangoapps.contentstore.rest_api.v2.views import home, downstreams +from cms.djangoapps.contentstore.rest_api.v2.views import downstreams, home + app_name = "v2" urlpatterns = [ @@ -23,6 +24,11 @@ downstreams.DownstreamView.as_view(), name="downstream" ), + re_path( + f'^upstreams/{settings.COURSE_KEY_PATTERN}$', + downstreams.UpstreamListView.as_view(), + name='upstream-list' + ), re_path( fr'^downstreams/{settings.USAGE_KEY_PATTERN}/sync$', downstreams.SyncFromUpstreamView.as_view(), diff --git a/cms/djangoapps/contentstore/rest_api/v2/views/downstreams.py b/cms/djangoapps/contentstore/rest_api/v2/views/downstreams.py index 8c0d651910a6..f3d4f4460654 100644 --- a/cms/djangoapps/contentstore/rest_api/v2/views/downstreams.py +++ b/cms/djangoapps/contentstore/rest_api/v2/views/downstreams.py @@ -67,11 +67,21 @@ from rest_framework.views import APIView from xblock.core import XBlock +from openedx_learning.api import authoring + +from cms.djangoapps.contentstore.rest_api.v2.serializers import PublishableEntityLinksSerializer from cms.lib.xblock.upstream_sync import ( - UpstreamLink, UpstreamLinkException, NoUpstream, BadUpstream, BadDownstream, - fetch_customizable_fields, sync_from_upstream, decline_sync, sever_upstream_link + BadDownstream, + BadUpstream, + NoUpstream, + UpstreamLink, + UpstreamLinkException, + decline_sync, + fetch_customizable_fields, + sever_upstream_link, + sync_from_upstream, ) -from common.djangoapps.student.auth import has_studio_write_access, has_studio_read_access +from common.djangoapps.student.auth import has_studio_read_access, has_studio_write_access from openedx.core.lib.api.view_utils import ( DeveloperErrorViewMixin, view_auth_classes, @@ -79,7 +89,6 @@ from xmodule.modulestore.django import modulestore from xmodule.modulestore.exceptions import ItemNotFoundError - logger = logging.getLogger(__name__) @@ -108,6 +117,20 @@ class _AuthenticatedRequest(Request): # ... +@view_auth_classes() +class UpstreamListView(DeveloperErrorViewMixin, APIView): + """ + Serves course->library publishable entity links + """ + def get(self, request: _AuthenticatedRequest, course_key_string: str): + """ + Fetches publishable entity links for given course key + """ + links = authoring.get_entity_links_by_downstream(downstream_context_key=course_key_string) + serializer = PublishableEntityLinksSerializer(links, many=True) + return Response(serializer.data) + + @view_auth_classes(is_authenticated=True) class DownstreamView(DeveloperErrorViewMixin, APIView): """