Skip to content

Commit

Permalink
Merge branch 'master' into jipm/fix-zoom-image-tool
Browse files Browse the repository at this point in the history
  • Loading branch information
mariajgrimaldi authored Oct 29, 2024
2 parents 72703d9 + e1ecf72 commit da16ffc
Show file tree
Hide file tree
Showing 157 changed files with 8,971 additions and 3,261 deletions.
7 changes: 7 additions & 0 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,11 @@ complexity of Open edX configuration and deployment into their own hands.
System Dependencies
-------------------

OS:
* Ubuntu 20.04

* Ubuntu 22.04

Interperters/Tools:

* Python 3.11
Expand Down Expand Up @@ -100,6 +105,8 @@ Language Packages:
- ``pip install -r requirements/edx/base.txt`` (production)
- ``pip install -r requirements/edx/dev.txt`` (development)

Some Python packages have system dependencies. For example, installing these packages on Debian or Ubuntu will require first running ``sudo apt install python3-dev default-libmysqlclient-dev build-essential pkg-config`` to satisfy the requirements of the ``mysqlclient`` Python package.

Build Steps
-----------

Expand Down
2 changes: 2 additions & 0 deletions catalog-info.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ metadata:
- url: "https://docs.openedx.org"
title: "Documentation"
icon: "Web"
annotations:
openedx.org/release: "master"
spec:
owner: group:wg-maintenance-edx-platform
type: 'service'
Expand Down
11 changes: 10 additions & 1 deletion cms/djangoapps/contentstore/asset_storage_handlers.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
from common.djangoapps.util.json_request import JsonResponse
from openedx.core.djangoapps.contentserver.caching import del_cached_content
from openedx.core.djangoapps.site_configuration import helpers as configuration_helpers
from openedx_filters.course_authoring.filters import LMSPageURLRequested
from xmodule.contentstore.content import StaticContent # lint-amnesty, pylint: disable=wrong-import-order
from xmodule.contentstore.django import contentstore # lint-amnesty, pylint: disable=wrong-import-order
from xmodule.exceptions import NotFoundError # lint-amnesty, pylint: disable=wrong-import-order
Expand Down Expand Up @@ -714,7 +715,15 @@ def get_asset_json(display_name, content_type, date, location, thumbnail_locatio
Helper method for formatting the asset information to send to client.
'''
asset_url = StaticContent.serialize_asset_key_with_slash(location)
external_url = urljoin(configuration_helpers.get_value('LMS_ROOT_URL', settings.LMS_ROOT_URL), asset_url)

## .. filter_implemented_name: LMSPageURLRequested
## .. filter_type: org.openedx.course_authoring.lms.page.url.requested.v1
lms_root, _ = LMSPageURLRequested.run_filter(
url=configuration_helpers.get_value('LMS_ROOT_URL', settings.LMS_ROOT_URL),
org=location.org,
)

external_url = urljoin(lms_root, asset_url)
portable_url = StaticContent.get_static_path_from_location(location)
usage_locations = [] if usage is None else usage
return {
Expand Down
174 changes: 138 additions & 36 deletions cms/djangoapps/contentstore/helpers.py

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
from .course_team import CourseTeamSerializer
from .grading import CourseGradingModelSerializer, CourseGradingSerializer
from .group_configurations import CourseGroupConfigurationsSerializer
from .home import CourseHomeSerializer, CourseHomeTabSerializer, LibraryTabSerializer
from .home import StudioHomeSerializer, CourseHomeTabSerializer, LibraryTabSerializer
from .proctoring import (
LimitedProctoredExamSettingsSerializer,
ProctoredExamConfigurationSerializer,
Expand Down
6 changes: 4 additions & 2 deletions cms/djangoapps/contentstore/rest_api/v1/serializers/home.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,8 @@ class LibraryTabSerializer(serializers.Serializer):
libraries = LibraryViewSerializer(many=True, required=False, allow_null=True)


class CourseHomeSerializer(serializers.Serializer):
"""Serializer for course home"""
class StudioHomeSerializer(serializers.Serializer):
"""Serializer for Studio home"""
allow_course_reruns = serializers.BooleanField()
allow_to_create_new_org = serializers.BooleanField()
allow_unicode_course_id = serializers.BooleanField()
Expand All @@ -58,6 +58,8 @@ class CourseHomeSerializer(serializers.Serializer):
in_process_course_actions = UnsucceededCourseSerializer(many=True, required=False, allow_null=True)
libraries = LibraryViewSerializer(many=True, required=False, allow_null=True)
libraries_enabled = serializers.BooleanField()
libraries_v1_enabled = serializers.BooleanField()
libraries_v2_enabled = serializers.BooleanField()
taxonomies_enabled = serializers.BooleanField()
taxonomy_list_mfe_url = serializers.CharField()
optimization_enabled = serializers.BooleanField()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ class ContainerHandlerSerializer(serializers.Serializer):
unit_block_id = serializers.CharField(source="unit.location.block_id")
subsection_location = serializers.CharField(source="subsection.location")
course_sequence_ids = serializers.ListField(child=serializers.CharField())
library_content_picker_url = serializers.CharField()

def get_assets_url(self, obj):
"""
Expand All @@ -103,6 +104,18 @@ def get_assets_url(self, obj):
return None


class UpstreamLinkSerializer(serializers.Serializer):
"""
Serializer holding info for syncing a block with its upstream (eg, a library block).
"""
upstream_ref = serializers.CharField()
version_synced = serializers.IntegerField()
version_available = serializers.IntegerField(allow_null=True)
version_declined = serializers.IntegerField(allow_null=True)
error_message = serializers.CharField(allow_null=True)
ready_to_sync = serializers.BooleanField()


class ChildVerticalContainerSerializer(serializers.Serializer):
"""
Serializer for representing a xblock child of vertical container.
Expand All @@ -113,6 +126,7 @@ class ChildVerticalContainerSerializer(serializers.Serializer):
block_type = serializers.CharField()
user_partition_info = serializers.DictField()
user_partitions = serializers.ListField()
upstream_link = UpstreamLinkSerializer(allow_null=True)
actions = serializers.SerializerMethodField()
validation_messages = MessageValidation(many=True)
render_error = serializers.CharField()
Expand Down
9 changes: 6 additions & 3 deletions cms/djangoapps/contentstore/rest_api/v1/views/home.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
from openedx.core.lib.api.view_utils import view_auth_classes

from ....utils import get_home_context, get_course_context, get_library_context
from ..serializers import CourseHomeSerializer, CourseHomeTabSerializer, LibraryTabSerializer
from ..serializers import StudioHomeSerializer, CourseHomeTabSerializer, LibraryTabSerializer


@view_auth_classes(is_authenticated=True)
Expand All @@ -24,7 +24,7 @@ class HomePageView(APIView):
description="Query param to filter by course org",
)],
responses={
200: CourseHomeSerializer,
200: StudioHomeSerializer,
401: "The requester is not authenticated.",
},
)
Expand Down Expand Up @@ -59,6 +59,9 @@ def get(self, request: Request):
"in_process_course_actions": [],
"libraries": [],
"libraries_enabled": true,
"libraries_v1_enabled": true,
"libraries_v2_enabled": true,
"library_authoring_mfe_url": "//localhost:3001/course/course-v1:edX+P315+2T2023",
"optimization_enabled": true,
"request_course_creator_url": "/request_course_creator",
"rerun_creator_status": true,
Expand All @@ -84,7 +87,7 @@ def get(self, request: Request):
'platform_name': settings.PLATFORM_NAME,
'user_is_active': request.user.is_active,
})
serializer = CourseHomeSerializer(home_context)
serializer = StudioHomeSerializer(home_context)
return Response(serializer.data)


Expand Down
24 changes: 18 additions & 6 deletions cms/djangoapps/contentstore/rest_api/v1/views/tests/test_home.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,7 @@ class HomePageViewTest(CourseTestCase):
def setUp(self):
super().setUp()
self.url = reverse("cms.djangoapps.contentstore:v1:home")

def test_home_page_courses_response(self):
"""Check successful response content"""
response = self.client.get(self.url)

expected_response = {
self.expected_response = {
"allow_course_reruns": True,
"allow_to_create_new_org": False,
"allow_unicode_course_id": False,
Expand All @@ -51,6 +46,8 @@ def test_home_page_courses_response(self):
"in_process_course_actions": [],
"libraries": [],
"libraries_enabled": True,
"libraries_v1_enabled": True,
"libraries_v2_enabled": False,
"taxonomies_enabled": True,
"taxonomy_list_mfe_url": 'http://course-authoring-mfe/taxonomies',
"optimization_enabled": False,
Expand All @@ -66,6 +63,21 @@ def test_home_page_courses_response(self):
"user_is_active": True,
}

def test_home_page_studio_response(self):
"""Check successful response content"""
response = self.client.get(self.url)

self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertDictEqual(self.expected_response, response.data)

@override_settings(MEILISEARCH_ENABLED=True)
def test_home_page_studio_with_meilisearch_enabled(self):
"""Check response content when Meilisearch is enabled"""
response = self.client.get(self.url)

expected_response = self.expected_response
expected_response["libraries_v2_enabled"] = True

self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertDictEqual(expected_response, response.data)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,8 @@ def setup_xblock(self):
parent=self.vertical.location,
category="html",
display_name="Html Content 2",
upstream="lb:FakeOrg:FakeLib:html:FakeBlock",
upstream_version=5,
)

def create_block(self, parent, category, display_name, **kwargs):
Expand Down Expand Up @@ -193,6 +195,7 @@ def test_children_content(self):
"name": self.html_unit_first.display_name_with_default,
"block_id": str(self.html_unit_first.location),
"block_type": self.html_unit_first.location.block_type,
"upstream_link": None,
"user_partition_info": expected_user_partition_info,
"user_partitions": expected_user_partitions,
"actions": {
Expand All @@ -218,12 +221,21 @@ def test_children_content(self):
"can_delete": True,
"can_manage_tags": True,
},
"upstream_link": {
"upstream_ref": "lb:FakeOrg:FakeLib:html:FakeBlock",
"version_synced": 5,
"version_available": None,
"version_declined": None,
"error_message": "Linked library item was not found in the system",
"ready_to_sync": False,
},
"user_partition_info": expected_user_partition_info,
"user_partitions": expected_user_partitions,
"validation_messages": [],
"render_error": "",
},
]
self.maxDiff = None
self.assertEqual(response.data["children"], expected_response)

def test_not_valid_usage_key_string(self):
Expand Down
23 changes: 23 additions & 0 deletions cms/djangoapps/contentstore/rest_api/v1/views/vertical_block.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
ContainerHandlerSerializer,
VerticalContainerSerializer,
)
from cms.lib.xblock.upstream_sync import UpstreamLink
from openedx.core.lib.api.view_utils import view_auth_classes
from xmodule.modulestore.django import modulestore # lint-amnesty, pylint: disable=wrong-import-order
from xmodule.modulestore.exceptions import ItemNotFoundError # lint-amnesty, pylint: disable=wrong-import-order
Expand Down Expand Up @@ -198,6 +199,7 @@ def get(self, request: Request, usage_key_string: str):
"block_type": "drag-and-drop-v2",
"user_partition_info": {},
"user_partitions": {}
"upstream_link": null,
"actions": {
"can_copy": true,
"can_duplicate": true,
Expand All @@ -215,6 +217,13 @@ def get(self, request: Request, usage_key_string: str):
"block_type": "video",
"user_partition_info": {},
"user_partitions": {}
"upstream_link": {
"upstream_ref": "lb:org:mylib:video:404",
"version_synced": 16
"version_available": null,
"error_message": "Linked library item not found: lb:org:mylib:video:404",
"ready_to_sync": false,
},
"actions": {
"can_copy": true,
"can_duplicate": true,
Expand All @@ -232,6 +241,13 @@ def get(self, request: Request, usage_key_string: str):
"block_type": "html",
"user_partition_info": {},
"user_partitions": {},
"upstream_link": {
"upstream_ref": "lb:org:mylib:html:abcd",
"version_synced": 43,
"version_available": 49,
"error_message": null,
"ready_to_sync": true,
},
"actions": {
"can_copy": true,
"can_duplicate": true,
Expand Down Expand Up @@ -267,6 +283,7 @@ def get(self, request: Request, usage_key_string: str):
child_info = modulestore().get_item(child)
user_partition_info = get_visibility_partition_info(child_info, course=course)
user_partitions = get_user_partition_info(child_info, course=course)
upstream_link = UpstreamLink.try_get_for_block(child_info)
validation_messages = get_xblock_validation_messages(child_info)
render_error = get_xblock_render_error(request, child_info)

Expand All @@ -277,6 +294,12 @@ def get(self, request: Request, usage_key_string: str):
"block_type": child_info.location.block_type,
"user_partition_info": user_partition_info,
"user_partitions": user_partitions,
"upstream_link": (
# If the block isn't linked to an upstream (which is by far the most common case) then just
# make this field null, which communicates the same info, but with less noise.
upstream_link.to_json() if upstream_link.upstream_ref
else None
),
"validation_messages": validation_messages,
"render_error": render_error,
})
Expand Down
24 changes: 20 additions & 4 deletions cms/djangoapps/contentstore/rest_api/v2/urls.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,31 @@
"""Contenstore API v2 URLs."""

from django.urls import path

from cms.djangoapps.contentstore.rest_api.v2.views import HomePageCoursesViewV2
from django.conf import settings
from django.urls import path, re_path

from cms.djangoapps.contentstore.rest_api.v2.views import home, downstreams
app_name = "v2"

urlpatterns = [
path(
"home/courses",
HomePageCoursesViewV2.as_view(),
home.HomePageCoursesViewV2.as_view(),
name="courses",
),
# TODO: Potential future path.
# re_path(
# fr'^downstreams/$',
# downstreams.DownstreamsListView.as_view(),
# name="downstreams_list",
# ),
re_path(
fr'^downstreams/{settings.USAGE_KEY_PATTERN}$',
downstreams.DownstreamView.as_view(),
name="downstream"
),
re_path(
fr'^downstreams/{settings.USAGE_KEY_PATTERN}/sync$',
downstreams.SyncFromUpstreamView.as_view(),
name="sync_from_upstream"
),
]
3 changes: 0 additions & 3 deletions cms/djangoapps/contentstore/rest_api/v2/views/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +0,0 @@
"""Module for v2 views."""

from cms.djangoapps.contentstore.rest_api.v2.views.home import HomePageCoursesViewV2
Loading

0 comments on commit da16ffc

Please sign in to comment.