"
assert passed_args.data.get("id") == TEST_LOCATOR
assert passed_args.method == "PATCH"
@@ -301,7 +284,6 @@ def test_xblock_handler_called_with_correct_arguments(self):
assert response.status_code == status.HTTP_200_OK
data = response.json()
assert data["locator"] == TEST_LOCATOR
- assert data["courseKey"] == self.get_course_key_string()
class XBlockViewDeleteTest(XBlockViewTestCase, ModuleStoreTestCase, APITestCase):
@@ -343,4 +325,3 @@ def test_xblock_handler_called_with_correct_arguments(self):
assert response.status_code == status.HTTP_200_OK
data = response.json()
assert data["locator"] == TEST_LOCATOR
- assert data["courseKey"] == self.get_course_key_string()
diff --git a/cms/djangoapps/contentstore/rest_api/v1/views/transcripts.py b/cms/djangoapps/contentstore/rest_api/v1/views/transcripts.py
index af23a81fb867..f621929f9cc7 100644
--- a/cms/djangoapps/contentstore/rest_api/v1/views/transcripts.py
+++ b/cms/djangoapps/contentstore/rest_api/v1/views/transcripts.py
@@ -1,5 +1,5 @@
"""
-Public rest API endpoints for the Studio Content API video assets.
+Public rest API endpoints for the CMS API video assets.
"""
import logging
from rest_framework.generics import (
@@ -21,6 +21,11 @@
handle_transcript_download,
)
import cms.djangoapps.contentstore.toggles as contentstore_toggles
+from cms.djangoapps.contentstore.rest_api.v1.serializers import TranscriptSerializer
+from rest_framework.parsers import (MultiPartParser, FormParser)
+from openedx.core.lib.api.parsers import TypedFileUploadParser
+
+from .utils import validate_request_with_serializer
log = logging.getLogger(__name__)
toggles = contentstore_toggles
@@ -29,11 +34,13 @@
@view_auth_classes()
class TranscriptView(DeveloperErrorViewMixin, CreateAPIView, RetrieveAPIView, DestroyAPIView):
"""
- public rest API endpoints for the Studio Content API video transcripts.
+ public rest API endpoints for the CMS API video transcripts.
course_key: required argument, needed to authorize course authors and identify the video.
edx_video_id: optional query parameter, needed to identify the transcript.
language_code: optional query parameter, needed to identify the transcript.
"""
+ serializer_class = TranscriptSerializer
+ parser_classes = (MultiPartParser, FormParser, TypedFileUploadParser)
def dispatch(self, request, *args, **kwargs):
if not toggles.use_studio_content_api():
@@ -43,6 +50,7 @@ def dispatch(self, request, *args, **kwargs):
@csrf_exempt
@course_author_access_required
@expect_json_in_class_view
+ @validate_request_with_serializer
def create(self, request, course_key_string): # pylint: disable=arguments-differ
return upload_transcript(request)
diff --git a/cms/djangoapps/contentstore/rest_api/v1/views/utils.py b/cms/djangoapps/contentstore/rest_api/v1/views/utils.py
new file mode 100644
index 000000000000..7175b76c7c26
--- /dev/null
+++ b/cms/djangoapps/contentstore/rest_api/v1/views/utils.py
@@ -0,0 +1,23 @@
+"""
+Utilities for the REST API views.
+"""
+from functools import wraps
+from django.http import HttpResponseBadRequest
+
+
+def validate_request_with_serializer(view_func):
+ """
+ A decorator to validate request data using the view's serializer.
+
+ Usage:
+ @validate_request_with_serializer
+ def my_view_function(self, request, ...):
+ ...
+ """
+ @wraps(view_func)
+ def _wrapped_view(instance, request, *args, **kwargs):
+ serializer = instance.serializer_class(data=request.data)
+ if not serializer.is_valid():
+ return HttpResponseBadRequest(reason=serializer.errors)
+ return view_func(instance, request, *args, **kwargs)
+ return _wrapped_view
diff --git a/cms/djangoapps/contentstore/rest_api/v1/views/videos.py b/cms/djangoapps/contentstore/rest_api/v1/views/videos.py
index 46282b2eb61d..710dbb5df204 100644
--- a/cms/djangoapps/contentstore/rest_api/v1/views/videos.py
+++ b/cms/djangoapps/contentstore/rest_api/v1/views/videos.py
@@ -1,5 +1,5 @@
"""
-Public rest API endpoints for the Studio Content API video assets.
+Public rest API endpoints for the CMS API video assets.
"""
import logging
from rest_framework.generics import (
@@ -7,10 +7,12 @@
RetrieveAPIView,
DestroyAPIView
)
+from rest_framework.parsers import (MultiPartParser, FormParser)
from django.views.decorators.csrf import csrf_exempt
from django.http import Http404
from openedx.core.lib.api.view_utils import DeveloperErrorViewMixin, view_auth_classes
+from openedx.core.lib.api.parsers import TypedFileUploadParser
from common.djangoapps.util.json_request import expect_json_in_class_view
from ....api import course_author_access_required
@@ -19,10 +21,12 @@
handle_videos,
get_video_encodings_download,
handle_video_images,
- enabled_video_features,
- handle_generate_video_upload_link
+ enabled_video_features
)
+from cms.djangoapps.contentstore.rest_api.v1.serializers import VideoUploadSerializer, VideoImageSerializer
import cms.djangoapps.contentstore.toggles as contentstore_toggles
+from .utils import validate_request_with_serializer
+
log = logging.getLogger(__name__)
toggles = contentstore_toggles
@@ -31,10 +35,11 @@
@view_auth_classes()
class VideosView(DeveloperErrorViewMixin, CreateAPIView, RetrieveAPIView, DestroyAPIView):
"""
- public rest API endpoints for the Studio Content API video assets.
+ public rest API endpoints for the CMS API video assets.
course_key: required argument, needed to authorize course authors and identify the video.
video_id: required argument, needed to identify the video.
"""
+ serializer_class = VideoUploadSerializer
def dispatch(self, request, *args, **kwargs):
# TODO: probably want to refactor this to a decorator.
@@ -50,7 +55,9 @@ def dispatch(self, request, *args, **kwargs):
@csrf_exempt
@course_author_access_required
@expect_json_in_class_view
+ @validate_request_with_serializer
def create(self, request, course_key): # pylint: disable=arguments-differ
+ """Deprecated. Use the upload_link endpoint instead."""
return handle_videos(request, course_key.html_id())
@course_author_access_required
@@ -70,6 +77,8 @@ class VideoImagesView(DeveloperErrorViewMixin, CreateAPIView):
course_key: required argument, needed to authorize course authors and identify the video.
video_id: required argument, needed to identify the video.
"""
+ serializer_class = VideoImageSerializer
+ parser_classes = (MultiPartParser, FormParser, TypedFileUploadParser)
def dispatch(self, request, *args, **kwargs):
# TODO: probably want to refactor this to a decorator.
@@ -85,6 +94,7 @@ def dispatch(self, request, *args, **kwargs):
@csrf_exempt
@course_author_access_required
@expect_json_in_class_view
+ @validate_request_with_serializer
def create(self, request, course_key, edx_video_id=None): # pylint: disable=arguments-differ
return handle_video_images(request, course_key.html_id(), edx_video_id)
@@ -140,6 +150,7 @@ class UploadLinkView(DeveloperErrorViewMixin, CreateAPIView):
"""
public rest API endpoint providing a list of enabled video features.
"""
+ serializer_class = VideoUploadSerializer
def dispatch(self, request, *args, **kwargs):
# TODO: probably want to refactor this to a decorator.
@@ -155,5 +166,6 @@ def dispatch(self, request, *args, **kwargs):
@csrf_exempt
@course_author_access_required
@expect_json_in_class_view
+ @validate_request_with_serializer
def create(self, request, course_key): # pylint: disable=arguments-differ
- return handle_generate_video_upload_link(request, course_key.html_id())
+ return handle_videos(request, course_key.html_id())
diff --git a/cms/djangoapps/contentstore/rest_api/v1/views/xblock.py b/cms/djangoapps/contentstore/rest_api/v1/views/xblock.py
index 2da54811d4b3..0e5765d8a2e2 100644
--- a/cms/djangoapps/contentstore/rest_api/v1/views/xblock.py
+++ b/cms/djangoapps/contentstore/rest_api/v1/views/xblock.py
@@ -1,5 +1,5 @@
"""
-Public rest API endpoints for the Studio Content API.
+Public rest API endpoints for the CMS API.
"""
import logging
from rest_framework.generics import RetrieveUpdateDestroyAPIView, CreateAPIView
@@ -9,11 +9,14 @@
from openedx.core.lib.api.view_utils import DeveloperErrorViewMixin, view_auth_classes
from common.djangoapps.util.json_request import expect_json_in_class_view
-from ....api import course_author_access_required
-
+from cms.djangoapps.contentstore.api import course_author_access_required
from cms.djangoapps.contentstore.xblock_storage_handlers import view_handlers
import cms.djangoapps.contentstore.toggles as contentstore_toggles
+from cms.djangoapps.contentstore.rest_api.v1.serializers import XblockSerializer
+from .utils import validate_request_with_serializer
+
+
log = logging.getLogger(__name__)
toggles = contentstore_toggles
handle_xblock = view_handlers.handle_xblock
@@ -22,11 +25,12 @@
@view_auth_classes()
class XblockView(DeveloperErrorViewMixin, RetrieveUpdateDestroyAPIView, CreateAPIView):
"""
- Public rest API endpoints for the Studio Content API.
+ Public rest API endpoints for the CMS API.
course_key: required argument, needed to authorize course authors.
usage_key_string (optional):
xblock identifier, for example in the form of "block-v1:+type@+block@"
"""
+ serializer_class = XblockSerializer
def dispatch(self, request, *args, **kwargs):
# TODO: probably want to refactor this to a decorator.
@@ -47,11 +51,13 @@ def retrieve(self, request, course_key, usage_key_string=None):
@course_author_access_required
@expect_json_in_class_view
+ @validate_request_with_serializer
def update(self, request, course_key, usage_key_string=None):
return handle_xblock(request, usage_key_string)
@course_author_access_required
@expect_json_in_class_view
+ @validate_request_with_serializer
def partial_update(self, request, course_key, usage_key_string=None):
return handle_xblock(request, usage_key_string)
@@ -63,5 +69,6 @@ def destroy(self, request, course_key, usage_key_string=None):
@csrf_exempt
@course_author_access_required
@expect_json_in_class_view
+ @validate_request_with_serializer
def create(self, request, course_key, usage_key_string=None):
return handle_xblock(request, usage_key_string)
diff --git a/cms/djangoapps/contentstore/tests/test_contentstore.py b/cms/djangoapps/contentstore/tests/test_contentstore.py
index 9162598645b9..1eb70347399c 100644
--- a/cms/djangoapps/contentstore/tests/test_contentstore.py
+++ b/cms/djangoapps/contentstore/tests/test_contentstore.py
@@ -1406,11 +1406,16 @@ def test_course_overview_view_with_course(self):
self.assertEqual(resp.status_code, 404)
return
+ assets_url = reverse_course_url(
+ 'assets_handler',
+ course.location.course_key
+ )
self.assertContains(
resp,
- ''.format( # lint-amnesty, pylint: disable=line-too-long
+ ''.format( # lint-amnesty, pylint: disable=line-too-long
locator=str(course.location),
course_key=str(course.id),
+ assets_url=assets_url,
),
status_code=200,
html=True
diff --git a/cms/djangoapps/contentstore/tests/test_video_utils.py b/cms/djangoapps/contentstore/tests/test_video_utils.py
index 5ba7384dba2b..c81761a283f4 100644
--- a/cms/djangoapps/contentstore/tests/test_video_utils.py
+++ b/cms/djangoapps/contentstore/tests/test_video_utils.py
@@ -5,7 +5,7 @@
from datetime import datetime
from unittest import TestCase
-from unittest.mock import MagicMock, patch
+from unittest import mock
import ddt
import pytz
@@ -144,7 +144,7 @@ def mocked_youtube_thumbnail_response(
return mocked_response
@override_settings(AWS_ACCESS_KEY_ID='test_key_id', AWS_SECRET_ACCESS_KEY='test_secret')
- @patch('requests.get')
+ @mock.patch('requests.get')
@ddt.data(
(
{
@@ -228,7 +228,7 @@ def mocked_youtube_thumbnail_responses(resolutions):
self.assertEqual(thumbnail_content_type, 'image/jpeg')
@override_settings(AWS_ACCESS_KEY_ID='test_key_id', AWS_SECRET_ACCESS_KEY='test_secret')
- @patch('requests.get')
+ @mock.patch('requests.get')
def test_scrape_youtube_thumbnail(self, mocked_request):
"""
Test that youtube thumbnails are correctly scrapped.
@@ -273,8 +273,8 @@ def test_scrape_youtube_thumbnail(self, mocked_request):
)
)
@override_settings(AWS_ACCESS_KEY_ID='test_key_id', AWS_SECRET_ACCESS_KEY='test_secret')
- @patch('cms.djangoapps.contentstore.video_utils.LOGGER')
- @patch('requests.get')
+ @mock.patch('cms.djangoapps.contentstore.video_utils.LOGGER')
+ @mock.patch('requests.get')
@ddt.unpack
def test_scrape_youtube_thumbnail_logging(
self,
@@ -333,8 +333,8 @@ def test_scrape_youtube_thumbnail_logging(
)
),
)
- @patch('cms.djangoapps.contentstore.video_utils.LOGGER')
- @patch('cms.djangoapps.contentstore.video_utils.download_youtube_video_thumbnail')
+ @mock.patch('cms.djangoapps.contentstore.video_utils.LOGGER')
+ @mock.patch('cms.djangoapps.contentstore.video_utils.download_youtube_video_thumbnail')
@ddt.unpack
def test_no_video_thumbnail_downloaded(
self,
@@ -376,7 +376,16 @@ class S3Boto3TestCase(TestCase):
def setUp(self):
self.storage = S3Boto3Storage()
- self.storage._connections.connection = MagicMock() # pylint: disable=protected-access
+ self.storage._connections.connection = mock.MagicMock() # pylint: disable=protected-access
+
+ def order_dict(self, dictionary):
+ """
+ sorting dict key:values for tests cases.
+ """
+ sorted_key_values = sorted(dictionary.items())
+ dictionary.clear()
+ dictionary.update(sorted_key_values)
+ return dictionary
def test_video_backend(self):
self.assertEqual(
@@ -408,17 +417,18 @@ def test_storage_without_global_default_acl_setting(self):
content = ContentFile('new content')
storage = S3Boto3Storage(**{'bucket_name': 'test'})
- storage._connections.connection = MagicMock() # pylint: disable=protected-access
+ storage._connections.connection = mock.MagicMock() # pylint: disable=protected-access
storage.save(name, content)
storage.bucket.Object.assert_called_once_with(name)
obj = storage.bucket.Object.return_value
obj.upload_fileobj.assert_called_with(
- content,
- ExtraArgs={
+ mock.ANY,
+ ExtraArgs=self.order_dict({
'ContentType': 'text/plain',
- }
+ }),
+ Config=storage.transfer_config # pylint: disable=protected-access
)
@override_settings(AWS_DEFAULT_ACL='public-read')
@@ -435,7 +445,7 @@ def test_storage_without_global_default_acl_setting_and_bucket_acls(self, defaul
name = 'test_storage_save.txt'
content = ContentFile('new content')
storage = S3Boto3Storage(**{'bucket_name': 'test', 'default_acl': default_acl})
- storage._connections.connection = MagicMock() # pylint: disable=protected-access
+ storage._connections.connection = mock.MagicMock() # pylint: disable=protected-access
storage.save(name, content)
storage.bucket.Object.assert_called_once_with(name)
@@ -451,8 +461,9 @@ def test_storage_without_global_default_acl_setting_and_bucket_acls(self, defaul
del ExtraArgs['ACL']
obj.upload_fileobj.assert_called_with(
- content,
- ExtraArgs=ExtraArgs
+ mock.ANY,
+ ExtraArgs=self.order_dict(ExtraArgs),
+ Config=storage.transfer_config # pylint: disable=protected-access
)
@ddt.data('public-read', 'private')
@@ -465,15 +476,16 @@ def test_storage_passing_default_acl_as_none(self, input_acl):
content = ContentFile('new content')
storage = S3Boto3Storage(**{'bucket_name': 'test', 'default_acl': None})
- storage._connections.connection = MagicMock() # pylint: disable=protected-access
+ storage._connections.connection = mock.MagicMock() # pylint: disable=protected-access
storage.save(name, content)
storage.bucket.Object.assert_called_once_with(name)
obj = storage.bucket.Object.return_value
obj.upload_fileobj.assert_called_with(
- content,
+ mock.ANY,
+ Config=storage.transfer_config, # pylint: disable=protected-access
ExtraArgs={
'ContentType': 'text/plain',
- }
+ },
)
diff --git a/cms/djangoapps/contentstore/utils.py b/cms/djangoapps/contentstore/utils.py
index 97b70e828ce2..1a4b709622e6 100644
--- a/cms/djangoapps/contentstore/utils.py
+++ b/cms/djangoapps/contentstore/utils.py
@@ -1390,9 +1390,63 @@ def get_help_urls():
return help_tokens
+def get_response_format(request):
+ return request.GET.get('format') or request.POST.get('format') or 'html'
+
+
+def request_response_format_is_json(request, response_format):
+ return response_format == 'json' or 'application/json' in request.META.get('HTTP_ACCEPT', 'application/json')
+
+
+def get_library_context(request, request_is_json=False):
+ """
+ Utils is used to get context of course home library tab.
+ It is used for both DRF and django views.
+ """
+ from cms.djangoapps.contentstore.views.course import (
+ get_allowed_organizations,
+ get_allowed_organizations_for_libraries,
+ user_can_create_organizations,
+ _accessible_libraries_iter,
+ _get_course_creator_status,
+ _format_library_for_view,
+ )
+ from cms.djangoapps.contentstore.views.library import (
+ LIBRARIES_ENABLED,
+ )
+
+ libraries = _accessible_libraries_iter(request.user) if LIBRARIES_ENABLED else []
+ data = {
+ 'libraries': [_format_library_for_view(lib, request) for lib in libraries],
+ }
+
+ if not request_is_json:
+ return {
+ **data,
+ 'in_process_course_actions': [],
+ 'courses': [],
+ 'libraries_enabled': LIBRARIES_ENABLED,
+ 'show_new_library_button': LIBRARIES_ENABLED and request.user.is_active,
+ 'user': request.user,
+ 'request_course_creator_url': reverse('request_course_creator'),
+ 'course_creator_status': _get_course_creator_status(request.user),
+ 'allow_unicode_course_id': settings.FEATURES.get('ALLOW_UNICODE_COURSE_ID', False),
+ 'archived_courses': True,
+ 'allow_course_reruns': settings.FEATURES.get('ALLOW_COURSE_RERUNS', True),
+ 'rerun_creator_status': GlobalStaff().has_user(request.user),
+ 'split_studio_home': split_library_view_on_dashboard(),
+ 'active_tab': 'libraries',
+ 'allowed_organizations_for_libraries': get_allowed_organizations_for_libraries(request.user),
+ 'allowed_organizations': get_allowed_organizations(request.user),
+ 'can_create_organizations': user_can_create_organizations(request.user),
+ }
+
+ return data
+
+
def get_home_context(request):
"""
- Utils is used to get context of course grading.
+ Utils is used to get context of course home.
It is used for both DRF and django views.
"""
@@ -1420,8 +1474,14 @@ def get_home_context(request):
courses_iter, in_process_course_actions = get_courses_accessible_to_user(request, org)
user = request.user
libraries = []
+ response_format = get_response_format(request)
+
if not split_library_view_on_dashboard() and LIBRARIES_ENABLED:
- libraries = _accessible_libraries_iter(request.user)
+ accessible_libraries = _accessible_libraries_iter(user)
+ libraries = [_format_library_for_view(lib, request) for lib in accessible_libraries]
+
+ if split_library_view_on_dashboard() and request_response_format_is_json(request, response_format):
+ libraries = get_library_context(request, True)['libraries']
def format_in_process_course_view(uca):
"""
@@ -1456,7 +1516,7 @@ def format_in_process_course_view(uca):
'libraries_enabled': LIBRARIES_ENABLED,
'redirect_to_library_authoring_mfe': should_redirect_to_library_authoring_mfe(),
'library_authoring_mfe_url': LIBRARY_AUTHORING_MICROFRONTEND_URL,
- 'libraries': [_format_library_for_view(lib, request) for lib in libraries],
+ 'libraries': libraries,
'show_new_library_button': user_can_create_library(user) and not should_redirect_to_library_authoring_mfe(),
'user': user,
'request_course_creator_url': reverse('request_course_creator'),
diff --git a/cms/djangoapps/contentstore/video_storage_handlers.py b/cms/djangoapps/contentstore/video_storage_handlers.py
index d1a7c55ac6f5..6e83a5b9e3cc 100644
--- a/cms/djangoapps/contentstore/video_storage_handlers.py
+++ b/cms/djangoapps/contentstore/video_storage_handlers.py
@@ -729,7 +729,9 @@ def videos_post(course, request):
"""
if use_mock_video_uploads():
- return {'files': [{'file_name': 'video.mp4', 'upload_url': 'http://example.com/put_video'}]}, 200
+ return {'files': [{
+ 'file_name': 'video.mp4', 'upload_url': 'http://example.com/put_video', 'edx_video_id': '1234'
+ }]}, 200
error = None
data = request.json
diff --git a/cms/djangoapps/contentstore/views/component.py b/cms/djangoapps/contentstore/views/component.py
index 148b259898cc..3c31637d4c78 100644
--- a/cms/djangoapps/contentstore/views/component.py
+++ b/cms/djangoapps/contentstore/views/component.py
@@ -336,7 +336,7 @@ def create_support_legend_dict():
template_id = "peer-assessment"
elif category == 'problem':
# Override generic "Problem" name to describe this blank template:
- display_name = _("Blank Advanced Problem")
+ display_name = _("Blank Problem")
templates_for_category.append(
create_template_dict(display_name, category, support_level_without_template, template_id, 'advanced')
)
diff --git a/cms/djangoapps/contentstore/views/course.py b/cms/djangoapps/contentstore/views/course.py
index d74a99a8e391..4a70e5028ce3 100644
--- a/cms/djangoapps/contentstore/views/course.py
+++ b/cms/djangoapps/contentstore/views/course.py
@@ -89,7 +89,6 @@
from ..tasks import rerun_course as rerun_course_task
from ..toggles import (
default_enable_flexible_peer_openassessments,
- split_library_view_on_dashboard,
use_new_course_outline_page,
use_new_home_page,
use_new_updates_page,
@@ -102,6 +101,7 @@
get_course_settings,
get_course_grading,
get_home_context,
+ get_library_context,
get_lms_link_for_item,
get_proctored_exam_settings_url,
get_course_outline_url,
@@ -121,7 +121,6 @@
update_course_discussions_settings,
)
from .component import ADVANCED_COMPONENT_TYPES
-from .library import LIBRARIES_ENABLED
log = logging.getLogger(__name__)
User = get_user_model()
@@ -551,26 +550,7 @@ def library_listing(request):
"""
List all Libraries available to the logged in user
"""
- libraries = _accessible_libraries_iter(request.user) if LIBRARIES_ENABLED else []
- data = {
- 'in_process_course_actions': [],
- 'courses': [],
- 'libraries_enabled': LIBRARIES_ENABLED,
- 'libraries': [_format_library_for_view(lib, request) for lib in libraries],
- 'show_new_library_button': LIBRARIES_ENABLED and request.user.is_active,
- 'user': request.user,
- 'request_course_creator_url': reverse('request_course_creator'),
- 'course_creator_status': _get_course_creator_status(request.user),
- 'allow_unicode_course_id': settings.FEATURES.get('ALLOW_UNICODE_COURSE_ID', False),
- 'archived_courses': True,
- 'allow_course_reruns': settings.FEATURES.get('ALLOW_COURSE_RERUNS', True),
- 'rerun_creator_status': GlobalStaff().has_user(request.user),
- 'split_studio_home': split_library_view_on_dashboard(),
- 'active_tab': 'libraries',
- 'allowed_organizations': get_allowed_organizations(request.user),
- 'allowed_organizations_for_libraries': get_allowed_organizations_for_libraries(request.user),
- 'can_create_organizations': user_can_create_organizations(request.user),
- }
+ data = get_library_context(request)
return render_to_response('index.html', data)
diff --git a/cms/djangoapps/contentstore/views/tests/test_block.py b/cms/djangoapps/contentstore/views/tests/test_block.py
index ce5771ef83e8..26b3f91a0bd7 100644
--- a/cms/djangoapps/contentstore/views/tests/test_block.py
+++ b/cms/djangoapps/contentstore/views/tests/test_block.py
@@ -2675,10 +2675,7 @@ def setUp(self):
XBlockStudioConfiguration.objects.create(
name="openassessment", enabled=True, support_level="us"
)
- # Library Sourced Block and Library Content block has it's own category.
- XBlockStudioConfiguration.objects.create(
- name="library_sourced", enabled=True, support_level="fs"
- )
+ # Library Content block has its own category.
XBlockStudioConfiguration.objects.create(
name="library_content", enabled=True, support_level="fs"
)
@@ -2779,7 +2776,7 @@ def test_basic_components_support_levels(self):
self._verify_basic_component("video", "Video", "us")
problem_templates = self.get_templates_of_type("problem")
problem_no_boilerplate = self.get_template(
- problem_templates, "Blank Advanced Problem"
+ problem_templates, "Blank Problem"
)
self.assertIsNotNone(problem_no_boilerplate)
self.assertEqual("us", problem_no_boilerplate["support_level"])
diff --git a/cms/djangoapps/contentstore/views/tests/test_container_page.py b/cms/djangoapps/contentstore/views/tests/test_container_page.py
index d3bf988d2a45..b78c0cce8347 100644
--- a/cms/djangoapps/contentstore/views/tests/test_container_page.py
+++ b/cms/djangoapps/contentstore/views/tests/test_container_page.py
@@ -9,6 +9,7 @@
from django.http import Http404
from django.test.client import RequestFactory
+from django.urls import reverse
from pytz import UTC
from urllib.parse import quote
@@ -57,11 +58,16 @@ def setUp(self):
self.store.publish(self.vertical.location, self.user.id)
def test_container_html(self):
+ assets_url = reverse(
+ 'assets_handler', kwargs={'course_key_string': str(self.child_container.location.course_key)}
+ )
self._test_html_content(
self.child_container,
expected_section_tag=(
''.format(self.child_container.location)
+ 'data-locator="{0}" data-course-key="{0.course_key}" data-course-assets="{1}">'.format(
+ self.child_container.location, assets_url
+ )
),
expected_breadcrumbs=(
'
\\s*Week 1<\\/a>.*'
@@ -86,11 +92,16 @@ def test_container_on_container_html(self):
self._create_block(draft_container, "html", "Child HTML")
def test_container_html(xblock):
+ assets_url = reverse(
+ 'assets_handler', kwargs={'course_key_string': str(draft_container.location.course_key)}
+ )
self._test_html_content(
xblock,
expected_section_tag=(
''.format(draft_container.location)
+ 'data-locator="{0}" data-course-key="{0.course_key}" data-course-assets="{1}">'.format(
+ draft_container.location, assets_url
+ )
),
expected_breadcrumbs=(
'Lesson 1.*'
diff --git a/cms/djangoapps/contentstore/xblock_storage_handlers/view_handlers.py b/cms/djangoapps/contentstore/xblock_storage_handlers/view_handlers.py
index f7d369630769..425f97e3751f 100644
--- a/cms/djangoapps/contentstore/xblock_storage_handlers/view_handlers.py
+++ b/cms/djangoapps/contentstore/xblock_storage_handlers/view_handlers.py
@@ -175,7 +175,7 @@ def handle_xblock(request, usage_key_string=None):
"""
Service method with all business logic for handling xblock requests.
This method is used both by the internal xblock_handler API and by
- the public studio content API.
+ the public CMS API.
"""
if usage_key_string:
usage_key = usage_key_with_run(usage_key_string)
diff --git a/cms/envs/common.py b/cms/envs/common.py
index cbc100bcabe6..2021d372bcc7 100644
--- a/cms/envs/common.py
+++ b/cms/envs/common.py
@@ -1752,7 +1752,7 @@
# Tagging
'openedx_tagging.core.tagging.apps.TaggingConfig',
- 'openedx.features.content_tagging',
+ 'openedx.core.djangoapps.content_tagging',
'openedx.features.course_duration_limits',
'openedx.features.content_type_gating',
@@ -1791,6 +1791,9 @@
# Blockstore
'blockstore.apps.bundles',
+
+ # alternative swagger generator for CMS API
+ 'drf_spectacular',
]
@@ -2771,3 +2774,16 @@
#### django-simple-history##
# disable indexing on date field its coming django-simple-history.
SIMPLE_HISTORY_DATE_INDEX = False
+
+# This affects the CMS API swagger docs but not the legacy swagger docs under /api-docs/.
+REST_FRAMEWORK['DEFAULT_SCHEMA_CLASS'] = 'drf_spectacular.openapi.AutoSchema'
+
+# These fields override the spectacular settings default values.
+# Any fields not included here will use the default values.
+SPECTACULAR_SETTINGS = {
+ 'TITLE': 'CMS API',
+ 'DESCRIPTION': 'Experimental API to edit xblocks and course content. Danger: Do not use on running courses!',
+ 'VERSION': '1.0.0',
+ 'SERVE_INCLUDE_SCHEMA': False,
+ 'PREPROCESSING_HOOKS': ['cms.lib.spectacular.cms_api_filter'], # restrict spectacular to CMS API endpoints
+}
diff --git a/cms/envs/devstack-experimental.yml b/cms/envs/devstack-experimental.yml
index 61a94c4bc5a9..969e93293776 100644
--- a/cms/envs/devstack-experimental.yml
+++ b/cms/envs/devstack-experimental.yml
@@ -512,7 +512,7 @@ VIDEO_IMAGE_MAX_AGE: 31536000
VIDEO_IMAGE_SETTINGS:
DIRECTORY_PREFIX: video-images/
STORAGE_KWARGS:
- location: /edx/var/edxapp/media//
+ location: /edx/var/edxapp/media/
VIDEO_IMAGE_MAX_BYTES: 2097152
VIDEO_IMAGE_MIN_BYTES: 2048
BASE_URL: /media/
@@ -520,7 +520,7 @@ VIDEO_TRANSCRIPTS_MAX_AGE: 31536000
VIDEO_TRANSCRIPTS_SETTINGS:
DIRECTORY_PREFIX: video-transcripts/
STORAGE_KWARGS:
- location: edx/var/edxapp/media//
+ location: /edx/var/edxapp/media/
VIDEO_TRANSCRIPTS_MAX_BYTES: 3145728
BASE_URL: /media/
VIDEO_UPLOAD_PIPELINE:
diff --git a/cms/envs/devstack.py b/cms/envs/devstack.py
index 3364d42b9797..61359d0611f3 100644
--- a/cms/envs/devstack.py
+++ b/cms/envs/devstack.py
@@ -145,11 +145,19 @@ def should_show_debug_toolbar(request): # lint-amnesty, pylint: disable=missing
XBLOCK_SETTINGS.update({'VideoBlock': {'licensing_enabled': True}})
################################ SEARCH INDEX ################################
-FEATURES['ENABLE_COURSEWARE_INDEX'] = False
+FEATURES['ENABLE_COURSEWARE_INDEX'] = True
FEATURES['ENABLE_LIBRARY_INDEX'] = False
FEATURES['ENABLE_CONTENT_LIBRARY_INDEX'] = False
SEARCH_ENGINE = "search.elastic.ElasticSearchEngine"
+ELASTIC_SEARCH_CONFIG = [
+ {
+ 'use_ssl': False,
+ 'host': 'edx.devstack.elasticsearch710',
+ 'port': 9200
+ }
+]
+
################################ COURSE DISCUSSIONS ###########################
FEATURES['ENABLE_DISCUSSION_SERVICE'] = True
diff --git a/cms/envs/production.py b/cms/envs/production.py
index 401cca648d75..d04dfcd8acc0 100644
--- a/cms/envs/production.py
+++ b/cms/envs/production.py
@@ -154,7 +154,8 @@ def get_env_setting(setting):
WEBPACK_LOADER['DEFAULT']['STATS_FILE'] = STATIC_ROOT / "webpack-stats.json"
WEBPACK_LOADER['WORKERS']['STATS_FILE'] = STATIC_ROOT / "webpack-worker-stats.json"
-EMAIL_FILE_PATH = ENV_TOKENS.get('EMAIL_FILE_PATH', None)
+DATA_DIR = path(ENV_TOKENS.get('DATA_DIR', DATA_DIR))
+EMAIL_FILE_PATH = ENV_TOKENS.get('EMAIL_FILE_PATH', DATA_DIR / "emails" / "studio")
# CMS_BASE: Public domain name of Studio (should be resolvable from the end-user's browser)
@@ -188,7 +189,6 @@ def get_env_setting(setting):
]
LOG_DIR = ENV_TOKENS.get('LOG_DIR', LOG_DIR)
-DATA_DIR = path(ENV_TOKENS.get('DATA_DIR', DATA_DIR))
CACHES = ENV_TOKENS.get('CACHES', CACHES)
# Cache used for location mapping -- called many times with the same key/value
diff --git a/cms/lib/spectacular.py b/cms/lib/spectacular.py
new file mode 100644
index 000000000000..d05d71353157
--- /dev/null
+++ b/cms/lib/spectacular.py
@@ -0,0 +1,19 @@
+""" Helper functions for drf-spectacular """
+
+
+def cms_api_filter(endpoints):
+ """
+ At the moment, we are only enabling drf-spectacular for the CMS API.
+ Filter out endpoints that are not part of the CMS API.
+ """
+ filtered = []
+ for (path, path_regex, method, callback) in endpoints:
+ # Add only paths to the list that are part of the CMS API
+ if (
+ path.startswith("/api/contentstore/v1/xblock") or
+ path.startswith("/api/contentstore/v1/videos") or
+ path.startswith("/api/contentstore/v1/video_transcripts") or
+ path.startswith("/api/contentstore/v1/file_assets")
+ ):
+ filtered.append((path, path_regex, method, callback))
+ return filtered
diff --git a/cms/static/cms/js/require-config.js b/cms/static/cms/js/require-config.js
index db784c45cbfb..28898e5cf7be 100644
--- a/cms/static/cms/js/require-config.js
+++ b/cms/static/cms/js/require-config.js
@@ -353,6 +353,11 @@
'jquery_extend_patch': {
deps: ['jquery']
}
+ },
+ config: {
+ text: {
+ useXhr: () => true
+ }
}
});
}).call(this, require, define);
diff --git a/cms/static/js/i18n/ar/djangojs.js b/cms/static/js/i18n/ar/djangojs.js
index e7c5aae5ceb9..12dc71be061a 100644
--- a/cms/static/js/i18n/ar/djangojs.js
+++ b/cms/static/js/i18n/ar/djangojs.js
@@ -1903,7 +1903,6 @@
"This learner will be removed from the team,allowing another learner to take the available spot.": "\u0633\u064a\u062a\u0645 \u0627\u0633\u062a\u0628\u0639\u0627\u062f \u0647\u0630\u0627 \u0627\u0644\u0645\u062a\u0639\u0644\u0645 \u0645\u0646 \u0627\u0644\u0641\u0631\u064a\u0642\u060c \u0645\u0645\u0627 \u064a\u0633\u0645\u062d \u0644\u0645\u062a\u0639\u0644\u0645 \u0622\u062e\u0631 \u0628\u0623\u062e\u0630 \u0627\u0644\u0645\u0643\u0627\u0646 \u0627\u0644\u0645\u062a\u0627\u062d.",
"This link will open in a modal window": "\u0633\u064a\u0641\u062a\u062d \u0647\u0630\u0627 \u0627\u0644\u0631\u0627\u0628\u0637 \u0641\u064a \u0646\u0627\u0641\u0630\u0629 \u0645\u0646\u0628\u062b\u0642\u0629 \u062c\u062f\u064a\u062f\u0629.",
"This link will open in a new browser window/tab": "\u0633\u064a\u0641\u062a\u062d \u0647\u0630\u0627 \u0627\u0644\u0631\u0627\u0628\u0637 \u0641\u064a \u0646\u0627\u0641\u0630\u0629 \u0645\u062a\u0635\u0641\u0651\u062d \u062c\u062f\u064a\u062f\u0629/\u062a\u0628\u0648\u064a\u0628\u0629 \u062c\u062f\u064a\u062f\u0629",
- "This may be happening because of an error with our server or your internet connection. Try refreshing the page or making sure you are online.": "\u062a\u0648\u062c\u062f \u0645\u0634\u0643\u0644\u0629 \u0641\u064a \u0627\u0644\u062e\u0627\u062f\u0645 \u0623\u0648 \u0641\u064a \u0627\u0644\u0627\u062a\u0635\u0627\u0644 \u0628\u0627\u0644\u0634\u0628\u0643\u0629\u060c \u064a\u0631\u062c\u0649 \u062a\u062d\u062f\u064a\u062b \u0627\u0644\u0635\u0641\u062d\u0629 \u0623\u0648 \u0627\u0644\u062a\u0623\u0643\u062f \u0645\u0646 \u0627\u0644\u0627\u062a\u0635\u0627\u0644 \u0628\u0627\u0644\u0634\u0628\u0643\u0629.",
"This page contains information about orders that you have placed with {platform_name}.": "\u062a\u062d\u062a\u0648\u064a \u0647\u0630\u0647 \u0627\u0644\u0635\u0641\u062d\u0629 \u0639\u0644\u0649 \u0645\u0639\u0644\u0648\u0645\u0627\u062a \u0639\u0646 \u0627\u0644\u0637\u0644\u0628\u064a\u0627\u062a \u0627\u0644\u062a\u064a \u0642\u0645\u062a \u0628\u0647\u0627 \u0639\u0646\u062f {platform_name}.",
"This post could not be closed. Refresh the page and try again.": "\u062a\u0639\u0630\u0631 \u0625\u063a\u0644\u0627\u0642 \u0647\u0630\u0627 \u0627\u0644\u0645\u0646\u0634\u0648\u0631\u060c \u0641\u0636\u0644\u064b\u0627 \u0642\u0645 \u0628\u062a\u062d\u062f\u064a\u062b \u0627\u0644\u0635\u0641\u062d\u0629 \u0648\u0625\u0639\u0627\u062f\u0629 \u0627\u0644\u0645\u062d\u0627\u0648\u0644\u0629.",
"This post could not be flagged for abuse. Refresh the page and try again.": "\u0644\u0627 \u064a\u0645\u0643\u0646 \u0627\u0644\u0625\u0628\u0644\u0627\u063a \u0639\u0646 \u0627\u0633\u0627\u0621\u0629 \u0641\u064a \u0647\u0630\u0627 \u0627\u0644\u0645\u0646\u0634\u0648\u0631. \u0642\u0645 \u0628\u062a\u062d\u062f\u064a\u062b \u0627\u0644\u0635\u0641\u062d\u0629 \u0648\u062d\u0627\u0648\u0644 \u0645\u0631\u0629 \u0623\u062e\u0631\u0649.",
@@ -1999,7 +1998,6 @@
"Unable to load": "\u062a\u0639\u0630\u0651\u0631 \u0625\u062c\u0631\u0627\u0621 \u0627\u0644\u062a\u062d\u0645\u064a\u0644.",
"Unable to submit application": "\u0646\u0639\u062a\u0630\u0651\u0631 \u0644\u062a\u0639\u0630\u0651\u0631 \u062a\u0642\u062f\u064a\u0645 \u0627\u0644\u0637\u0644\u0628",
"Unable to submit request to generate report.": "\u062a\u0639\u0630\u0631 \u0625\u0631\u0633\u0627\u0644 \u0637\u0644\u0628 \u0644\u0625\u0646\u0634\u0627\u0621 \u0627\u0644\u062a\u0642\u0631\u064a\u0631.",
- "Unable to update settings": "\u062a\u0639\u0630\u0631 \u062a\u062d\u062f\u064a\u062b \u0627\u0644\u0625\u0639\u062f\u0627\u062f\u0627\u062a",
"Underline": "\u062e\u0637 \u062a\u062d\u062a \u0627\u0644\u0646\u0635",
"Undo": "\u062a\u0631\u0627\u062c\u064f\u0639",
"Undo (Ctrl+Z)": "\u0625\u0644\u063a\u0627\u0621 (Ctrl+Z)",
diff --git a/cms/static/js/i18n/de-de/djangojs.js b/cms/static/js/i18n/de-de/djangojs.js
index 783bf8d0469d..24637b410460 100644
--- a/cms/static/js/i18n/de-de/djangojs.js
+++ b/cms/static/js/i18n/de-de/djangojs.js
@@ -1084,7 +1084,6 @@
"Loading more threads": "Lade weitere Diskussionsstr\u00e4nge",
"Loading posts list": "Lade Beitrags\u00fcbersicht",
"Loading your courses": "Lade ihren Kurs",
- "Loading...": "Lade...",
"Location": "Ort",
"Location in Course": "Position im Kurs",
"Lock this asset": "Objekt sperren",
@@ -1517,7 +1516,6 @@
"Select the course-wide discussion topics that you want to divide.": "W\u00e4hlen Sie die kursweiten Diskussionsthemen aus, die Sie aufteilen m\u00f6chten.",
"Select the time zone for displaying course dates. If you do not specify a time zone, course dates, including assignment deadlines, will be displayed in your browser's local time zone.": "W\u00e4hlen Sie die Zeitzone des angebotenen Kurses aus. Wenn Sie keine bestimmte Zeitzone ausw\u00e4hlen, werden Kursdaten, inklusive Abgabetermine f\u00fcr Aufgaben, in der lokalen Zeit ihres Browsers dargestellt.",
"Select turnaround": "Wendepunkt ausw\u00e4hlen",
- "Selected blocks": "Ausgew\u00e4hlte Bl\u00f6cke",
"Selected tab": "Ausgew\u00e4hlter Tab",
"Self": "Selbst",
"Send to:": "Senden an:",
@@ -1851,7 +1849,6 @@
"This learner will be removed from the team,allowing another learner to take the available spot.": "Dieser Lernende wird aus dem Team entfernt, so dass ein anderer Lernender den verf\u00fcgbaren Platz einnehmen kann. ",
"This link will open in a modal window": "Dieser Link wird in einem Dialogfenster ge\u00f6ffnet",
"This link will open in a new browser window/tab": "Dieser Link wird in einem neuen Browserfenster/Reiter ge\u00f6ffnet",
- "This may be happening because of an error with our server or your internet connection. Try refreshing the page or making sure you are online.": "Dieses Problem wurde durch einen Fehler auf unserem Server oder mit Ihrer Internetverbindung verursacht. Versuchen Sie die Seite neu zu laden und/oder pr\u00fcfen Sie ihre Internetverbindung",
"This page contains information about orders that you have placed with {platform_name}.": "Diese Seite beinhaltet alle Informationen zu Ihren Bestellungen, welche Sie auf der {platform_name} get\u00e4tigt haben.",
"This post could not be closed. Refresh the page and try again.": "Dieser Beitrag konnte nicht geschlossen werden. Aktualisieren Sie die Seite und versuchen Sie es erneut.",
"This post could not be flagged for abuse. Refresh the page and try again.": "Dieser Beitrag konnte nicht als missbr\u00e4uchlich gekennzeichnet werden. Aktualisieren Sie die Seite und versuchen Sie es erneut.",
@@ -1946,7 +1943,6 @@
"Unable to load": "Laden nicht m\u00f6glich",
"Unable to submit application": "Antrag kann nicht gestellt werden",
"Unable to submit request to generate report.": "Anfrage zur Erstellung eines Berichts nicht m\u00f6glich.",
- "Unable to update settings": "Einstellungen aktualisieren nicht m\u00f6glich",
"Underline": "Unterstrich",
"Undo": "Undo",
"Undo (Ctrl+Z)": "R\u00fcckg\u00e4ngig (STRG+Z)",
diff --git a/cms/static/js/i18n/eo/djangojs.js b/cms/static/js/i18n/eo/djangojs.js
index f9ba7aa9d95c..5ef96bc3e679 100644
--- a/cms/static/js/i18n/eo/djangojs.js
+++ b/cms/static/js/i18n/eo/djangojs.js
@@ -616,6 +616,7 @@
"Discussion topics in the course are not divided.": "D\u00efs\u00e7\u00fcss\u00ef\u00f6n t\u00f6p\u00ef\u00e7s \u00efn th\u00e9 \u00e7\u00f6\u00fcrs\u00e9 \u00e4r\u00e9 n\u00f6t d\u00efv\u00efd\u00e9d. \u2c60'\u03c3\u044f\u0454\u043c \u03b9\u03c1\u0455\u03c5\u043c \u2202\u03c3\u0142\u03c3\u044f \u0455\u03b9\u0442 \u03b1\u043c\u0454\u0442, \u00a2\u03c3\u03b7\u0455\u0454\u00a2\u0442\u0454\u0442\u03c5\u044f \u03b1#",
"Discussions are unified; all learners interact with posts from other learners, regardless of the group they are in.": "D\u00efs\u00e7\u00fcss\u00ef\u00f6ns \u00e4r\u00e9 \u00fcn\u00eff\u00ef\u00e9d; \u00e4ll l\u00e9\u00e4rn\u00e9rs \u00efnt\u00e9r\u00e4\u00e7t w\u00efth p\u00f6sts fr\u00f6m \u00f6th\u00e9r l\u00e9\u00e4rn\u00e9rs, r\u00e9g\u00e4rdl\u00e9ss \u00f6f th\u00e9 gr\u00f6\u00fcp th\u00e9\u00fd \u00e4r\u00e9 \u00efn. \u2c60'\u03c3\u044f\u0454\u043c \u03b9\u03c1\u0455\u03c5\u043c \u2202\u03c3\u0142#",
"Discussions enabled": "D\u00efs\u00e7\u00fcss\u00ef\u00f6ns \u00e9n\u00e4\u00dfl\u00e9d \u2c60'\u03c3\u044f\u0454\u043c \u03b9\u03c1\u0455\u03c5\u043c \u2202\u03c3\u0142\u03c3\u044f \u0455\u03b9\u0442 \u03b1\u043c\u0454\u0442,#",
+ "Dismiss": "D\u00efsm\u00efss \u2c60'\u03c3\u044f\u0454\u043c \u03b9\u03c1\u0455\u03c5\u043c #",
"Display Name": "D\u00efspl\u00e4\u00fd N\u00e4m\u00e9 \u2c60'\u03c3\u044f\u0454\u043c \u03b9\u03c1\u0455\u03c5\u043c \u2202\u03c3\u0142\u03c3\u044f \u0455#",
"Div": "D\u00efv \u2c60'\u03c3\u044f\u0454\u043c#",
"Divide the selected content-specific discussion topics": "D\u00efv\u00efd\u00e9 th\u00e9 s\u00e9l\u00e9\u00e7t\u00e9d \u00e7\u00f6nt\u00e9nt-sp\u00e9\u00e7\u00eff\u00ef\u00e7 d\u00efs\u00e7\u00fcss\u00ef\u00f6n t\u00f6p\u00ef\u00e7s \u2c60'\u03c3\u044f\u0454\u043c \u03b9\u03c1\u0455\u03c5\u043c \u2202\u03c3\u0142\u03c3\u044f \u0455\u03b9\u0442 \u03b1\u043c\u0454\u0442, \u00a2\u03c3\u03b7\u0455\u0454\u00a2\u0442\u0454\u0442\u03c5\u044f \u03b1#",
@@ -1088,7 +1089,6 @@
"Loading more threads": "L\u00f6\u00e4d\u00efng m\u00f6r\u00e9 thr\u00e9\u00e4ds \u2c60'\u03c3\u044f\u0454\u043c \u03b9\u03c1\u0455\u03c5\u043c \u2202\u03c3\u0142\u03c3\u044f \u0455\u03b9\u0442 \u03b1\u043c\u0454\u0442, #",
"Loading posts list": "L\u00f6\u00e4d\u00efng p\u00f6sts l\u00efst \u2c60'\u03c3\u044f\u0454\u043c \u03b9\u03c1\u0455\u03c5\u043c \u2202\u03c3\u0142\u03c3\u044f \u0455\u03b9\u0442 \u03b1\u043c\u0454\u0442#",
"Loading your courses": "L\u00f6\u00e4d\u00efng \u00fd\u00f6\u00fcr \u00e7\u00f6\u00fcrs\u00e9s \u2c60'\u03c3\u044f\u0454\u043c \u03b9\u03c1\u0455\u03c5\u043c \u2202\u03c3\u0142\u03c3\u044f \u0455\u03b9\u0442 \u03b1\u043c\u0454\u0442, #",
- "Loading...": "L\u00f6\u00e4d\u00efng... \u2c60'\u03c3\u044f\u0454\u043c \u03b9\u03c1\u0455\u03c5\u043c \u2202\u03c3\u0142\u03c3#",
"Location": "L\u00f6\u00e7\u00e4t\u00ef\u00f6n \u2c60'\u03c3\u044f\u0454\u043c \u03b9\u03c1\u0455\u03c5\u043c \u2202#",
"Location in Course": "L\u00f6\u00e7\u00e4t\u00ef\u00f6n \u00efn \u00c7\u00f6\u00fcrs\u00e9 \u2c60'\u03c3\u044f\u0454\u043c \u03b9\u03c1\u0455\u03c5\u043c \u2202\u03c3\u0142\u03c3\u044f \u0455\u03b9\u0442 \u03b1\u043c\u0454\u0442#",
"Lock this asset": "L\u00f6\u00e7k th\u00efs \u00e4ss\u00e9t \u2c60'\u03c3\u044f\u0454\u043c \u03b9\u03c1\u0455\u03c5\u043c \u2202\u03c3\u0142\u03c3\u044f \u0455\u03b9\u0442 \u03b1#",
@@ -1166,7 +1166,7 @@
"New Password": "N\u00e9w P\u00e4ssw\u00f6rd \u2c60'\u03c3\u044f\u0454\u043c \u03b9\u03c1\u0455\u03c5\u043c \u2202\u03c3\u0142\u03c3\u044f \u0455#",
"New document": "N\u00e9w d\u00f6\u00e7\u00fcm\u00e9nt \u2c60'\u03c3\u044f\u0454\u043c \u03b9\u03c1\u0455\u03c5\u043c \u2202\u03c3\u0142\u03c3\u044f \u0455#",
"New enrollment mode:": "N\u00e9w \u00e9nr\u00f6llm\u00e9nt m\u00f6d\u00e9: \u2c60'\u03c3\u044f\u0454\u043c \u03b9\u03c1\u0455\u03c5\u043c \u2202\u03c3\u0142\u03c3\u044f \u0455\u03b9\u0442 \u03b1\u043c\u0454\u0442, #",
- "New files were added to this course's Files & Uploads": "N\u00e9w f\u00efl\u00e9s w\u00e9r\u00e9 \u00e4dd\u00e9d t\u00f6 th\u00efs \u00e7\u00f6\u00fcrs\u00e9's F\u00efl\u00e9s & \u00dbpl\u00f6\u00e4ds \u2c60'\u03c3\u044f\u0454\u043c \u03b9\u03c1\u0455\u03c5\u043c \u2202\u03c3\u0142\u03c3\u044f \u0455\u03b9\u0442 \u03b1\u043c\u0454\u0442, \u00a2\u03c3\u03b7\u0455\u0454\u00a2\u0442\u0454\u0442\u03c5\u044f \u03b1#",
+ "New file(s) added to Files & Uploads.": "N\u00e9w f\u00efl\u00e9(s) \u00e4dd\u00e9d t\u00f6 F\u00efl\u00e9s & \u00dbpl\u00f6\u00e4ds. \u2c60'\u03c3\u044f\u0454\u043c \u03b9\u03c1\u0455\u03c5\u043c \u2202\u03c3\u0142\u03c3\u044f \u0455\u03b9\u0442 \u03b1\u043c\u0454\u0442, \u00a2\u03c3\u03b7\u0455\u0454\u00a2\u0442\u0454\u0442\u03c5#",
"New window": "N\u00e9w w\u00efnd\u00f6w \u2c60'\u03c3\u044f\u0454\u043c \u03b9\u03c1\u0455\u03c5\u043c \u2202\u03c3\u0142\u03c3#",
"New {component_type}": "N\u00e9w {component_type} \u2c60'\u03c3\u044f\u0454\u043c \u03b9\u03c1\u0455\u03c5\u043c #",
"Next": "N\u00e9xt \u2c60'\u03c3\u044f\u0454\u043c \u03b9#",
@@ -1558,7 +1558,6 @@
"Select the course-wide discussion topics that you want to divide.": "S\u00e9l\u00e9\u00e7t th\u00e9 \u00e7\u00f6\u00fcrs\u00e9-w\u00efd\u00e9 d\u00efs\u00e7\u00fcss\u00ef\u00f6n t\u00f6p\u00ef\u00e7s th\u00e4t \u00fd\u00f6\u00fc w\u00e4nt t\u00f6 d\u00efv\u00efd\u00e9. \u2c60'\u03c3\u044f\u0454\u043c \u03b9\u03c1\u0455\u03c5\u043c \u2202\u03c3\u0142\u03c3\u044f \u0455\u03b9\u0442 \u03b1\u043c\u0454\u0442, \u00a2\u03c3\u03b7\u0455\u0454\u00a2\u0442\u0454\u0442\u03c5\u044f \u03b1#",
"Select the time zone for displaying course dates. If you do not specify a time zone, course dates, including assignment deadlines, will be displayed in your browser's local time zone.": "S\u00e9l\u00e9\u00e7t th\u00e9 t\u00efm\u00e9 z\u00f6n\u00e9 f\u00f6r d\u00efspl\u00e4\u00fd\u00efng \u00e7\u00f6\u00fcrs\u00e9 d\u00e4t\u00e9s. \u00ccf \u00fd\u00f6\u00fc d\u00f6 n\u00f6t sp\u00e9\u00e7\u00eff\u00fd \u00e4 t\u00efm\u00e9 z\u00f6n\u00e9, \u00e7\u00f6\u00fcrs\u00e9 d\u00e4t\u00e9s, \u00efn\u00e7l\u00fcd\u00efng \u00e4ss\u00efgnm\u00e9nt d\u00e9\u00e4dl\u00efn\u00e9s, w\u00efll \u00df\u00e9 d\u00efspl\u00e4\u00fd\u00e9d \u00efn \u00fd\u00f6\u00fcr \u00dfr\u00f6ws\u00e9r's l\u00f6\u00e7\u00e4l t\u00efm\u00e9 z\u00f6n\u00e9. \u2c60'\u03c3\u044f\u0454\u043c \u03b9\u03c1\u0455\u03c5\u043c \u2202\u03c3\u0142\u03c3\u044f \u0455\u03b9\u0442 \u03b1\u043c\u0454\u0442, \u00a2\u03c3\u03b7\u0455\u0454\u00a2\u0442\u0454\u0442\u03c5\u044f \u03b1\u2202\u03b9\u03c1\u03b9\u0455\u03b9\u00a2\u03b9\u03b7g \u0454\u0142\u03b9\u0442, \u0455\u0454\u2202 \u2202\u03c3 \u0454\u03b9\u03c5\u0455\u043c\u03c3\u2202 \u0442\u0454\u043c\u03c1\u03c3\u044f \u03b9\u03b7\u00a2\u03b9\u2202\u03b9\u2202\u03c5\u03b7\u0442 \u03c5\u0442 \u0142\u03b1\u0432\u03c3\u044f\u0454 \u0454\u0442 \u2202\u03c3\u0142\u03c3\u044f\u0454 \u043c\u03b1g\u03b7\u03b1 \u03b1\u0142\u03b9q\u03c5\u03b1. \u03c5\u0442 \u0454\u03b7\u03b9\u043c \u03b1\u2202 \u043c\u03b9\u03b7\u03b9\u043c \u03bd\u0454\u03b7\u03b9\u03b1\u043c, q\u03c5\u03b9\u0455 \u03b7\u03c3\u0455\u0442\u044f\u03c5\u2202 \u0454\u03c7\u0454\u044f\u00a2\u03b9\u0442\u03b1\u0442\u03b9\u03c3\u03b7 \u03c5\u0142\u0142\u03b1\u043c\u00a2\u03c3 \u0142\u03b1\u0432\u03c3\u044f\u03b9\u0455 \u03b7\u03b9\u0455\u03b9 \u03c5\u0442 \u03b1\u0142\u03b9q\u03c5\u03b9\u03c1 \u0454\u03c7 \u0454\u03b1 \u00a2\u03c3\u043c\u043c\u03c3\u2202\u03c3 \u00a2\u03c3\u03b7\u0455\u0454q\u03c5\u03b1\u0442. \u2202\u03c5\u03b9\u0455 \u03b1\u03c5\u0442\u0454 \u03b9\u044f\u03c5\u044f\u0454 \u2202\u03c3\u0142\u03c3\u044f \u03b9\u03b7 \u044f\u0454\u03c1\u044f\u0454\u043d\u0454\u03b7\u2202\u0454\u044f\u03b9\u0442 \u03b9\u03b7 \u03bd\u03c3\u0142\u03c5\u03c1\u0442\u03b1\u0442\u0454 \u03bd\u0454\u0142\u03b9\u0442 \u0454\u0455\u0455\u0454 \u00a2\u03b9\u0142\u0142\u03c5\u043c \u2202\u03c3\u0142\u03c3\u044f\u0454 \u0454\u03c5 \u0192\u03c5g\u03b9\u03b1\u0442 \u03b7\u03c5\u0142\u0142\u03b1 \u03c1\u03b1\u044f\u03b9\u03b1\u0442\u03c5\u044f. \u0454\u03c7\u00a2\u0454\u03c1\u0442\u0454\u03c5\u044f \u0455\u03b9\u03b7\u0442 \u03c3\u00a2\u00a2\u03b1\u0454\u00a2\u03b1\u0442 \u00a2\u03c5\u03c1\u03b9\u2202\u03b1\u0442\u03b1\u0442 \u03b7\u03c3\u03b7 \u03c1\u044f\u03c3\u03b9\u2202\u0454\u03b7\u0442, \u0455#",
"Select turnaround": "S\u00e9l\u00e9\u00e7t t\u00fcrn\u00e4r\u00f6\u00fcnd \u2c60'\u03c3\u044f\u0454\u043c \u03b9\u03c1\u0455\u03c5\u043c \u2202\u03c3\u0142\u03c3\u044f \u0455\u03b9\u0442 \u03b1\u043c\u0454#",
- "Selected blocks": "S\u00e9l\u00e9\u00e7t\u00e9d \u00dfl\u00f6\u00e7ks \u2c60'\u03c3\u044f\u0454\u043c \u03b9\u03c1\u0455\u03c5\u043c \u2202\u03c3\u0142\u03c3\u044f \u0455\u03b9\u0442 \u03b1#",
"Selected tab": "S\u00e9l\u00e9\u00e7t\u00e9d t\u00e4\u00df \u2c60'\u03c3\u044f\u0454\u043c \u03b9\u03c1\u0455\u03c5\u043c \u2202\u03c3\u0142\u03c3\u044f \u0455#",
"Self": "S\u00e9lf \u2c60'\u03c3\u044f\u0454\u043c \u03b9#",
"Send to:": "S\u00e9nd t\u00f6: \u2c60'\u03c3\u044f\u0454\u043c \u03b9\u03c1\u0455\u03c5\u043c \u2202#",
@@ -2021,7 +2020,6 @@
"Unable to load": "\u00dbn\u00e4\u00dfl\u00e9 t\u00f6 l\u00f6\u00e4d \u2c60'\u03c3\u044f\u0454\u043c \u03b9\u03c1\u0455\u03c5\u043c \u2202\u03c3\u0142\u03c3\u044f \u0455\u03b9\u0442#",
"Unable to submit application": "\u00dbn\u00e4\u00dfl\u00e9 t\u00f6 s\u00fc\u00dfm\u00eft \u00e4ppl\u00ef\u00e7\u00e4t\u00ef\u00f6n \u2c60'\u03c3\u044f\u0454\u043c \u03b9\u03c1\u0455\u03c5\u043c \u2202\u03c3\u0142\u03c3\u044f \u0455\u03b9\u0442 \u03b1\u043c\u0454\u0442, \u00a2\u03c3\u03b7\u0455\u0454\u00a2#",
"Unable to submit request to generate report.": "\u00dbn\u00e4\u00dfl\u00e9 t\u00f6 s\u00fc\u00dfm\u00eft r\u00e9q\u00fc\u00e9st t\u00f6 g\u00e9n\u00e9r\u00e4t\u00e9 r\u00e9p\u00f6rt. \u2c60'\u03c3\u044f\u0454\u043c \u03b9\u03c1\u0455\u03c5\u043c \u2202\u03c3\u0142\u03c3\u044f \u0455\u03b9\u0442 \u03b1\u043c\u0454\u0442, \u00a2\u03c3\u03b7\u0455\u0454\u00a2\u0442\u0454\u0442\u03c5\u044f #",
- "Unable to update settings": "\u00dbn\u00e4\u00dfl\u00e9 t\u00f6 \u00fcpd\u00e4t\u00e9 s\u00e9tt\u00efngs \u2c60'\u03c3\u044f\u0454\u043c \u03b9\u03c1\u0455\u03c5\u043c \u2202\u03c3\u0142\u03c3\u044f \u0455\u03b9\u0442 \u03b1\u043c\u0454\u0442, \u00a2\u03c3\u03b7\u0455#",
"Underline": "\u00dbnd\u00e9rl\u00efn\u00e9 \u2c60'\u03c3\u044f\u0454\u043c \u03b9\u03c1\u0455\u03c5\u043c \u2202\u03c3\u0142#",
"Undo": "\u00dbnd\u00f6 \u2c60'\u03c3\u044f\u0454\u043c \u03b9#",
"Undo (Ctrl+Z)": "\u00dbnd\u00f6 (\u00c7trl+Z) \u2c60'\u03c3\u044f\u0454\u043c \u03b9\u03c1\u0455\u03c5\u043c \u2202\u03c3\u0142\u03c3\u044f \u0455\u03b9#",
@@ -2169,6 +2167,7 @@
"View and grade responses": "V\u00ef\u00e9w \u00e4nd gr\u00e4d\u00e9 r\u00e9sp\u00f6ns\u00e9s \u2c60'\u03c3\u044f\u0454\u043c \u03b9\u03c1\u0455\u03c5\u043c \u2202\u03c3\u0142\u03c3\u044f \u0455\u03b9\u0442 \u03b1\u043c\u0454\u0442, \u00a2\u03c3\u03b7#",
"View child items": "V\u00ef\u00e9w \u00e7h\u00efld \u00eft\u00e9ms \u2c60'\u03c3\u044f\u0454\u043c \u03b9\u03c1\u0455\u03c5\u043c \u2202\u03c3\u0142\u03c3\u044f \u0455\u03b9\u0442 \u03b1\u043c#",
"View discussion": "V\u00ef\u00e9w d\u00efs\u00e7\u00fcss\u00ef\u00f6n \u2c60'\u03c3\u044f\u0454\u043c \u03b9\u03c1\u0455\u03c5\u043c \u2202\u03c3\u0142\u03c3\u044f \u0455\u03b9\u0442 \u03b1#",
+ "View files": "V\u00ef\u00e9w f\u00efl\u00e9s \u2c60'\u03c3\u044f\u0454\u043c \u03b9\u03c1\u0455\u03c5\u043c \u2202\u03c3\u0142\u03c3#",
"View program": "V\u00ef\u00e9w pr\u00f6gr\u00e4m \u2c60'\u03c3\u044f\u0454\u043c \u03b9\u03c1\u0455\u03c5\u043c \u2202\u03c3\u0142\u03c3\u044f \u0455#",
"View your receipts or modify your subscription on the {a_start}Orders and subscriptions{a_end} page": "V\u00ef\u00e9w \u00fd\u00f6\u00fcr r\u00e9\u00e7\u00e9\u00efpts \u00f6r m\u00f6d\u00eff\u00fd \u00fd\u00f6\u00fcr s\u00fc\u00dfs\u00e7r\u00efpt\u00ef\u00f6n \u00f6n th\u00e9 {a_start}\u00d6rd\u00e9rs \u00e4nd s\u00fc\u00dfs\u00e7r\u00efpt\u00ef\u00f6ns{a_end} p\u00e4g\u00e9 \u2c60'\u03c3\u044f\u0454\u043c \u03b9\u03c1\u0455\u03c5\u043c \u2202\u03c3\u0142\u03c3\u044f \u0455\u03b9\u0442 \u03b1\u043c\u0454\u0442, \u00a2\u03c3\u03b7\u0455#",
"View {span_start} {team_name} {span_end}": "V\u00ef\u00e9w {span_start} {team_name} {span_end} \u2c60'\u03c3\u044f\u0454\u043c \u03b9\u03c1\u0455\u03c5\u043c \u2202\u03c3\u0142\u03c3\u044f \u0455\u03b9\u0442 \u03b1\u043c#",
diff --git a/cms/static/js/i18n/es-419/djangojs.js b/cms/static/js/i18n/es-419/djangojs.js
index 537a9c241844..cb094093eb11 100644
--- a/cms/static/js/i18n/es-419/djangojs.js
+++ b/cms/static/js/i18n/es-419/djangojs.js
@@ -467,6 +467,7 @@
"Cannot delete when in use by a unit": "No puede borrar cuando esta en uso por una unidad",
"Cannot delete when in use by an experiment": "No se puede borrar mientras est\u00e9 en uso por un experimento",
"Cannot join instructor managed team": "No se puede unir al equipo administrado por el instructor",
+ "Cannot submit empty response even everything is optional.": "No se puede enviar una respuesta vac\u00eda, incluso si todo es opcional.",
"Cannot update attempt review status": "No es posible actualizar el estado de revisi\u00f3n de los intentos ",
"Caption": "Leyenda",
"Caution: The last published version of this unit is live. By publishing changes you will change the student experience.": "Atenci\u00f3n: La \u00faltima versi\u00f3n publicada de esta unidad est\u00e1 en vivo. Al publicar los cambios, cambiar\u00e1 la experiencia de los estudiantes.",
@@ -736,6 +737,7 @@
"Discussion topics in the course are not divided.": "Temas de discusi\u00f3n en el curso no son divididos.",
"Discussions are unified; all learners interact with posts from other learners, regardless of the group they are in.": "Las discusiones son unificadas; todos los estudiantes interact\u00faan con publicaciones de otros estudiantes, sin considerar su grupo.",
"Discussions enabled": "Discusiones habilitadas",
+ "Dismiss": "Descartar",
"Display Name": "Nombre para mostrar:",
"Div": "Div",
"Divide the selected content-specific discussion topics": "Divide los contenidos espec\u00edficos seleccionados de los temas de la discusi\u00f3n",
@@ -1213,7 +1215,6 @@
"Loading more threads": "Cargando m\u00e1s discusiones",
"Loading posts list": "Cargando lista de publicaci\u00f3nes",
"Loading your courses": "Cargando tus cursos",
- "Loading...": "Cargando...",
"Location": "Ubicaci\u00f3n",
"Location in Course": "Ubicaci\u00f3n en el curso",
"Lock this asset": "Bloquear este recurso",
@@ -1294,7 +1295,7 @@
"New Password": "Nueva Contrase\u00f1a",
"New document": "Documento nuevo",
"New enrollment mode:": "Nuevo modo de inscripcion:",
- "New files were added to this course's Files & Uploads": "Se agregaron nuevos archivos a la secci\u00f3n Archivos y Cargas de este curso",
+ "New file(s) added to Files & Uploads.": "Nuevos archivos agregados a Archivos y cargas.",
"New window": "Nueva ventana",
"New {component_type}": "Nuevo {component_type}",
"Next": "Siguiente",
@@ -1310,6 +1311,7 @@
"No content-specific discussion topics exist.": "No existen temas de discusi\u00f3n de contenidos espec\u00edficos",
"No description available": "No hay descripci\u00f3n disponible",
"No exams in course {course_id}.": "No hay examenes en el este curso {course_id}.",
+ "No files selected for upload.": "No hay archivos seleccionados para cargar.",
"No instructor dashboard for {proctor_service}": "No instructor registrado para {proctor_service}",
"No onboarding status API for {proctor_service}": "API no disponible para el estado de inducci\u00f3n {proctor_service}",
"No posts matched your query.": "Ninguna publicaci\u00f3n coincide con los criterios dados.",
@@ -1471,12 +1473,15 @@
"Please fix the following errors:": "Por favor corrija los siguientes errores:",
"Please follow the instructions here to upload a file elsewhere and link to it: {maxFileSizeRedirectUrl}": "Por favor siga las instrucciones aqui para cargar un archivo en otro parte y enlazelo: {maxFileSizeRedirectUrl}",
"Please note: Deletion of your account and personal data is permanent and cannot be undone. {platformName} will not be able to recover your account or the data that is deleted.": "Cuidado: la eliminaci\u00f3n de su cuenta y datos personales es permanente e irreversible. {platformName} no podr\u00e1 recuperar ni su cuenta ni los datos eliminados.",
+ "Please provide a description for each file you are uploading.": "Proporcione una descripci\u00f3n para cada archivo que est\u00e1 cargando.",
"Please provide a description of the link destination.": "Por favor, provee una descripci\u00f3n de la destinaci\u00f3n del v\u00ednculo.",
+ "Please provide a response.": "Proporcione una respuesta.",
"Please provide a valid URL.": "Por favor, provee un URL v\u00e1lido.",
"Please re-enter your password.": "Por favor, introduce tu contrase\u00f1a nuevamente.",
"Please select a PDF file to upload.": "Por favor selecciona un archivo PDF para subir.",
"Please select a file in .srt format.": "Por favor seleccione un archivo en formato .srt",
"Please specify a reason.": "Por favor especifica una raz\u00f3n.",
+ "Please upload a file.": "Cargue un archivo.",
"Please verify that you have uploaded a valid image (PNG and JPEG).": "Por favor verifica que hayas cargado una imagen v\u00e1lida (PNG y JPEG)",
"Please verify that your webcam is connected and that you have allowed your browser to access it.": "Por favor, comprueba que tu webcam este conectada y que el navegador tenga habilitado el acceso a la misma.",
"Please wait": "Por favor espere",
@@ -1695,7 +1700,6 @@
"Select the course-wide discussion topics that you want to divide.": "Seleccione los temas de discusi\u00f3n del curso que desea dividir.",
"Select the time zone for displaying course dates. If you do not specify a time zone, course dates, including assignment deadlines, will be displayed in your browser's local time zone.": "Selecciona la zona horaria para exponer las fechas del curso. Si no especificas una zona horaria, las fechas del curso, incluidas las fechas l\u00edmites de tareas, ser\u00e1n expuestas en la zona horaria local de tu navegador.",
"Select turnaround": "Seleccione tiempo de entrega.",
- "Selected blocks": "Bloques seleccionados",
"Selected tab": "Opci\u00f3n seleccionada",
"Self": "Auto",
"Send to:": "Enviar a:",
@@ -1994,6 +1998,7 @@
"There is no email history for this course.": "No hay historial de correos electr\u00f3nicos para este curso.",
"There is no onboarding exam accessible to this user.": "No se registra examen de inducci\u00f3n asequible para este usuario.",
"There is no onboarding exam related to this course id.": "No se registra un examen de inducci\u00f3n relacionado a esta identificaci\u00f3n de curso.",
+ "There is still file upload in progress. Please wait until it is finished.": "Todav\u00eda hay una carga de archivos en curso. Por favor espere hasta que termine.",
"There must be at least one group.": "Debe existir al menos un grupo.",
"There must be one cohort to which students can automatically be assigned.": "Tiene que haber una cohorte a la que los estudiantes pueden ser asignados autom\u00e1ticamente.",
"There was a problem creating the report. Select \"Create Executive Summary\" to try again.": "Hubo un problema creando el reporte. Selecciona \"Crear resumen ejecutivo\" para intentarlo nuevamente.",
@@ -2163,7 +2168,6 @@
"Unable to load": "No se ha podido cargar",
"Unable to submit application": "No se pudo enviar la solicitud",
"Unable to submit request to generate report.": "No se puede enviar la solicitud para generar reporte.",
- "Unable to update settings": "No es posible modificar las configuraciones",
"Underline": "Subrayado",
"Undo": "Deshacer",
"Undo (Ctrl+Z)": "Deshacer (Ctrl+Z)",
@@ -2308,6 +2312,7 @@
"View and grade responses": "Ver y calificar las respuestas",
"View child items": "Ver items hijos",
"View discussion": "Ver discusi\u00f3n",
+ "View files": "Archivos de vista",
"View my exam": "Ver mi examen",
"View program": "Ver programa",
"View your receipts or modify your subscription on the {a_start}Orders and subscriptions{a_end} page": "Consulta tus recibos o modifica tu suscripci\u00f3n en la p\u00e1gina {a_start}Pedidos y suscripciones{a_end}",
diff --git a/cms/static/js/i18n/es-ar/djangojs.js b/cms/static/js/i18n/es-ar/djangojs.js
index 76478b97ffc8..298c573a68c5 100644
--- a/cms/static/js/i18n/es-ar/djangojs.js
+++ b/cms/static/js/i18n/es-ar/djangojs.js
@@ -158,6 +158,7 @@
"Block view is unavailable": "La vista de bloque no est\u00e1 disponible",
"Can I request additional time to complete my exam?": "\u00bfPuedo solicitar un tiempo adicional para completar mi examen?",
"Cancel": "Cancelar",
+ "Cannot submit empty response even everything is optional.": "No se puede enviar una respuesta vac\u00eda, incluso si todo es opcional.",
"Cannot update attempt review status": "No se puede actualizar el estado de revisi\u00f3n del intento",
"Changes to steps that are not selected as part of the assignment will not be saved.": "Los cambios en los pasos que no se seleccionen como parte de la tarea no se guardar\u00e1n.",
"Choose": "Seleccionar",
@@ -241,6 +242,7 @@
"Must be a Staff User to Perform this request.": "Debe ser un miembro del equipo para realizar esta petici\u00f3n.",
"Navigate to onboarding exam": "Navegar al examen de incorporaci\u00f3n",
"No exams in course {course_id}.": "No hay ex\u00e1menes en curso {course_id}.",
+ "No files selected for upload.": "No hay archivos seleccionados para cargar.",
"No instructor dashboard for {proctor_service}": "No hay panel de instructor para {proctor_service}",
"No onboarding status API for {proctor_service}": "Sin API de estado de ingreso para {proctor_service}",
"No proctored exams in course {course_id}": "No hay ex\u00e1menes supervisados en curso {course_id}",
@@ -272,6 +274,9 @@
"Peers Assessed": "Compa\u00f1eros evaluados",
"Pending Session Review": "Revisi\u00f3n de sesi\u00f3n pendiente",
"Please check your internet connection.": "Por favor, revisar la conexi\u00f3n de Internet.",
+ "Please provide a description for each file you are uploading.": "Proporcione una descripci\u00f3n para cada archivo que est\u00e1 cargando.",
+ "Please provide a response.": "Por favor, escriba una respuesta.",
+ "Please upload a file.": "Por favor, cargue un archivo.",
"Please wait": "Espere por favor",
"Practice Exam Completed": "Examen de pr\u00e1ctica completado",
"Practice Exam Failed": "Examen de pr\u00e1ctica fallido",
@@ -326,6 +331,7 @@
"There are currently {stuck_learners} learners in the waiting state, meaning they have not yet met all requirements for Peer Assessment. ": "Actualmente hay {stuck_learners} alumnos en estado de espera, lo que significa que a\u00fan no han cumplido con todos los requisitos para la evaluaci\u00f3n por pares.",
"There is no onboarding exam accessible to this user.": "No hay ning\u00fan examen de ingreso accesible para este usuario.",
"There is no onboarding exam related to this course id.": "No hay un examen de ingreso relacionado con esta identificaci\u00f3n de curso.",
+ "There is still file upload in progress. Please wait until it is finished.": "Todav\u00eda hay una carga de archivos en curso. Por favor, espere hasta que termine.",
"This ORA has already been released. Changes will only affect learners making new submissions. Existing submissions will not be modified by this change.": "Este ORA ya ha sido publicado. Los cambios solo afectar\u00e1n a los alumnos que realicen nuevos env\u00edos. Las presentaciones existentes no se ver\u00e1n modificadas por este cambio.",
"This assessment could not be submitted.": "Esta evaluaci\u00f3n no se pudo enviar.",
"This exam has a time limit associated with it.": "Este examen tiene un l\u00edmite de tiempo",
diff --git a/cms/static/js/i18n/es-es/djangojs.js b/cms/static/js/i18n/es-es/djangojs.js
index 2c0d4f535e14..92f27659fdc3 100644
--- a/cms/static/js/i18n/es-es/djangojs.js
+++ b/cms/static/js/i18n/es-es/djangojs.js
@@ -158,6 +158,7 @@
"Block view is unavailable": "La vista en bloque no est\u00e1 disponible",
"Can I request additional time to complete my exam?": "\u00bfPuedo solicitar un tiempo adicional para completar mi examen?",
"Cancel": "Cancelar",
+ "Cannot submit empty response even everything is optional.": "No se puede enviar una respuesta vac\u00eda, incluso si todo es opcional.",
"Cannot update attempt review status": "No se puede actualizar el estado de revisi\u00f3n del intento",
"Changes to steps that are not selected as part of the assignment will not be saved.": "Los cambios en los pasos que no est\u00e1n seleccionados como parte de la tarea no se guardar\u00e1n.",
"Choose": "Elegir",
@@ -241,6 +242,7 @@
"Must be a Staff User to Perform this request.": "Debes ser un miembro del equipo para realizar esta petici\u00f3n.",
"Navigate to onboarding exam": "Navegar al examen de incorporaci\u00f3n",
"No exams in course {course_id}.": "No hay ex\u00e1menes en curso {course_id}.",
+ "No files selected for upload.": "No hay archivos seleccionados para cargar.",
"No instructor dashboard for {proctor_service}": "No hay panel de instructor para {proctor_service}",
"No onboarding status API for {proctor_service}": "Sin API de estado de ingreso para {proctor_service}",
"No proctored exams in course {course_id}": "No hay ex\u00e1menes supervisados en curso {course_id}",
@@ -272,6 +274,9 @@
"Peers Assessed": "Compa\u00f1ero evaluado",
"Pending Session Review": "Revisi\u00f3n de la sesi\u00f3n pendiente",
"Please check your internet connection.": "Por favor, revisar la conexi\u00f3n de Internet.",
+ "Please provide a description for each file you are uploading.": "Proporcione una descripci\u00f3n para cada archivo que est\u00e1 cargando.",
+ "Please provide a response.": "Por favor, escriba una respuesta.",
+ "Please upload a file.": "Por favor, cargue un archivo.",
"Please wait": "Por favor, espera",
"Practice Exam Completed": "Examen pr\u00e1ctico completado",
"Practice Exam Failed": "Examen pr\u00e1ctico fallido",
@@ -326,6 +331,7 @@
"There are currently {stuck_learners} learners in the waiting state, meaning they have not yet met all requirements for Peer Assessment. ": "Actualmente se encuentran {stuck_learners} estudiantes en estado de espera, lo cual significa que a\u00fan no cumplen con todos los requisitos para la evaluaci\u00f3n por pares.",
"There is no onboarding exam accessible to this user.": "No hay ning\u00fan examen de ingreso accesible para este usuario.",
"There is no onboarding exam related to this course id.": "No hay un examen de ingreso relacionado con esta identificaci\u00f3n de curso.",
+ "There is still file upload in progress. Please wait until it is finished.": "Todav\u00eda hay una carga de archivos en curso. Por favor, espere hasta que termine.",
"This ORA has already been released. Changes will only affect learners making new submissions. Existing submissions will not be modified by this change.": "Esta tarea de respuesta abierta ya ha sido publicada. Los cambios solo afectar\u00e1n a los estudiantes que hagan nuevas entregas. Las entregas ya realizadas no se ver\u00e1n modificadas por este cambio.",
"This assessment could not be submitted.": "Esta tarea no ha podido enviarse.",
"This exam has a time limit associated with it.": "Este examen tiene un l\u00edmite de tiempo",
diff --git a/cms/static/js/i18n/eu-es/djangojs.js b/cms/static/js/i18n/eu-es/djangojs.js
index 8e9f08714f1a..cc6b5d6487c2 100644
--- a/cms/static/js/i18n/eu-es/djangojs.js
+++ b/cms/static/js/i18n/eu-es/djangojs.js
@@ -1159,7 +1159,6 @@
"This is the list of chosen %s. You may remove some by selecting them in the box below and then clicking the \"Remove\" arrow between the two boxes.": "Hau da aukeratutako %s zerrenda. Hauetako zenbait ezaba ditzakezu azpiko kutxan hautatu eta bi kutxen artean dagoen \"Ezabatu\" gezian klik eginez.",
"This is the name of the group": "Hau taldearen izena da",
"This learner is currently sharing a limited profile.": "Ikasle hau une honetan profil mugatua partekatzen ari da.",
- "This may be happening because of an error with our server or your internet connection. Try refreshing the page or making sure you are online.": "Zure zerbitzarearen edo zure interneteko konexioaren arazo batengatik gertatuko zen hau agian. Saiatu orria freskatzen eta ziurtatu on-line zaudela.",
"This post could not be closed. Refresh the page and try again.": "Mezu hau ezin da itxi. Freskatu orria eta saiatu berri",
"This post could not be flagged for abuse. Refresh the page and try again.": "Mezu hau ezin da iraintzat markatu. Freskatu orria eta saiatu berri",
"This post could not be unflagged for abuse. Refresh the page and try again.": "Mezu hau ezin da iraintzat desmarkatu. Freskatu orria eta saiatu berri",
diff --git a/cms/static/js/i18n/fa-ir/djangojs.js b/cms/static/js/i18n/fa-ir/djangojs.js
index a6fdba8dbe1c..ef7a945126da 100644
--- a/cms/static/js/i18n/fa-ir/djangojs.js
+++ b/cms/static/js/i18n/fa-ir/djangojs.js
@@ -467,6 +467,7 @@
"Cannot delete when in use by a unit": "\u0646\u0645\u06cc\u200c\u062a\u0648\u0627\u0646\u06cc\u062f \u0647\u0646\u06af\u0627\u0645 \u0627\u0633\u062a\u0641\u0627\u062f\u0647 \u062a\u0648\u0633\u0637 \u06cc\u06a9 \u0648\u0627\u062d\u062f\u060c \u0622\u0646 \u0631\u0627 \u062d\u0630\u0641 \u06a9\u0646\u06cc\u062f",
"Cannot delete when in use by an experiment": "\u0647\u0646\u06af\u0627\u0645\u06cc \u06a9\u0647 \u0627\u0632 \u0622\u0646 \u062f\u0631 \u062a\u062c\u0631\u0628\u0647\u200c\u0627\u06cc \u0627\u0633\u062a\u0641\u0627\u062f\u0647 \u0645\u06cc\u200c\u0634\u0648\u062f \u0627\u0645\u06a9\u0627\u0646 \u062d\u0630\u0641 \u0622\u0646 \u0646\u06cc\u0633\u062a",
"Cannot join instructor managed team": "\u0646\u0645\u06cc\u200c\u062a\u0648\u0627\u0646\u06cc\u062f \u0628\u0647 \u062a\u06cc\u0645\u06cc \u06a9\u0647 \u062a\u0648\u0633\u0637 \u0645\u0631\u0628\u06cc \u0645\u062f\u06cc\u0631\u06cc\u062a \u0645\u06cc\u200c\u0634\u0648\u062f \u0628\u067e\u06cc\u0648\u0646\u062f\u06cc\u062f",
+ "Cannot submit empty response even everything is optional.": "\u0646\u0645\u06cc \u062a\u0648\u0627\u0646 \u067e\u0627\u0633\u062e \u062e\u0627\u0644\u06cc \u0627\u0631\u0633\u0627\u0644 \u06a9\u0631\u062f \u062d\u062a\u06cc \u0647\u0645\u0647 \u0686\u06cc\u0632 \u0627\u062e\u062a\u06cc\u0627\u0631\u06cc \u0627\u0633\u062a.",
"Cannot update attempt review status": "\u0627\u0645\u06a9\u0627\u0646 \u0631\u0648\u0632\u0622\u0645\u062f\u0633\u0627\u0632\u06cc \u0648\u0636\u0639\u06cc\u062a \u062a\u0644\u0627\u0634 \u0628\u0631\u0631\u0633\u06cc \u0646\u06cc\u0633\u062a",
"Caption": " \u062a\u0648\u0636\u06cc\u062d",
"Caution: The last published version of this unit is live. By publishing changes you will change the student experience.": "\u0627\u062d\u062a\u06cc\u0627\u0637: \u0622\u062e\u0631\u06cc\u0646 \u0646\u0633\u062e\u06c0 \u0645\u0646\u062a\u0634\u0631\u0634\u062f\u06c0 \u0627\u06cc\u0646 \u0648\u0627\u062d\u062f \u067e\u062e\u0634 \u0632\u0646\u062f\u0647 \u0627\u0633\u062a. \u0628\u0627 \u0627\u0646\u062a\u0634\u0627\u0631 \u062a\u063a\u06cc\u06cc\u0631\u0627\u062a\u060c \u062a\u062c\u0631\u0628\u06c0 \u06cc\u0627\u062f\u06af\u06cc\u0631\u0646\u062f\u0647 \u0631\u0627 \u062a\u063a\u06cc\u06cc\u0631 \u062e\u0648\u0627\u0647\u06cc\u062f \u062f\u0627\u062f.",
@@ -757,6 +758,7 @@
"Draft (Never published)": "\u067e\u06cc\u0634\u200c\u0646\u0648\u06cc\u0633 (\u0647\u0631\u06af\u0632 \u0645\u0646\u062a\u0634\u0631\u0646\u0634\u062f\u0647)",
"Draft (Unpublished changes)": "\u067e\u06cc\u0634\u200c\u0646\u0648\u06cc\u0633 (\u062a\u063a\u06cc\u06cc\u0631\u0627\u062a \u0645\u0646\u062a\u0634\u0631\u0646\u0634\u062f\u0647)",
"Draft saved on {lastSavedStart}{editedOn}{lastSavedEnd} by {editedByStart}{editedBy}{editedByEnd}": "\u067e\u06cc\u0634\u200c\u0646\u0648\u06cc\u0633 \u0630\u062e\u06cc\u0631\u0647 \u0634\u062f\u0647 \u0627\u0633\u062a \u062f\u0631 {lastSavedStart}{editedOn}{lastSavedEnd} \u0628\u0647\u200c\u062f\u0633\u062a {editedByStart}{editedBy}{editedByEnd}",
+ "Draft saved!": "\u067e\u06cc\u0634 \u0646\u0648\u06cc\u0633 \u0630\u062e\u06cc\u0631\u0647 \u0634\u062f!",
"Drag and drop or {spanStart}browse your computer{spanEnd}.": "\u0628\u06a9\u0634 \u0648 \u0631\u0647\u0627\u06a9\u0646 \u06cc\u0627 {spanStart} \u0631\u0627\u06cc\u0627\u0646\u0647\u200c\u0627\u062a \u0631\u0627 \u0628\u0631\u0631\u0633\u06cc \u06a9\u0646 {spanEnd}.",
"Drag to reorder": "\u06a9\u0634\u06cc\u062f\u0646 \u0628\u0631\u0627\u06cc \u062a\u0631\u062a\u06cc\u0628 \u0645\u062c\u062f\u062f",
"Drop target image": "\u062a\u0635\u0648\u06cc\u0631 \u0647\u062f\u0641 \u0631\u0627 \u0631\u0647\u0627 \u06a9\u0646\u06cc\u062f",
@@ -1212,7 +1214,6 @@
"Loading more threads": "\u062f\u0631 \u062d\u0627\u0644 \u0628\u0627\u0631\u06af\u06cc\u0631\u06cc \u0645\u0648\u0636\u0648\u0639\u0627\u062a \u0628\u06cc\u0634\u062a\u0631",
"Loading posts list": "\u062f\u0631 \u062d\u0627\u0644 \u0628\u0627\u0631\u06af\u06cc\u0631\u06cc \u0641\u0647\u0631\u0633\u062a \u0645\u0637\u0627\u0644\u0628 \u0627\u0631\u0633\u0627\u0644\u06cc",
"Loading your courses": "\u062f\u0631 \u062d\u0627\u0644 \u0628\u0627\u0631\u06af\u06cc\u0631\u06cc \u062f\u0648\u0631\u0647\u200c\u0647\u0627\u06cc \u0634\u0645\u0627",
- "Loading...": "\u062f\u0631 \u062d\u0627\u0644 \u0628\u0627\u0631\u06af\u06cc\u0631\u06cc ...",
"Location": "\u0645\u06a9\u0627\u0646",
"Location in Course": "\u0645\u06a9\u0627\u0646 \u062f\u0631 \u062f\u0648\u0631\u0647 \u0622\u0645\u0648\u0632\u0634\u06cc",
"Lock this asset": "\u0642\u0641\u0644 \u0627\u06cc\u0646 \u0645\u0646\u0628\u0639",
@@ -1293,7 +1294,6 @@
"New Password": "\u06af\u0630\u0631\u0648\u0627\u0698\u06c0 \u062c\u062f\u06cc\u062f",
"New document": "\u0633\u0646\u062f \u062c\u062f\u06cc\u062f",
"New enrollment mode:": "\u0648\u0636\u0639\u06cc\u062a \u062a\u0627\u0632\u0647 \u062b\u0628\u062a\u200c\u0646\u0627\u0645:",
- "New files were added to this course's Files & Uploads": "\u0641\u0627\u06cc\u0644 \u0647\u0627\u06cc \u062c\u062f\u06cc\u062f \u0628\u0647 \"\u0641\u0627\u06cc\u0644 \u0647\u0627 \u0648 \u0622\u067e\u0644\u0648\u062f\u0647\u0627\"\u06cc \u0627\u06cc\u0646 \u062f\u0648\u0631\u0647 \u0627\u0636\u0627\u0641\u0647 \u0634\u062f",
"New window": "\u067e\u0646\u062c\u0631\u06c0 \u062c\u062f\u06cc\u062f",
"New {component_type}": "{component_type} \u062c\u062f\u06cc\u062f",
"Next": "\u0628\u0639\u062f\u06cc",
@@ -1309,6 +1309,7 @@
"No content-specific discussion topics exist.": "\u0647\u06cc\u0686 \u0645\u0628\u062d\u062b\u06cc \u0645\u0631\u0628\u0648\u0637 \u0628\u0647 \u0645\u062d\u062a\u0648\u0627\u06cc \u062e\u0627\u0635 \u0648\u062c\u0648\u062f \u0646\u062f\u0627\u0631\u062f.",
"No description available": "\u0628\u062f\u0648\u0646 \u0634\u0631\u062d",
"No exams in course {course_id}.": "\u0647\u06cc\u0686 \u0622\u0632\u0645\u0648\u0646\u06cc \u062f\u0631 \u062f\u0648\u0631\u0647 \u0622\u0645\u0648\u0632\u0634\u06cc {course_id} \u0648\u062c\u0648\u062f \u0646\u062f\u0627\u0631\u062f.",
+ "No files selected for upload.": "\u0647\u06cc\u0686 \u0641\u0627\u06cc\u0644\u06cc \u0628\u0631\u0627\u06cc \u0622\u067e\u0644\u0648\u062f \u0627\u0646\u062a\u062e\u0627\u0628 \u0646\u0634\u062f\u0647 \u0627\u0633\u062a.",
"No instructor dashboard for {proctor_service}": "\u0628\u062f\u0648\u0646 \u067e\u06cc\u0634\u062e\u0648\u0627\u0646 \u0622\u0645\u0648\u0632\u0634\u06cc \u0628\u0631\u0627\u06cc {proctor_service}",
"No onboarding status API for {proctor_service}": "API \u0648\u0636\u0639\u06cc\u062a \u0648\u0631\u0648\u062f \u0628\u0631\u0627\u06cc {proctor_service} \u0648\u062c\u0648\u062f \u0646\u062f\u0627\u0631\u062f",
"No posts matched your query.": "\u0647\u06cc\u0686 \u0645\u0637\u0644\u0628 \u0627\u0631\u0633\u0627\u0644\u06cc \u0628\u0627 \u062c\u0633\u062a\u062c\u0648\u06cc \u0634\u0645\u0627 \u0645\u0646\u0637\u0628\u0642 \u0646\u0628\u0648\u062f.",
@@ -1449,6 +1450,7 @@
"Please add the instructor's title": "\u0644\u0637\u0641\u0627\u064b \u0639\u0646\u0648\u0627\u0646 \u0645\u0631\u0628\u06cc \u0631\u0627 \u0628\u06cc\u0641\u0632\u0627\u06cc\u06cc\u062f",
"Please address the errors on this page first, and then save your progress.": "\u0644\u0637\u0641\u0627 \u0627\u0628\u062a\u062f\u0627 \u062e\u0637\u0627\u0647\u0627\u06cc \u0627\u06cc\u0646 \u0635\u0641\u062d\u0647 \u0631\u0627 \u0628\u0631\u0631\u0633\u06cc \u0648 \u0631\u0641\u0639 \u06a9\u0631\u062f\u0647 \u0633\u067e\u0633 \u0645\u06cc\u0632\u0627\u0646 \u067e\u06cc\u0634\u0631\u0641\u062a \u062e\u0648\u062f \u0631\u0627 \u0630\u062e\u06cc\u0631\u0647 \u06a9\u0646\u06cc\u062f. ",
"Please check the following validation feedbacks and reflect them in your course settings:": "\u0644\u0637\u0641\u0627\u064b \u0628\u0627\u0632\u062e\u0648\u0631\u062f\u0647\u0627\u06cc \u062a\u0623\u06cc\u06cc\u062f \u0627\u0639\u062a\u0628\u0627\u0631 \u0632\u06cc\u0631 \u0631\u0627 \u06a9\u0646\u062a\u0631\u0644 \u06a9\u0631\u062f\u0647 \u0648 \u0622\u0646\u200c\u0647\u0627 \u0631\u0627 \u062f\u0631 \u062a\u0646\u0638\u06cc\u0645\u0627\u062a \u062f\u0648\u0631\u06c0 \u0622\u0645\u0648\u0632\u0634\u06cc \u062e\u0648\u062f \u0645\u0646\u0639\u06a9\u0633 \u06a9\u0646\u06cc\u062f:",
+ "Please check your internet connection.": "\u0644\u0637\u0641\u0627 \u0627\u062a\u0635\u0627\u0644 \u0627\u06cc\u0646\u062a\u0631\u0646\u062a \u062e\u0648\u062f \u0631\u0627 \u0628\u0631\u0631\u0633\u06cc \u06a9\u0646\u06cc\u062f.",
"Please describe this image or agree that it has no contextual value by checking the checkbox.": "\u0644\u0637\u0641\u0627\u064b \u0627\u06cc\u0646 \u062a\u0635\u0648\u06cc\u0631 \u0631\u0627 \u062a\u0648\u0635\u06cc\u0641 \u06a9\u0646\u06cc\u062f \u06cc\u0627 \u0628\u0627 \u0632\u062f\u0646 \u0639\u0644\u0627\u0645\u062a \u062f\u0631 \u062e\u0627\u0646\u0647 \u06a9\u0646\u062a\u0631\u0644 \u0645\u0648\u0627\u0641\u0642\u062a \u06a9\u0646\u06cc\u062f \u06a9\u0647 \u0647\u06cc\u0686 \u0627\u0631\u0632\u0634 \u0645\u062a\u0646\u06cc \u0646\u062f\u0627\u0631\u062f. ",
"Please do not use any spaces in this field.": "\u0644\u0637\u0641\u0627 \u0627\u0632 \u0641\u0627\u0635\u0644\u0647 \u062f\u0631 \u0627\u06cc\u0646 \u0642\u0633\u0645\u062a \u0627\u0633\u062a\u0641\u0627\u062f\u0647 \u0646\u06a9\u0646\u06cc\u062f.",
"Please do not use any spaces or special characters in this field.": "\u0644\u0637\u0641\u0627 \u0627\u0632 \u0641\u0627\u0635\u0644\u0647 \u06cc\u0627 \u0646\u0648\u06cc\u0633\u0647\u200c\u0647\u0627\u06cc \u062e\u0627\u0635 \u062f\u0631 \u0627\u06cc\u0646 \u0642\u0633\u0645\u062a \u0627\u0633\u062a\u0641\u0627\u062f\u0647 \u0646\u06a9\u0646\u06cc\u062f.",
@@ -1469,12 +1471,15 @@
"Please fix the following errors:": "\u0644\u0637\u0641\u0627\u064b \u062e\u0637\u0627\u0647\u0627\u06cc \u0632\u06cc\u0631 \u0631\u0627 \u0627\u0635\u0644\u0627\u062d \u06a9\u0646\u06cc\u062f:",
"Please follow the instructions here to upload a file elsewhere and link to it: {maxFileSizeRedirectUrl}": "\u0644\u0637\u0641\u0627 \u0631\u0627\u0647\u0646\u0645\u0627\u06cc \u0632\u06cc\u0631 \u0631\u0627 \u0628\u0631\u0627\u06cc \u0686\u06af\u0648\u0646\u06af\u06cc \u0628\u0627\u0631\u06af\u0630\u0627\u0631\u06cc \u06cc\u06a9 \u0641\u0627\u06cc\u0644 \u062f\u0631 \u062c\u0627\u06cc\u06cc \u062f\u06cc\u06af\u0631 \u0648 \u06cc\u06a9 \u0627\u0631\u062a\u0628\u0627\u0637 \u0628\u0647 \u0622\u0646 \u0627\u06cc\u062c\u0627\u062f \u06a9\u0646\u06cc\u062f : {maxFileSizeRedirectUrl}",
"Please note: Deletion of your account and personal data is permanent and cannot be undone. {platformName} will not be able to recover your account or the data that is deleted.": "\u0644\u0637\u0641\u0627\u064b \u062a\u0648\u062c\u0647 \u062f\u0627\u0634\u062a\u0647 \u0628\u0627\u0634\u06cc\u062f: \u062d\u0633\u0627\u0628 \u06a9\u0627\u0631\u0628\u0631\u06cc \u0648 \u062f\u0627\u062f\u0647\u200c\u0647\u0627\u06cc \u0634\u062e\u0635\u06cc \u0634\u0645\u0627 \u0628\u0631\u0627\u06cc \u0647\u0645\u06cc\u0634\u0647 \u062d\u0630\u0641 \u062e\u0648\u0627\u0647\u062f \u0634\u062f \u0648 \u0642\u0627\u0628\u0644 \u0648\u0627\u06af\u0631\u062f \u0646\u06cc\u0633\u062a. \u067e\u0633 {platformName} \u0646\u0645\u06cc\u200c\u062a\u0648\u0627\u0646\u062f \u062d\u0633\u0627\u0628 \u06a9\u0627\u0631\u0628\u0631\u06cc \u0634\u0645\u0627 \u06cc\u0627 \u062f\u0627\u062f\u0647\u200c\u0647\u0627\u06cc \u062d\u0630\u0641\u200c\u0634\u062f\u0647 \u0631\u0627 \u0628\u0627\u0632\u06cc\u0627\u0628\u06cc \u06a9\u0646\u062f.",
+ "Please provide a description for each file you are uploading.": "\u0644\u0637\u0641\u0627\u064b \u062a\u0648\u0636\u06cc\u062d\u06cc \u0628\u0631\u0627\u06cc \u0647\u0631 \u0641\u0627\u06cc\u0644\u06cc \u06a9\u0647 \u0622\u067e\u0644\u0648\u062f \u0645\u06cc \u06a9\u0646\u06cc\u062f \u0627\u0631\u0627\u0626\u0647 \u062f\u0647\u06cc\u062f.",
"Please provide a description of the link destination.": "\u0644\u0637\u0641\u0627\u064b \u062a\u0648\u0636\u06cc\u062d\u06cc \u062f\u0631\u0628\u0627\u0631\u06c0 \u0645\u0642\u0635\u062f \u067e\u06cc\u0648\u0646\u062f \u0627\u0631\u0627\u0626\u0647 \u062f\u0647\u06cc\u062f.",
+ "Please provide a response.": "\u0644\u0637\u0641\u0627 \u067e\u0627\u0633\u062e \u062f\u0647\u06cc\u062f.",
"Please provide a valid URL.": "\u06cc\u06a9 \u0646\u0634\u0627\u0646\u06cc \u0627\u06cc\u0646\u062a\u0631\u0646\u062a\u06cc \u0645\u0639\u062a\u0628\u0631 \u0648\u0627\u0631\u062f \u06a9\u0646\u06cc\u062f.",
"Please re-enter your password.": "\u0644\u0637\u0641\u0627\u064b \u06af\u0630\u0631\u0648\u0627\u0698\u0647 \u0631\u0627 \u062f\u0648\u0628\u0627\u0631\u0647 \u0648\u0627\u0631\u062f \u06a9\u0646\u06cc\u062f.",
"Please select a PDF file to upload.": "\u0644\u0637\u0641\u0627 \u06cc\u06a9 \u067e\u0631\u0648\u0646\u062f\u0647 PDF \u0628\u0631\u0627\u06cc \u0628\u0627\u0631\u06af\u0630\u0627\u0631\u06cc \u0627\u0646\u062a\u062e\u0627\u0628 \u06a9\u0646\u06cc\u062f",
"Please select a file in .srt format.": "\u0644\u0637\u0641\u0627 \u06cc\u06a9 \u067e\u0631\u0648\u0646\u062f\u0647 \u0628\u0627 \u0642\u0627\u0644\u0628 srt. \u0628\u0631\u0627\u06cc \u0628\u0627\u0631\u06af\u0630\u0627\u0631\u06cc \u0627\u0646\u062a\u062e\u0627\u0628 \u06a9\u0646\u06cc\u062f.",
"Please specify a reason.": "\u0644\u0637\u0641\u0627\u064b \u06cc\u06a9 \u062f\u0644\u06cc\u0644 \u0630\u06a9\u0631 \u06a9\u0646\u06cc\u062f.",
+ "Please upload a file.": "\u0644\u0637\u0641\u0627 \u06cc\u06a9 \u0641\u0627\u06cc\u0644 \u0622\u067e\u0644\u0648\u062f \u06a9\u0646\u06cc\u062f",
"Please verify that you have uploaded a valid image (PNG and JPEG).": "\u0644\u0637\u0641\u0627\u064b \u062a\u0623\u06cc\u06cc\u062f \u06a9\u0646\u06cc\u062f \u06a9\u0647 \u062a\u0635\u0648\u06cc\u0631\u06cc \u0645\u0639\u062a\u0628\u0631 (PNG \u0648 JPEG) \u0628\u0627\u0631\u06af\u0630\u0627\u0631\u06cc \u06a9\u0631\u062f\u0647\u200c\u0627\u06cc\u062f.",
"Please verify that your webcam is connected and that you have allowed your browser to access it.": "\u0644\u0637\u0641\u0627\u064b \u0628\u0631\u0631\u0633\u06cc \u06a9\u0646\u06cc\u062f \u06a9\u0647 \u062f\u0648\u0631\u0628\u06cc\u0646 \u0631\u0627\u06cc\u0627\u0646\u06c0 \u0634\u0645\u0627 \u0645\u062a\u0635\u0644 \u0627\u0633\u062a \u0648 \u0628\u0647 \u0645\u0631\u0648\u0631\u06af\u0631 \u062e\u0648\u062f \u0627\u062c\u0627\u0632\u06c0 \u062f\u0633\u062a\u0631\u0633\u06cc \u0628\u0647 \u0622\u0646 \u0631\u0627 \u062f\u0627\u062f\u0647\u200c\u0627\u06cc\u062f.",
"Please wait": "\u0644\u0637\u0641\u0627 \u0634\u06a9\u06cc\u0628\u0627 \u0628\u0627\u0634\u06cc\u062f",
@@ -1650,6 +1655,8 @@
"Save changes": "\u0630\u062e\u06cc\u0631\u0647 \u062a\u063a\u06cc\u06cc\u0631\u0627\u062a",
"Saved cohort": "\u062f\u0633\u062a\u0647 \u0630\u062e\u06cc\u0631\u0647 \u0634\u062f\u0647 ",
"Saving": "\u062f\u0631 \u062d\u0627\u0644 \u0630\u062e\u06cc\u0631\u0647\u200c\u0633\u0627\u0632\u06cc",
+ "Saving draft": "\u0630\u062e\u06cc\u0631\u0647 \u067e\u06cc\u0634 \u0646\u0648\u06cc\u0633",
+ "Saving draft...": "\u062f\u0631 \u062d\u0627\u0644 \u0630\u062e\u06cc\u0631\u0647 \u067e\u06cc\u0634 \u0646\u0648\u06cc\u0633...",
"Saving your email preference": "\u062f\u0631 \u062d\u0627\u0644 \u0630\u062e\u06cc\u0631\u06c0 \u0631\u0627\u06cc\u0627\u0646\u0627\u0645\u0647 \u0645\u0631\u062c\u062d",
"Scheduled:": "\u0628\u0631\u0646\u0627\u0645\u0647\u200c\u0631\u06cc\u0632\u06cc\u200c\u0634\u062f\u0647:",
"Scope": "\u062f\u0627\u0645\u0646\u0647",
@@ -1691,7 +1698,6 @@
"Select the course-wide discussion topics that you want to divide.": "\u0645\u0628\u0627\u062d\u062b \u06af\u0641\u062a\u06af\u0648\u06cc \u0637\u0648\u0644 \u062f\u0648\u0631\u0647 \u0622\u0645\u0648\u0632\u0634\u06cc \u0631\u0627 \u0627\u0646\u062a\u062e\u0627\u0628 \u06a9\u0646\u06cc\u062f \u06a9\u0647 \u0645\u06cc\u200c\u062e\u0648\u0627\u0647\u06cc\u062f \u062a\u0642\u0633\u06cc\u0645 \u06a9\u0646\u06cc\u062f.",
"Select the time zone for displaying course dates. If you do not specify a time zone, course dates, including assignment deadlines, will be displayed in your browser's local time zone.": "\u0645\u0646\u0637\u0642\u06c0 \u0632\u0645\u0627\u0646\u06cc \u0631\u0627 \u0628\u0631\u0627\u06cc \u0646\u0645\u0627\u06cc\u0634 \u062a\u0627\u0631\u06cc\u062e \u062f\u0648\u0631\u0647 \u0622\u0645\u0648\u0632\u0634\u06cc \u0627\u0646\u062a\u062e\u0627\u0628 \u06a9\u0646\u06cc\u062f. \u0627\u06af\u0631 \u0645\u0646\u0637\u0642\u06c0 \u0632\u0645\u0627\u0646\u06cc \u0631\u0627 \u0645\u0634\u062e\u0635 \u0646\u06a9\u0646\u06cc\u062f\u060c \u062a\u0627\u0631\u06cc\u062e \u062f\u0648\u0631\u0647\u200c\u0647\u0627\u060c \u0645\u0627\u0646\u0646\u062f \u0645\u0647\u0644\u062a \u0627\u0646\u062c\u0627\u0645 \u062a\u06a9\u0644\u06cc\u0641\u060c \u062f\u0631 \u0645\u0646\u0637\u0642\u06c0 \u0632\u0645\u0627\u0646\u06cc \u0645\u062d\u0644\u06cc \u0645\u0631\u0648\u0631\u06af\u0631 \u0634\u0645\u0627 \u0646\u0645\u0627\u06cc\u0634 \u062f\u0627\u062f\u0647 \u0645\u06cc\u200c\u0634\u0648\u062f.",
"Select turnaround": "\u0627\u0646\u062a\u062e\u0627\u0628 \u0686\u0631\u062e\u0634",
- "Selected blocks": "\u0628\u0644\u0648\u06a9\u200c\u0647\u0627\u06cc \u0645\u0646\u062a\u062e\u0628",
"Selected tab": "\u0632\u0628\u0627\u0646\u06c0 \u0628\u0631\u06af\u0632\u06cc\u062f\u0647",
"Self": "\u062e\u0648\u062f",
"Send to:": "\u0627\u0631\u0633\u0627\u0644 \u0628\u0647:",
@@ -1990,6 +1996,7 @@
"There is no email history for this course.": "\u0627\u06cc\u0646 \u062f\u0648\u0631\u0647 \u0622\u0645\u0648\u0632\u0634\u06cc\u060c \u0633\u0627\u0628\u0642\u0647 \u0627\u0631\u0633\u0627\u0644 \u0631\u0627\u06cc\u0627\u0646\u0627\u0645\u0647 \u0646\u062f\u0627\u0631\u062f.",
"There is no onboarding exam accessible to this user.": "\u0647\u06cc\u0686 \u0622\u0632\u0645\u0648\u0646 \u0622\u0632\u0645\u0627\u06cc\u0634\u06cc \u0628\u0631\u0627\u06cc \u0627\u06cc\u0646 \u06a9\u0627\u0631\u0628\u0631 \u0648\u062c\u0648\u062f \u0646\u062f\u0627\u0631\u062f.",
"There is no onboarding exam related to this course id.": "\u0647\u06cc\u0686 \u0622\u0632\u0645\u0648\u0646 \u0648\u0631\u0648\u062f\u06cc \u0645\u0631\u0628\u0648\u0637 \u0628\u0647 \u0627\u06cc\u0646 \u0634\u0646\u0627\u0633\u0647 \u062f\u0648\u0631\u0647 \u0622\u0645\u0648\u0632\u0634\u06cc \u0648\u062c\u0648\u062f \u0646\u062f\u0627\u0631\u062f.",
+ "There is still file upload in progress. Please wait until it is finished.": "\u0647\u0646\u0648\u0632 \u0622\u067e\u0644\u0648\u062f \u0641\u0627\u06cc\u0644 \u062f\u0631 \u062d\u0627\u0644 \u0627\u0646\u062c\u0627\u0645 \u0627\u0633\u062a. \u0644\u0637\u0641\u0627 \u0635\u0628\u0631 \u06a9\u0646\u06cc\u062f \u062a\u0627 \u062a\u0645\u0627\u0645 \u0634\u0648\u062f.",
"There must be at least one group.": "\u062d\u062f\u0627\u0642\u0644 \u06cc\u06a9 \u06af\u0631\u0648\u0647 \u0628\u0627\u06cc\u062f \u0648\u062c\u0648\u062f \u062f\u0627\u0634\u062a\u0647 \u0628\u0627\u0634\u062f.",
"There must be one cohort to which students can automatically be assigned.": "\u0628\u0627\u06cc\u062f \u06cc\u06a9 \u0647\u0645\u200c\u06af\u0631\u0648\u0647 \u0628\u0627\u0634\u062f \u06a9\u0647 \u0628\u062a\u0648\u0627\u0646 \u0628\u0647\u200c\u0637\u0648\u0631 \u062e\u0648\u062f\u06a9\u0627\u0631 \u06cc\u0627\u062f\u06af\u06cc\u0631\u0646\u062f\u06af\u0627\u0646 \u0631\u0627 \u0628\u0647 \u0622\u0646 \u0627\u062e\u062a\u0635\u0627\u0635 \u062f\u0647\u0646\u062f",
"There was a problem creating the report. Select \"Create Executive Summary\" to try again.": "\u0645\u0634\u06a9\u0644\u06cc \u062f\u0631 \u06af\u0632\u0627\u0631\u0634\u200c\u06af\u06cc\u0631\u06cc \u0648\u062c\u0648\u062f \u062f\u0627\u0634\u062a. \u0628\u0631\u0627\u06cc \u0633\u0627\u062e\u062a \u062f\u0648\u0628\u0627\u0631\u0647 \"\u062e\u0644\u0627\u0635\u06c0 \u0627\u062c\u0631\u0627\u06cc\u06cc \u0633\u0627\u062e\u062a\" \u0631\u0627 \u0627\u0646\u062a\u062e\u0627\u0628 \u06a9\u0646\u06cc\u062f.",
@@ -2054,7 +2061,6 @@
"This learner will be removed from the team,allowing another learner to take the available spot.": "\u0627\u06cc\u0646 \u0641\u0631\u062f \u0627\u0632 \u062a\u06cc\u0645 \u062d\u0630\u0641 \u062e\u0648\u0627\u0647\u062f \u0634\u062f \u0648 \u062f\u06cc\u06af\u0631\u06cc \u0627\u062c\u0627\u0632\u0647 \u0645\u06cc\u200c\u06cc\u0627\u0628\u062f \u062a\u0627 \u062c\u0627\u06cc \u0627\u0648 \u0631\u0627 \u0628\u06af\u06cc\u0631\u062f.",
"This link will open in a modal window": "\u0627\u06cc\u0646 \u067e\u06cc\u0648\u0646\u062f \u062f\u0631 \u06cc\u06a9 \u067e\u0646\u062c\u0631\u0647 \u0645\u0648\u062f\u0627\u0644 \u0628\u0627\u0632 \u062e\u0648\u0627\u0647\u062f \u0634\u062f",
"This link will open in a new browser window/tab": "\u0627\u06cc\u0646 \u067e\u06cc\u0648\u0646\u062f \u062f\u0631 \u06cc\u06a9 \u067e\u0646\u062c\u0631\u0647/ \u0632\u0628\u0627\u0646\u0647 \u0645\u0631\u0648\u0631\u06af\u0631 \u062c\u062f\u06cc\u062f \u0628\u0627\u0632 \u062e\u0648\u0627\u0647\u062f \u0634\u062f",
- "This may be happening because of an error with our server or your internet connection. Try refreshing the page or making sure you are online.": "\u0639\u0627\u0645\u0644 \u0627\u06cc\u0646 \u0627\u062a\u0641\u0627\u0642 \u0645\u0645\u06a9\u0646 \u0627\u0633\u062a \u0633\u0631\u0648\u0631 \u0645\u0627 \u06cc\u0627 \u0627\u062a\u0635\u0627\u0644 \u0634\u0645\u0627 \u0628\u0647 \u0627\u06cc\u0646\u062a\u0631\u0646\u062a \u0628\u0627\u0634\u062f. \u0628\u0627\u0631 \u062f\u06cc\u06af\u0631 \u0635\u0641\u062d\u0647 \u0631\u0627 \u0628\u0627\u0632 \u06a9\u0646\u06cc\u062f \u0648 \u06cc\u0627 \u0627\u0632 \u0627\u062a\u0635\u0627\u0644 \u0628\u0647 \u0627\u06cc\u0646\u062a\u0631\u0646\u062a \u0627\u0637\u0645\u06cc\u0646\u0627\u0646 \u062d\u0627\u0635\u0644 \u0646\u0645\u0627\u06cc\u06cc\u062f.",
"This page contains information about orders that you have placed with {platform_name}.": "\u0627\u06cc\u0646 \u0635\u0641\u062d\u0647 \u062d\u0627\u0648\u06cc \u0627\u0637\u0644\u0627\u0639\u0627\u062a\u06cc \u062f\u0631\u0628\u0627\u0631\u06c0 \u0633\u0641\u0627\u0631\u0634\u0627\u062a\u06cc \u0627\u0633\u062a \u06a9\u0647 \u0634\u0645\u0627 \u0628\u0627 {platform_name} \u062b\u0628\u062a \u06a9\u0631\u062f\u0647\u200c\u0627\u06cc\u062f.",
"This post could not be closed. Refresh the page and try again.": "\u0627\u06cc\u0646 \u0645\u0637\u0644\u0628 \u0627\u0631\u0633\u0627\u0644\u06cc \u0631\u0627 \u0646\u0645\u06cc\u200c\u062a\u0648\u0627\u0646 \u0628\u0633\u062a. \u0635\u0641\u062d\u0647 \u0631\u0627 \u062f\u0648\u0628\u0627\u0631\u0647 \u0628\u0627\u0631\u06af\u06cc\u0631\u06cc \u06a9\u0631\u062f\u0647 \u0648 \u0645\u062c\u062f\u062f \u062a\u0644\u0627\u0634 \u06a9\u0646\u06cc\u062f.",
"This post could not be flagged for abuse. Refresh the page and try again.": "\u0627\u06cc\u0646 \u0645\u0637\u0644\u0628 \u0627\u0631\u0633\u0627\u0644\u06cc \u0631\u0627 \u0646\u0645\u06cc\u200c\u062a\u0648\u0627\u0646 \u0628\u0647 \u062f\u0644\u06cc\u0644 \u0633\u0648\u0621\u0627\u0633\u062a\u0641\u0627\u062f\u0647 \u067e\u0631\u0686\u0645\u200c\u0622\u0630\u06cc\u0646 \u06a9\u0631\u062f. \u0635\u0641\u062d\u0647 \u0631\u0627 \u0631\u0648\u0632\u0622\u0645\u062f \u06a9\u0631\u062f\u0647 \u0648 \u062f\u0648\u0628\u0627\u0631\u0647 \u062a\u0644\u0627\u0634 \u06a9\u0646\u06cc\u062f.",
@@ -2159,7 +2165,6 @@
"Unable to load": "\u0642\u0627\u062f\u0631 \u0628\u0647 \u0628\u0627\u0631\u06af\u0630\u0627\u0631\u06cc \u0646\u06cc\u0633\u062a.",
"Unable to submit application": "\u0627\u0631\u0633\u0627\u0644 \u0628\u0631\u0646\u0627\u0645\u0647 \u0627\u0645\u06a9\u0627\u0646\u200c\u067e\u0630\u06cc\u0631 \u0646\u06cc\u0633\u062a",
"Unable to submit request to generate report.": "\u0627\u0631\u0633\u0627\u0644 \u062f\u0631\u062e\u0648\u0627\u0633\u062a \u0628\u0631\u0627\u06cc \u06af\u0632\u0627\u0631\u0634\u200c\u06af\u06cc\u0631\u06cc \u0627\u0645\u06a9\u0627\u0646\u200c\u067e\u0630\u06cc\u0631 \u0646\u06cc\u0633\u062a.",
- "Unable to update settings": "\u062a\u0646\u0638\u06cc\u0645\u0627\u062a \u0631\u0648\u0632\u0622\u0645\u062f \u0646\u0634\u062f",
"Underline": "\u062e\u0637 \u0632\u06cc\u0631",
"Undo": "\u0648\u0627\u06af\u0631\u062f",
"Undo (Ctrl+Z)": "\u0648\u0627\u06af\u0631\u062f (Ctrl+Z)",
diff --git a/cms/static/js/i18n/fa/djangojs.js b/cms/static/js/i18n/fa/djangojs.js
index a6fdba8dbe1c..ef7a945126da 100644
--- a/cms/static/js/i18n/fa/djangojs.js
+++ b/cms/static/js/i18n/fa/djangojs.js
@@ -467,6 +467,7 @@
"Cannot delete when in use by a unit": "\u0646\u0645\u06cc\u200c\u062a\u0648\u0627\u0646\u06cc\u062f \u0647\u0646\u06af\u0627\u0645 \u0627\u0633\u062a\u0641\u0627\u062f\u0647 \u062a\u0648\u0633\u0637 \u06cc\u06a9 \u0648\u0627\u062d\u062f\u060c \u0622\u0646 \u0631\u0627 \u062d\u0630\u0641 \u06a9\u0646\u06cc\u062f",
"Cannot delete when in use by an experiment": "\u0647\u0646\u06af\u0627\u0645\u06cc \u06a9\u0647 \u0627\u0632 \u0622\u0646 \u062f\u0631 \u062a\u062c\u0631\u0628\u0647\u200c\u0627\u06cc \u0627\u0633\u062a\u0641\u0627\u062f\u0647 \u0645\u06cc\u200c\u0634\u0648\u062f \u0627\u0645\u06a9\u0627\u0646 \u062d\u0630\u0641 \u0622\u0646 \u0646\u06cc\u0633\u062a",
"Cannot join instructor managed team": "\u0646\u0645\u06cc\u200c\u062a\u0648\u0627\u0646\u06cc\u062f \u0628\u0647 \u062a\u06cc\u0645\u06cc \u06a9\u0647 \u062a\u0648\u0633\u0637 \u0645\u0631\u0628\u06cc \u0645\u062f\u06cc\u0631\u06cc\u062a \u0645\u06cc\u200c\u0634\u0648\u062f \u0628\u067e\u06cc\u0648\u0646\u062f\u06cc\u062f",
+ "Cannot submit empty response even everything is optional.": "\u0646\u0645\u06cc \u062a\u0648\u0627\u0646 \u067e\u0627\u0633\u062e \u062e\u0627\u0644\u06cc \u0627\u0631\u0633\u0627\u0644 \u06a9\u0631\u062f \u062d\u062a\u06cc \u0647\u0645\u0647 \u0686\u06cc\u0632 \u0627\u062e\u062a\u06cc\u0627\u0631\u06cc \u0627\u0633\u062a.",
"Cannot update attempt review status": "\u0627\u0645\u06a9\u0627\u0646 \u0631\u0648\u0632\u0622\u0645\u062f\u0633\u0627\u0632\u06cc \u0648\u0636\u0639\u06cc\u062a \u062a\u0644\u0627\u0634 \u0628\u0631\u0631\u0633\u06cc \u0646\u06cc\u0633\u062a",
"Caption": " \u062a\u0648\u0636\u06cc\u062d",
"Caution: The last published version of this unit is live. By publishing changes you will change the student experience.": "\u0627\u062d\u062a\u06cc\u0627\u0637: \u0622\u062e\u0631\u06cc\u0646 \u0646\u0633\u062e\u06c0 \u0645\u0646\u062a\u0634\u0631\u0634\u062f\u06c0 \u0627\u06cc\u0646 \u0648\u0627\u062d\u062f \u067e\u062e\u0634 \u0632\u0646\u062f\u0647 \u0627\u0633\u062a. \u0628\u0627 \u0627\u0646\u062a\u0634\u0627\u0631 \u062a\u063a\u06cc\u06cc\u0631\u0627\u062a\u060c \u062a\u062c\u0631\u0628\u06c0 \u06cc\u0627\u062f\u06af\u06cc\u0631\u0646\u062f\u0647 \u0631\u0627 \u062a\u063a\u06cc\u06cc\u0631 \u062e\u0648\u0627\u0647\u06cc\u062f \u062f\u0627\u062f.",
@@ -757,6 +758,7 @@
"Draft (Never published)": "\u067e\u06cc\u0634\u200c\u0646\u0648\u06cc\u0633 (\u0647\u0631\u06af\u0632 \u0645\u0646\u062a\u0634\u0631\u0646\u0634\u062f\u0647)",
"Draft (Unpublished changes)": "\u067e\u06cc\u0634\u200c\u0646\u0648\u06cc\u0633 (\u062a\u063a\u06cc\u06cc\u0631\u0627\u062a \u0645\u0646\u062a\u0634\u0631\u0646\u0634\u062f\u0647)",
"Draft saved on {lastSavedStart}{editedOn}{lastSavedEnd} by {editedByStart}{editedBy}{editedByEnd}": "\u067e\u06cc\u0634\u200c\u0646\u0648\u06cc\u0633 \u0630\u062e\u06cc\u0631\u0647 \u0634\u062f\u0647 \u0627\u0633\u062a \u062f\u0631 {lastSavedStart}{editedOn}{lastSavedEnd} \u0628\u0647\u200c\u062f\u0633\u062a {editedByStart}{editedBy}{editedByEnd}",
+ "Draft saved!": "\u067e\u06cc\u0634 \u0646\u0648\u06cc\u0633 \u0630\u062e\u06cc\u0631\u0647 \u0634\u062f!",
"Drag and drop or {spanStart}browse your computer{spanEnd}.": "\u0628\u06a9\u0634 \u0648 \u0631\u0647\u0627\u06a9\u0646 \u06cc\u0627 {spanStart} \u0631\u0627\u06cc\u0627\u0646\u0647\u200c\u0627\u062a \u0631\u0627 \u0628\u0631\u0631\u0633\u06cc \u06a9\u0646 {spanEnd}.",
"Drag to reorder": "\u06a9\u0634\u06cc\u062f\u0646 \u0628\u0631\u0627\u06cc \u062a\u0631\u062a\u06cc\u0628 \u0645\u062c\u062f\u062f",
"Drop target image": "\u062a\u0635\u0648\u06cc\u0631 \u0647\u062f\u0641 \u0631\u0627 \u0631\u0647\u0627 \u06a9\u0646\u06cc\u062f",
@@ -1212,7 +1214,6 @@
"Loading more threads": "\u062f\u0631 \u062d\u0627\u0644 \u0628\u0627\u0631\u06af\u06cc\u0631\u06cc \u0645\u0648\u0636\u0648\u0639\u0627\u062a \u0628\u06cc\u0634\u062a\u0631",
"Loading posts list": "\u062f\u0631 \u062d\u0627\u0644 \u0628\u0627\u0631\u06af\u06cc\u0631\u06cc \u0641\u0647\u0631\u0633\u062a \u0645\u0637\u0627\u0644\u0628 \u0627\u0631\u0633\u0627\u0644\u06cc",
"Loading your courses": "\u062f\u0631 \u062d\u0627\u0644 \u0628\u0627\u0631\u06af\u06cc\u0631\u06cc \u062f\u0648\u0631\u0647\u200c\u0647\u0627\u06cc \u0634\u0645\u0627",
- "Loading...": "\u062f\u0631 \u062d\u0627\u0644 \u0628\u0627\u0631\u06af\u06cc\u0631\u06cc ...",
"Location": "\u0645\u06a9\u0627\u0646",
"Location in Course": "\u0645\u06a9\u0627\u0646 \u062f\u0631 \u062f\u0648\u0631\u0647 \u0622\u0645\u0648\u0632\u0634\u06cc",
"Lock this asset": "\u0642\u0641\u0644 \u0627\u06cc\u0646 \u0645\u0646\u0628\u0639",
@@ -1293,7 +1294,6 @@
"New Password": "\u06af\u0630\u0631\u0648\u0627\u0698\u06c0 \u062c\u062f\u06cc\u062f",
"New document": "\u0633\u0646\u062f \u062c\u062f\u06cc\u062f",
"New enrollment mode:": "\u0648\u0636\u0639\u06cc\u062a \u062a\u0627\u0632\u0647 \u062b\u0628\u062a\u200c\u0646\u0627\u0645:",
- "New files were added to this course's Files & Uploads": "\u0641\u0627\u06cc\u0644 \u0647\u0627\u06cc \u062c\u062f\u06cc\u062f \u0628\u0647 \"\u0641\u0627\u06cc\u0644 \u0647\u0627 \u0648 \u0622\u067e\u0644\u0648\u062f\u0647\u0627\"\u06cc \u0627\u06cc\u0646 \u062f\u0648\u0631\u0647 \u0627\u0636\u0627\u0641\u0647 \u0634\u062f",
"New window": "\u067e\u0646\u062c\u0631\u06c0 \u062c\u062f\u06cc\u062f",
"New {component_type}": "{component_type} \u062c\u062f\u06cc\u062f",
"Next": "\u0628\u0639\u062f\u06cc",
@@ -1309,6 +1309,7 @@
"No content-specific discussion topics exist.": "\u0647\u06cc\u0686 \u0645\u0628\u062d\u062b\u06cc \u0645\u0631\u0628\u0648\u0637 \u0628\u0647 \u0645\u062d\u062a\u0648\u0627\u06cc \u062e\u0627\u0635 \u0648\u062c\u0648\u062f \u0646\u062f\u0627\u0631\u062f.",
"No description available": "\u0628\u062f\u0648\u0646 \u0634\u0631\u062d",
"No exams in course {course_id}.": "\u0647\u06cc\u0686 \u0622\u0632\u0645\u0648\u0646\u06cc \u062f\u0631 \u062f\u0648\u0631\u0647 \u0622\u0645\u0648\u0632\u0634\u06cc {course_id} \u0648\u062c\u0648\u062f \u0646\u062f\u0627\u0631\u062f.",
+ "No files selected for upload.": "\u0647\u06cc\u0686 \u0641\u0627\u06cc\u0644\u06cc \u0628\u0631\u0627\u06cc \u0622\u067e\u0644\u0648\u062f \u0627\u0646\u062a\u062e\u0627\u0628 \u0646\u0634\u062f\u0647 \u0627\u0633\u062a.",
"No instructor dashboard for {proctor_service}": "\u0628\u062f\u0648\u0646 \u067e\u06cc\u0634\u062e\u0648\u0627\u0646 \u0622\u0645\u0648\u0632\u0634\u06cc \u0628\u0631\u0627\u06cc {proctor_service}",
"No onboarding status API for {proctor_service}": "API \u0648\u0636\u0639\u06cc\u062a \u0648\u0631\u0648\u062f \u0628\u0631\u0627\u06cc {proctor_service} \u0648\u062c\u0648\u062f \u0646\u062f\u0627\u0631\u062f",
"No posts matched your query.": "\u0647\u06cc\u0686 \u0645\u0637\u0644\u0628 \u0627\u0631\u0633\u0627\u0644\u06cc \u0628\u0627 \u062c\u0633\u062a\u062c\u0648\u06cc \u0634\u0645\u0627 \u0645\u0646\u0637\u0628\u0642 \u0646\u0628\u0648\u062f.",
@@ -1449,6 +1450,7 @@
"Please add the instructor's title": "\u0644\u0637\u0641\u0627\u064b \u0639\u0646\u0648\u0627\u0646 \u0645\u0631\u0628\u06cc \u0631\u0627 \u0628\u06cc\u0641\u0632\u0627\u06cc\u06cc\u062f",
"Please address the errors on this page first, and then save your progress.": "\u0644\u0637\u0641\u0627 \u0627\u0628\u062a\u062f\u0627 \u062e\u0637\u0627\u0647\u0627\u06cc \u0627\u06cc\u0646 \u0635\u0641\u062d\u0647 \u0631\u0627 \u0628\u0631\u0631\u0633\u06cc \u0648 \u0631\u0641\u0639 \u06a9\u0631\u062f\u0647 \u0633\u067e\u0633 \u0645\u06cc\u0632\u0627\u0646 \u067e\u06cc\u0634\u0631\u0641\u062a \u062e\u0648\u062f \u0631\u0627 \u0630\u062e\u06cc\u0631\u0647 \u06a9\u0646\u06cc\u062f. ",
"Please check the following validation feedbacks and reflect them in your course settings:": "\u0644\u0637\u0641\u0627\u064b \u0628\u0627\u0632\u062e\u0648\u0631\u062f\u0647\u0627\u06cc \u062a\u0623\u06cc\u06cc\u062f \u0627\u0639\u062a\u0628\u0627\u0631 \u0632\u06cc\u0631 \u0631\u0627 \u06a9\u0646\u062a\u0631\u0644 \u06a9\u0631\u062f\u0647 \u0648 \u0622\u0646\u200c\u0647\u0627 \u0631\u0627 \u062f\u0631 \u062a\u0646\u0638\u06cc\u0645\u0627\u062a \u062f\u0648\u0631\u06c0 \u0622\u0645\u0648\u0632\u0634\u06cc \u062e\u0648\u062f \u0645\u0646\u0639\u06a9\u0633 \u06a9\u0646\u06cc\u062f:",
+ "Please check your internet connection.": "\u0644\u0637\u0641\u0627 \u0627\u062a\u0635\u0627\u0644 \u0627\u06cc\u0646\u062a\u0631\u0646\u062a \u062e\u0648\u062f \u0631\u0627 \u0628\u0631\u0631\u0633\u06cc \u06a9\u0646\u06cc\u062f.",
"Please describe this image or agree that it has no contextual value by checking the checkbox.": "\u0644\u0637\u0641\u0627\u064b \u0627\u06cc\u0646 \u062a\u0635\u0648\u06cc\u0631 \u0631\u0627 \u062a\u0648\u0635\u06cc\u0641 \u06a9\u0646\u06cc\u062f \u06cc\u0627 \u0628\u0627 \u0632\u062f\u0646 \u0639\u0644\u0627\u0645\u062a \u062f\u0631 \u062e\u0627\u0646\u0647 \u06a9\u0646\u062a\u0631\u0644 \u0645\u0648\u0627\u0641\u0642\u062a \u06a9\u0646\u06cc\u062f \u06a9\u0647 \u0647\u06cc\u0686 \u0627\u0631\u0632\u0634 \u0645\u062a\u0646\u06cc \u0646\u062f\u0627\u0631\u062f. ",
"Please do not use any spaces in this field.": "\u0644\u0637\u0641\u0627 \u0627\u0632 \u0641\u0627\u0635\u0644\u0647 \u062f\u0631 \u0627\u06cc\u0646 \u0642\u0633\u0645\u062a \u0627\u0633\u062a\u0641\u0627\u062f\u0647 \u0646\u06a9\u0646\u06cc\u062f.",
"Please do not use any spaces or special characters in this field.": "\u0644\u0637\u0641\u0627 \u0627\u0632 \u0641\u0627\u0635\u0644\u0647 \u06cc\u0627 \u0646\u0648\u06cc\u0633\u0647\u200c\u0647\u0627\u06cc \u062e\u0627\u0635 \u062f\u0631 \u0627\u06cc\u0646 \u0642\u0633\u0645\u062a \u0627\u0633\u062a\u0641\u0627\u062f\u0647 \u0646\u06a9\u0646\u06cc\u062f.",
@@ -1469,12 +1471,15 @@
"Please fix the following errors:": "\u0644\u0637\u0641\u0627\u064b \u062e\u0637\u0627\u0647\u0627\u06cc \u0632\u06cc\u0631 \u0631\u0627 \u0627\u0635\u0644\u0627\u062d \u06a9\u0646\u06cc\u062f:",
"Please follow the instructions here to upload a file elsewhere and link to it: {maxFileSizeRedirectUrl}": "\u0644\u0637\u0641\u0627 \u0631\u0627\u0647\u0646\u0645\u0627\u06cc \u0632\u06cc\u0631 \u0631\u0627 \u0628\u0631\u0627\u06cc \u0686\u06af\u0648\u0646\u06af\u06cc \u0628\u0627\u0631\u06af\u0630\u0627\u0631\u06cc \u06cc\u06a9 \u0641\u0627\u06cc\u0644 \u062f\u0631 \u062c\u0627\u06cc\u06cc \u062f\u06cc\u06af\u0631 \u0648 \u06cc\u06a9 \u0627\u0631\u062a\u0628\u0627\u0637 \u0628\u0647 \u0622\u0646 \u0627\u06cc\u062c\u0627\u062f \u06a9\u0646\u06cc\u062f : {maxFileSizeRedirectUrl}",
"Please note: Deletion of your account and personal data is permanent and cannot be undone. {platformName} will not be able to recover your account or the data that is deleted.": "\u0644\u0637\u0641\u0627\u064b \u062a\u0648\u062c\u0647 \u062f\u0627\u0634\u062a\u0647 \u0628\u0627\u0634\u06cc\u062f: \u062d\u0633\u0627\u0628 \u06a9\u0627\u0631\u0628\u0631\u06cc \u0648 \u062f\u0627\u062f\u0647\u200c\u0647\u0627\u06cc \u0634\u062e\u0635\u06cc \u0634\u0645\u0627 \u0628\u0631\u0627\u06cc \u0647\u0645\u06cc\u0634\u0647 \u062d\u0630\u0641 \u062e\u0648\u0627\u0647\u062f \u0634\u062f \u0648 \u0642\u0627\u0628\u0644 \u0648\u0627\u06af\u0631\u062f \u0646\u06cc\u0633\u062a. \u067e\u0633 {platformName} \u0646\u0645\u06cc\u200c\u062a\u0648\u0627\u0646\u062f \u062d\u0633\u0627\u0628 \u06a9\u0627\u0631\u0628\u0631\u06cc \u0634\u0645\u0627 \u06cc\u0627 \u062f\u0627\u062f\u0647\u200c\u0647\u0627\u06cc \u062d\u0630\u0641\u200c\u0634\u062f\u0647 \u0631\u0627 \u0628\u0627\u0632\u06cc\u0627\u0628\u06cc \u06a9\u0646\u062f.",
+ "Please provide a description for each file you are uploading.": "\u0644\u0637\u0641\u0627\u064b \u062a\u0648\u0636\u06cc\u062d\u06cc \u0628\u0631\u0627\u06cc \u0647\u0631 \u0641\u0627\u06cc\u0644\u06cc \u06a9\u0647 \u0622\u067e\u0644\u0648\u062f \u0645\u06cc \u06a9\u0646\u06cc\u062f \u0627\u0631\u0627\u0626\u0647 \u062f\u0647\u06cc\u062f.",
"Please provide a description of the link destination.": "\u0644\u0637\u0641\u0627\u064b \u062a\u0648\u0636\u06cc\u062d\u06cc \u062f\u0631\u0628\u0627\u0631\u06c0 \u0645\u0642\u0635\u062f \u067e\u06cc\u0648\u0646\u062f \u0627\u0631\u0627\u0626\u0647 \u062f\u0647\u06cc\u062f.",
+ "Please provide a response.": "\u0644\u0637\u0641\u0627 \u067e\u0627\u0633\u062e \u062f\u0647\u06cc\u062f.",
"Please provide a valid URL.": "\u06cc\u06a9 \u0646\u0634\u0627\u0646\u06cc \u0627\u06cc\u0646\u062a\u0631\u0646\u062a\u06cc \u0645\u0639\u062a\u0628\u0631 \u0648\u0627\u0631\u062f \u06a9\u0646\u06cc\u062f.",
"Please re-enter your password.": "\u0644\u0637\u0641\u0627\u064b \u06af\u0630\u0631\u0648\u0627\u0698\u0647 \u0631\u0627 \u062f\u0648\u0628\u0627\u0631\u0647 \u0648\u0627\u0631\u062f \u06a9\u0646\u06cc\u062f.",
"Please select a PDF file to upload.": "\u0644\u0637\u0641\u0627 \u06cc\u06a9 \u067e\u0631\u0648\u0646\u062f\u0647 PDF \u0628\u0631\u0627\u06cc \u0628\u0627\u0631\u06af\u0630\u0627\u0631\u06cc \u0627\u0646\u062a\u062e\u0627\u0628 \u06a9\u0646\u06cc\u062f",
"Please select a file in .srt format.": "\u0644\u0637\u0641\u0627 \u06cc\u06a9 \u067e\u0631\u0648\u0646\u062f\u0647 \u0628\u0627 \u0642\u0627\u0644\u0628 srt. \u0628\u0631\u0627\u06cc \u0628\u0627\u0631\u06af\u0630\u0627\u0631\u06cc \u0627\u0646\u062a\u062e\u0627\u0628 \u06a9\u0646\u06cc\u062f.",
"Please specify a reason.": "\u0644\u0637\u0641\u0627\u064b \u06cc\u06a9 \u062f\u0644\u06cc\u0644 \u0630\u06a9\u0631 \u06a9\u0646\u06cc\u062f.",
+ "Please upload a file.": "\u0644\u0637\u0641\u0627 \u06cc\u06a9 \u0641\u0627\u06cc\u0644 \u0622\u067e\u0644\u0648\u062f \u06a9\u0646\u06cc\u062f",
"Please verify that you have uploaded a valid image (PNG and JPEG).": "\u0644\u0637\u0641\u0627\u064b \u062a\u0623\u06cc\u06cc\u062f \u06a9\u0646\u06cc\u062f \u06a9\u0647 \u062a\u0635\u0648\u06cc\u0631\u06cc \u0645\u0639\u062a\u0628\u0631 (PNG \u0648 JPEG) \u0628\u0627\u0631\u06af\u0630\u0627\u0631\u06cc \u06a9\u0631\u062f\u0647\u200c\u0627\u06cc\u062f.",
"Please verify that your webcam is connected and that you have allowed your browser to access it.": "\u0644\u0637\u0641\u0627\u064b \u0628\u0631\u0631\u0633\u06cc \u06a9\u0646\u06cc\u062f \u06a9\u0647 \u062f\u0648\u0631\u0628\u06cc\u0646 \u0631\u0627\u06cc\u0627\u0646\u06c0 \u0634\u0645\u0627 \u0645\u062a\u0635\u0644 \u0627\u0633\u062a \u0648 \u0628\u0647 \u0645\u0631\u0648\u0631\u06af\u0631 \u062e\u0648\u062f \u0627\u062c\u0627\u0632\u06c0 \u062f\u0633\u062a\u0631\u0633\u06cc \u0628\u0647 \u0622\u0646 \u0631\u0627 \u062f\u0627\u062f\u0647\u200c\u0627\u06cc\u062f.",
"Please wait": "\u0644\u0637\u0641\u0627 \u0634\u06a9\u06cc\u0628\u0627 \u0628\u0627\u0634\u06cc\u062f",
@@ -1650,6 +1655,8 @@
"Save changes": "\u0630\u062e\u06cc\u0631\u0647 \u062a\u063a\u06cc\u06cc\u0631\u0627\u062a",
"Saved cohort": "\u062f\u0633\u062a\u0647 \u0630\u062e\u06cc\u0631\u0647 \u0634\u062f\u0647 ",
"Saving": "\u062f\u0631 \u062d\u0627\u0644 \u0630\u062e\u06cc\u0631\u0647\u200c\u0633\u0627\u0632\u06cc",
+ "Saving draft": "\u0630\u062e\u06cc\u0631\u0647 \u067e\u06cc\u0634 \u0646\u0648\u06cc\u0633",
+ "Saving draft...": "\u062f\u0631 \u062d\u0627\u0644 \u0630\u062e\u06cc\u0631\u0647 \u067e\u06cc\u0634 \u0646\u0648\u06cc\u0633...",
"Saving your email preference": "\u062f\u0631 \u062d\u0627\u0644 \u0630\u062e\u06cc\u0631\u06c0 \u0631\u0627\u06cc\u0627\u0646\u0627\u0645\u0647 \u0645\u0631\u062c\u062d",
"Scheduled:": "\u0628\u0631\u0646\u0627\u0645\u0647\u200c\u0631\u06cc\u0632\u06cc\u200c\u0634\u062f\u0647:",
"Scope": "\u062f\u0627\u0645\u0646\u0647",
@@ -1691,7 +1698,6 @@
"Select the course-wide discussion topics that you want to divide.": "\u0645\u0628\u0627\u062d\u062b \u06af\u0641\u062a\u06af\u0648\u06cc \u0637\u0648\u0644 \u062f\u0648\u0631\u0647 \u0622\u0645\u0648\u0632\u0634\u06cc \u0631\u0627 \u0627\u0646\u062a\u062e\u0627\u0628 \u06a9\u0646\u06cc\u062f \u06a9\u0647 \u0645\u06cc\u200c\u062e\u0648\u0627\u0647\u06cc\u062f \u062a\u0642\u0633\u06cc\u0645 \u06a9\u0646\u06cc\u062f.",
"Select the time zone for displaying course dates. If you do not specify a time zone, course dates, including assignment deadlines, will be displayed in your browser's local time zone.": "\u0645\u0646\u0637\u0642\u06c0 \u0632\u0645\u0627\u0646\u06cc \u0631\u0627 \u0628\u0631\u0627\u06cc \u0646\u0645\u0627\u06cc\u0634 \u062a\u0627\u0631\u06cc\u062e \u062f\u0648\u0631\u0647 \u0622\u0645\u0648\u0632\u0634\u06cc \u0627\u0646\u062a\u062e\u0627\u0628 \u06a9\u0646\u06cc\u062f. \u0627\u06af\u0631 \u0645\u0646\u0637\u0642\u06c0 \u0632\u0645\u0627\u0646\u06cc \u0631\u0627 \u0645\u0634\u062e\u0635 \u0646\u06a9\u0646\u06cc\u062f\u060c \u062a\u0627\u0631\u06cc\u062e \u062f\u0648\u0631\u0647\u200c\u0647\u0627\u060c \u0645\u0627\u0646\u0646\u062f \u0645\u0647\u0644\u062a \u0627\u0646\u062c\u0627\u0645 \u062a\u06a9\u0644\u06cc\u0641\u060c \u062f\u0631 \u0645\u0646\u0637\u0642\u06c0 \u0632\u0645\u0627\u0646\u06cc \u0645\u062d\u0644\u06cc \u0645\u0631\u0648\u0631\u06af\u0631 \u0634\u0645\u0627 \u0646\u0645\u0627\u06cc\u0634 \u062f\u0627\u062f\u0647 \u0645\u06cc\u200c\u0634\u0648\u062f.",
"Select turnaround": "\u0627\u0646\u062a\u062e\u0627\u0628 \u0686\u0631\u062e\u0634",
- "Selected blocks": "\u0628\u0644\u0648\u06a9\u200c\u0647\u0627\u06cc \u0645\u0646\u062a\u062e\u0628",
"Selected tab": "\u0632\u0628\u0627\u0646\u06c0 \u0628\u0631\u06af\u0632\u06cc\u062f\u0647",
"Self": "\u062e\u0648\u062f",
"Send to:": "\u0627\u0631\u0633\u0627\u0644 \u0628\u0647:",
@@ -1990,6 +1996,7 @@
"There is no email history for this course.": "\u0627\u06cc\u0646 \u062f\u0648\u0631\u0647 \u0622\u0645\u0648\u0632\u0634\u06cc\u060c \u0633\u0627\u0628\u0642\u0647 \u0627\u0631\u0633\u0627\u0644 \u0631\u0627\u06cc\u0627\u0646\u0627\u0645\u0647 \u0646\u062f\u0627\u0631\u062f.",
"There is no onboarding exam accessible to this user.": "\u0647\u06cc\u0686 \u0622\u0632\u0645\u0648\u0646 \u0622\u0632\u0645\u0627\u06cc\u0634\u06cc \u0628\u0631\u0627\u06cc \u0627\u06cc\u0646 \u06a9\u0627\u0631\u0628\u0631 \u0648\u062c\u0648\u062f \u0646\u062f\u0627\u0631\u062f.",
"There is no onboarding exam related to this course id.": "\u0647\u06cc\u0686 \u0622\u0632\u0645\u0648\u0646 \u0648\u0631\u0648\u062f\u06cc \u0645\u0631\u0628\u0648\u0637 \u0628\u0647 \u0627\u06cc\u0646 \u0634\u0646\u0627\u0633\u0647 \u062f\u0648\u0631\u0647 \u0622\u0645\u0648\u0632\u0634\u06cc \u0648\u062c\u0648\u062f \u0646\u062f\u0627\u0631\u062f.",
+ "There is still file upload in progress. Please wait until it is finished.": "\u0647\u0646\u0648\u0632 \u0622\u067e\u0644\u0648\u062f \u0641\u0627\u06cc\u0644 \u062f\u0631 \u062d\u0627\u0644 \u0627\u0646\u062c\u0627\u0645 \u0627\u0633\u062a. \u0644\u0637\u0641\u0627 \u0635\u0628\u0631 \u06a9\u0646\u06cc\u062f \u062a\u0627 \u062a\u0645\u0627\u0645 \u0634\u0648\u062f.",
"There must be at least one group.": "\u062d\u062f\u0627\u0642\u0644 \u06cc\u06a9 \u06af\u0631\u0648\u0647 \u0628\u0627\u06cc\u062f \u0648\u062c\u0648\u062f \u062f\u0627\u0634\u062a\u0647 \u0628\u0627\u0634\u062f.",
"There must be one cohort to which students can automatically be assigned.": "\u0628\u0627\u06cc\u062f \u06cc\u06a9 \u0647\u0645\u200c\u06af\u0631\u0648\u0647 \u0628\u0627\u0634\u062f \u06a9\u0647 \u0628\u062a\u0648\u0627\u0646 \u0628\u0647\u200c\u0637\u0648\u0631 \u062e\u0648\u062f\u06a9\u0627\u0631 \u06cc\u0627\u062f\u06af\u06cc\u0631\u0646\u062f\u06af\u0627\u0646 \u0631\u0627 \u0628\u0647 \u0622\u0646 \u0627\u062e\u062a\u0635\u0627\u0635 \u062f\u0647\u0646\u062f",
"There was a problem creating the report. Select \"Create Executive Summary\" to try again.": "\u0645\u0634\u06a9\u0644\u06cc \u062f\u0631 \u06af\u0632\u0627\u0631\u0634\u200c\u06af\u06cc\u0631\u06cc \u0648\u062c\u0648\u062f \u062f\u0627\u0634\u062a. \u0628\u0631\u0627\u06cc \u0633\u0627\u062e\u062a \u062f\u0648\u0628\u0627\u0631\u0647 \"\u062e\u0644\u0627\u0635\u06c0 \u0627\u062c\u0631\u0627\u06cc\u06cc \u0633\u0627\u062e\u062a\" \u0631\u0627 \u0627\u0646\u062a\u062e\u0627\u0628 \u06a9\u0646\u06cc\u062f.",
@@ -2054,7 +2061,6 @@
"This learner will be removed from the team,allowing another learner to take the available spot.": "\u0627\u06cc\u0646 \u0641\u0631\u062f \u0627\u0632 \u062a\u06cc\u0645 \u062d\u0630\u0641 \u062e\u0648\u0627\u0647\u062f \u0634\u062f \u0648 \u062f\u06cc\u06af\u0631\u06cc \u0627\u062c\u0627\u0632\u0647 \u0645\u06cc\u200c\u06cc\u0627\u0628\u062f \u062a\u0627 \u062c\u0627\u06cc \u0627\u0648 \u0631\u0627 \u0628\u06af\u06cc\u0631\u062f.",
"This link will open in a modal window": "\u0627\u06cc\u0646 \u067e\u06cc\u0648\u0646\u062f \u062f\u0631 \u06cc\u06a9 \u067e\u0646\u062c\u0631\u0647 \u0645\u0648\u062f\u0627\u0644 \u0628\u0627\u0632 \u062e\u0648\u0627\u0647\u062f \u0634\u062f",
"This link will open in a new browser window/tab": "\u0627\u06cc\u0646 \u067e\u06cc\u0648\u0646\u062f \u062f\u0631 \u06cc\u06a9 \u067e\u0646\u062c\u0631\u0647/ \u0632\u0628\u0627\u0646\u0647 \u0645\u0631\u0648\u0631\u06af\u0631 \u062c\u062f\u06cc\u062f \u0628\u0627\u0632 \u062e\u0648\u0627\u0647\u062f \u0634\u062f",
- "This may be happening because of an error with our server or your internet connection. Try refreshing the page or making sure you are online.": "\u0639\u0627\u0645\u0644 \u0627\u06cc\u0646 \u0627\u062a\u0641\u0627\u0642 \u0645\u0645\u06a9\u0646 \u0627\u0633\u062a \u0633\u0631\u0648\u0631 \u0645\u0627 \u06cc\u0627 \u0627\u062a\u0635\u0627\u0644 \u0634\u0645\u0627 \u0628\u0647 \u0627\u06cc\u0646\u062a\u0631\u0646\u062a \u0628\u0627\u0634\u062f. \u0628\u0627\u0631 \u062f\u06cc\u06af\u0631 \u0635\u0641\u062d\u0647 \u0631\u0627 \u0628\u0627\u0632 \u06a9\u0646\u06cc\u062f \u0648 \u06cc\u0627 \u0627\u0632 \u0627\u062a\u0635\u0627\u0644 \u0628\u0647 \u0627\u06cc\u0646\u062a\u0631\u0646\u062a \u0627\u0637\u0645\u06cc\u0646\u0627\u0646 \u062d\u0627\u0635\u0644 \u0646\u0645\u0627\u06cc\u06cc\u062f.",
"This page contains information about orders that you have placed with {platform_name}.": "\u0627\u06cc\u0646 \u0635\u0641\u062d\u0647 \u062d\u0627\u0648\u06cc \u0627\u0637\u0644\u0627\u0639\u0627\u062a\u06cc \u062f\u0631\u0628\u0627\u0631\u06c0 \u0633\u0641\u0627\u0631\u0634\u0627\u062a\u06cc \u0627\u0633\u062a \u06a9\u0647 \u0634\u0645\u0627 \u0628\u0627 {platform_name} \u062b\u0628\u062a \u06a9\u0631\u062f\u0647\u200c\u0627\u06cc\u062f.",
"This post could not be closed. Refresh the page and try again.": "\u0627\u06cc\u0646 \u0645\u0637\u0644\u0628 \u0627\u0631\u0633\u0627\u0644\u06cc \u0631\u0627 \u0646\u0645\u06cc\u200c\u062a\u0648\u0627\u0646 \u0628\u0633\u062a. \u0635\u0641\u062d\u0647 \u0631\u0627 \u062f\u0648\u0628\u0627\u0631\u0647 \u0628\u0627\u0631\u06af\u06cc\u0631\u06cc \u06a9\u0631\u062f\u0647 \u0648 \u0645\u062c\u062f\u062f \u062a\u0644\u0627\u0634 \u06a9\u0646\u06cc\u062f.",
"This post could not be flagged for abuse. Refresh the page and try again.": "\u0627\u06cc\u0646 \u0645\u0637\u0644\u0628 \u0627\u0631\u0633\u0627\u0644\u06cc \u0631\u0627 \u0646\u0645\u06cc\u200c\u062a\u0648\u0627\u0646 \u0628\u0647 \u062f\u0644\u06cc\u0644 \u0633\u0648\u0621\u0627\u0633\u062a\u0641\u0627\u062f\u0647 \u067e\u0631\u0686\u0645\u200c\u0622\u0630\u06cc\u0646 \u06a9\u0631\u062f. \u0635\u0641\u062d\u0647 \u0631\u0627 \u0631\u0648\u0632\u0622\u0645\u062f \u06a9\u0631\u062f\u0647 \u0648 \u062f\u0648\u0628\u0627\u0631\u0647 \u062a\u0644\u0627\u0634 \u06a9\u0646\u06cc\u062f.",
@@ -2159,7 +2165,6 @@
"Unable to load": "\u0642\u0627\u062f\u0631 \u0628\u0647 \u0628\u0627\u0631\u06af\u0630\u0627\u0631\u06cc \u0646\u06cc\u0633\u062a.",
"Unable to submit application": "\u0627\u0631\u0633\u0627\u0644 \u0628\u0631\u0646\u0627\u0645\u0647 \u0627\u0645\u06a9\u0627\u0646\u200c\u067e\u0630\u06cc\u0631 \u0646\u06cc\u0633\u062a",
"Unable to submit request to generate report.": "\u0627\u0631\u0633\u0627\u0644 \u062f\u0631\u062e\u0648\u0627\u0633\u062a \u0628\u0631\u0627\u06cc \u06af\u0632\u0627\u0631\u0634\u200c\u06af\u06cc\u0631\u06cc \u0627\u0645\u06a9\u0627\u0646\u200c\u067e\u0630\u06cc\u0631 \u0646\u06cc\u0633\u062a.",
- "Unable to update settings": "\u062a\u0646\u0638\u06cc\u0645\u0627\u062a \u0631\u0648\u0632\u0622\u0645\u062f \u0646\u0634\u062f",
"Underline": "\u062e\u0637 \u0632\u06cc\u0631",
"Undo": "\u0648\u0627\u06af\u0631\u062f",
"Undo (Ctrl+Z)": "\u0648\u0627\u06af\u0631\u062f (Ctrl+Z)",
diff --git a/cms/static/js/i18n/fr/djangojs.js b/cms/static/js/i18n/fr/djangojs.js
index ce83d52a883b..07e5c92aa490 100644
--- a/cms/static/js/i18n/fr/djangojs.js
+++ b/cms/static/js/i18n/fr/djangojs.js
@@ -1981,7 +1981,6 @@
"This learner will be removed from the team,allowing another learner to take the available spot.": "Cet apprenant sera retir\u00e9 de l'\u00e9quipe, permettant \u00e0 un autre apprenant de prendre la place vacante.",
"This link will open in a modal window": "Ce lien s'ouvrira dans une nouvelle fen\u00eatre contextuelle",
"This link will open in a new browser window/tab": "Ce lien s'ouvrira dans une nouvelle fen\u00eatre ou onglet de votre navigateur",
- "This may be happening because of an error with our server or your internet connection. Try refreshing the page or making sure you are online.": "Cet incident vous affecte \u00e0 cause d'une erreur sur notre serveur ou d'un probl\u00e8me de votre connexion internet. Essayez de rafra\u00eechir la page ou v\u00e9rifiez que votre connexion est bien active.",
"This page contains information about orders that you have placed with {platform_name}.": "Cette page contient des informations \u00e0 propos des commandes que vous avez pass\u00e9s avec {platform_name}.",
"This post could not be closed. Refresh the page and try again.": "Ce message ne peut \u00eatre ferm\u00e9. Veuillez actualiser la page et essayer \u00e0 nouveau.",
"This post could not be flagged for abuse. Refresh the page and try again.": "Ce message ne peut pas \u00eatre d\u00e9nonc\u00e9 pour abus. Veuillez actualiser la page et essayer \u00e0 nouveau.",
@@ -2079,7 +2078,6 @@
"Unable to load": "Chargement impossible",
"Unable to submit application": "Impossible de soumettre votre demande",
"Unable to submit request to generate report.": "Impossible de soumettre la requ\u00eate de g\u00e9n\u00e9ration de rapport.",
- "Unable to update settings": "Impossible de mettre \u00e0 jours les param\u00e8tres",
"Underline": "Souligner",
"Undo": "Annule",
"Undo (Ctrl+Z)": "Annuler (Ctrl+Z)",
diff --git a/cms/static/js/i18n/it-it/djangojs.js b/cms/static/js/i18n/it-it/djangojs.js
index f5380a01817c..593a272bb9ff 100644
--- a/cms/static/js/i18n/it-it/djangojs.js
+++ b/cms/static/js/i18n/it-it/djangojs.js
@@ -1193,7 +1193,6 @@
"Loading more threads": "Carica ulteriori discussioni",
"Loading posts list": "Caricamento dell'elenco dei post ",
"Loading your courses": "Caricamento dei tuoi corsi",
- "Loading...": "Caricamento...",
"Location": "Posizione",
"Location in Course": "Posizione in corso",
"Lock this asset": "Blocca questa attivit\u00e0",
@@ -1652,7 +1651,6 @@
"Select the course-wide discussion topics that you want to divide.": "Selezionare gli argomenti di discussione a livello del corso che si desidera dividere. ",
"Select the time zone for displaying course dates. If you do not specify a time zone, course dates, including assignment deadlines, will be displayed in your browser's local time zone.": "Seleziona il fuso orario per la visualizzazione delle date dei corsi. Se non specifichi un fuso orario, le date dei corsi, comprese le scadenze dei compiti, verranno visualizzate nel fuso orario locale del tuo browser. ",
"Select turnaround": "Seleziona soluzione temporaneo",
- "Selected blocks": "Blocchi selezionati",
"Selected tab": "Tab selezionata",
"Self": "Autonomo ",
"Send to:": "Manda a:",
@@ -1999,7 +1997,6 @@
"This learner will be removed from the team,allowing another learner to take the available spot.": "Questo studente verr\u00e0 rimosso dal team, consentendo a un altro studente di prendere il posto disponibile. ",
"This link will open in a modal window": "Questo link verr\u00e0 aperto in una finestra modale",
"This link will open in a new browser window/tab": "Questo link verr\u00e0 aperto in una nuova finestra/tab del browser",
- "This may be happening because of an error with our server or your internet connection. Try refreshing the page or making sure you are online.": "L'errore pu\u00f2 essere conseguenza di un errore nei nostri server o nella tua connessione Internet. Prova a ricaricare la pagina e assicurati di essere online.",
"This page contains information about orders that you have placed with {platform_name}.": "Questa pagina contiene informazioni sugli ordini che hai effettuato con {platform_name}. ",
"This post could not be closed. Refresh the page and try again.": "Questo post non pu\u00f2 essere chiuso. Aggiorna la pagina e riprova. ",
"This post could not be flagged for abuse. Refresh the page and try again.": "Questo post non pu\u00f2 essere contrassegnato come abuso. Aggiorna la pagina e riprova. ",
@@ -2097,7 +2094,6 @@
"Unable to load": "Impossibile caricare ",
"Unable to submit application": "Impossibile inviare la domanda",
"Unable to submit request to generate report.": "Impossibile inviare la richiesta per generare il report. ",
- "Unable to update settings": "Impossibile aggiornare le impostazioni",
"Underline": "Sottolineato",
"Undo": "Annulla",
"Undo (Ctrl+Z)": "Annulla (Ctrl+Z)",
diff --git a/cms/static/js/i18n/pt-pt/djangojs.js b/cms/static/js/i18n/pt-pt/djangojs.js
index 53824407cca6..94101bc295e5 100644
--- a/cms/static/js/i18n/pt-pt/djangojs.js
+++ b/cms/static/js/i18n/pt-pt/djangojs.js
@@ -1196,7 +1196,6 @@
"Loading more threads": "A carregar mais t\u00f3picos",
"Loading posts list": "A carregar lista de publica\u00e7\u00f5es",
"Loading your courses": "Carregando os seus cursos",
- "Loading...": "A carregar...",
"Location": "Local",
"Location in Course": "Localiza\u00e7\u00e3o no Curso",
"Lock this asset": "Bloquear este ficheiro",
@@ -1657,7 +1656,6 @@
"Select the course-wide discussion topics that you want to divide.": "Selecionar os t\u00f3picos de debate de todo o curso que pretende dividir.",
"Select the time zone for displaying course dates. If you do not specify a time zone, course dates, including assignment deadlines, will be displayed in your browser's local time zone.": "Selecione o fuso hor\u00e1rio para exibir as datas do curso. Se n\u00e3o for especificado um fuso hor\u00e1rio, as datas do curso, incluindo os prazos de atribui\u00e7\u00e3o, ser\u00e3o exibidos no fuso hor\u00e1rio local do seu navegador.",
"Select turnaround": "Selecione uma alernativa",
- "Selected blocks": "Blocos selecionados",
"Selected tab": "Separador selecionado",
"Self": "Auto",
"Send to:": "Enviar para:",
@@ -2004,7 +2002,6 @@
"This learner will be removed from the team,allowing another learner to take the available spot.": "Este aluno ser\u00e1 removido da equipa, permitindo que outro aluno assuma a vaga dispon\u00edvel.",
"This link will open in a modal window": "Esta liga\u00e7\u00e3o abrir-se-\u00e1 numa janela modal",
"This link will open in a new browser window/tab": "Este link ir\u00e1 abrir numa nova janela/separador do navegador",
- "This may be happening because of an error with our server or your internet connection. Try refreshing the page or making sure you are online.": "Ocorreu este problema provavelmente devido a um erro com o nosso servidor ou com a sua liga\u00e7\u00e3o \u00e0 Internet. Atualize a p\u00e1gina ou certifique-se que est\u00e1 online.",
"This page contains information about orders that you have placed with {platform_name}.": "Esta p\u00e1gina cont\u00e9m informa\u00e7\u00f5es sobre os pedidos que efetuou com {platform_name}.",
"This post could not be closed. Refresh the page and try again.": "N\u00e3o foi poss\u00edvel fechar esta publica\u00e7\u00e3o. Atualize a p\u00e1gina e tente de novo.",
"This post could not be flagged for abuse. Refresh the page and try again.": "N\u00e3o foi poss\u00edvel marcar esta publica\u00e7\u00e3o como abusiva. Atualize a p\u00e1gina e tente de novo.",
@@ -2103,7 +2100,6 @@
"Unable to load": "N\u00e3o foi poss\u00edvel carregar",
"Unable to submit application": "Imposs\u00edvel apresentar a candidatura.",
"Unable to submit request to generate report.": "N\u00e3o \u00e9 poss\u00edvel submeter o pedido de cria\u00e7\u00e3o de relat\u00f3rio.",
- "Unable to update settings": "N\u00e3o \u00e9 poss\u00edvel atualizar configura\u00e7\u00f5es",
"Underline": "Sublinhar",
"Undo": "Desfazer",
"Undo (Ctrl+Z)": "Desfazer (Ctrl + Z)",
diff --git a/cms/static/js/i18n/rtl/djangojs.js b/cms/static/js/i18n/rtl/djangojs.js
index a14efcf87dbf..6917e187da01 100644
--- a/cms/static/js/i18n/rtl/djangojs.js
+++ b/cms/static/js/i18n/rtl/djangojs.js
@@ -571,6 +571,7 @@
"Discussion topics in the course are not divided.": "\u0110\u1d09s\u0254nss\u1d09\u00f8n \u0287\u00f8d\u1d09\u0254s \u1d09n \u0287\u0265\u01dd \u0254\u00f8n\u0279s\u01dd \u0250\u0279\u01dd n\u00f8\u0287 d\u1d09\u028c\u1d09d\u01ddd.",
"Discussions are unified; all learners interact with posts from other learners, regardless of the group they are in.": "\u0110\u1d09s\u0254nss\u1d09\u00f8ns \u0250\u0279\u01dd nn\u1d09\u025f\u1d09\u01ddd; \u0250ll l\u01dd\u0250\u0279n\u01dd\u0279s \u1d09n\u0287\u01dd\u0279\u0250\u0254\u0287 \u028d\u1d09\u0287\u0265 d\u00f8s\u0287s \u025f\u0279\u00f8\u026f \u00f8\u0287\u0265\u01dd\u0279 l\u01dd\u0250\u0279n\u01dd\u0279s, \u0279\u01dd\u0183\u0250\u0279dl\u01ddss \u00f8\u025f \u0287\u0265\u01dd \u0183\u0279\u00f8nd \u0287\u0265\u01dd\u028e \u0250\u0279\u01dd \u1d09n.",
"Discussions enabled": "\u0110\u1d09s\u0254nss\u1d09\u00f8ns \u01ddn\u0250bl\u01ddd",
+ "Dismiss": "\u0110\u1d09s\u026f\u1d09ss",
"Display Name": "\u0110\u1d09sdl\u0250\u028e N\u0250\u026f\u01dd",
"Div": "\u0110\u1d09\u028c",
"Divide the selected content-specific discussion topics": "\u0110\u1d09\u028c\u1d09d\u01dd \u0287\u0265\u01dd s\u01ddl\u01dd\u0254\u0287\u01ddd \u0254\u00f8n\u0287\u01ddn\u0287-sd\u01dd\u0254\u1d09\u025f\u1d09\u0254 d\u1d09s\u0254nss\u1d09\u00f8n \u0287\u00f8d\u1d09\u0254s",
@@ -1014,7 +1015,6 @@
"Loading more threads": "\u0141\u00f8\u0250d\u1d09n\u0183 \u026f\u00f8\u0279\u01dd \u0287\u0265\u0279\u01dd\u0250ds",
"Loading posts list": "\u0141\u00f8\u0250d\u1d09n\u0183 d\u00f8s\u0287s l\u1d09s\u0287",
"Loading your courses": "\u0141\u00f8\u0250d\u1d09n\u0183 \u028e\u00f8n\u0279 \u0254\u00f8n\u0279s\u01dds",
- "Loading...": "\u0141\u00f8\u0250d\u1d09n\u0183...",
"Location": "\u0141\u00f8\u0254\u0250\u0287\u1d09\u00f8n",
"Location in Course": "\u0141\u00f8\u0254\u0250\u0287\u1d09\u00f8n \u1d09n \u023b\u00f8n\u0279s\u01dd",
"Lock this asset": "\u0141\u00f8\u0254\u029e \u0287\u0265\u1d09s \u0250ss\u01dd\u0287",
@@ -1088,7 +1088,7 @@
"New Password": "N\u01dd\u028d \u2c63\u0250ss\u028d\u00f8\u0279d",
"New document": "N\u01dd\u028d d\u00f8\u0254n\u026f\u01ddn\u0287",
"New enrollment mode:": "N\u01dd\u028d \u01ddn\u0279\u00f8ll\u026f\u01ddn\u0287 \u026f\u00f8d\u01dd:",
- "New files were added to this course's Files & Uploads": "N\u01dd\u028d \u025f\u1d09l\u01dds \u028d\u01dd\u0279\u01dd \u0250dd\u01ddd \u0287\u00f8 \u0287\u0265\u1d09s \u0254\u00f8n\u0279s\u01dd's F\u1d09l\u01dds & \u0244dl\u00f8\u0250ds",
+ "New file(s) added to Files & Uploads.": "N\u01dd\u028d \u025f\u1d09l\u01dd(s) \u0250dd\u01ddd \u0287\u00f8 F\u1d09l\u01dds & \u0244dl\u00f8\u0250ds.",
"New window": "N\u01dd\u028d \u028d\u1d09nd\u00f8\u028d",
"New {component_type}": "N\u01dd\u028d {component_type}",
"Next": "N\u01ddx\u0287",
@@ -1435,7 +1435,6 @@
"Select the course-wide discussion topics that you want to divide.": "S\u01ddl\u01dd\u0254\u0287 \u0287\u0265\u01dd \u0254\u00f8n\u0279s\u01dd-\u028d\u1d09d\u01dd d\u1d09s\u0254nss\u1d09\u00f8n \u0287\u00f8d\u1d09\u0254s \u0287\u0265\u0250\u0287 \u028e\u00f8n \u028d\u0250n\u0287 \u0287\u00f8 d\u1d09\u028c\u1d09d\u01dd.",
"Select the time zone for displaying course dates. If you do not specify a time zone, course dates, including assignment deadlines, will be displayed in your browser's local time zone.": "S\u01ddl\u01dd\u0254\u0287 \u0287\u0265\u01dd \u0287\u1d09\u026f\u01dd z\u00f8n\u01dd \u025f\u00f8\u0279 d\u1d09sdl\u0250\u028e\u1d09n\u0183 \u0254\u00f8n\u0279s\u01dd d\u0250\u0287\u01dds. \u0197\u025f \u028e\u00f8n d\u00f8 n\u00f8\u0287 sd\u01dd\u0254\u1d09\u025f\u028e \u0250 \u0287\u1d09\u026f\u01dd z\u00f8n\u01dd, \u0254\u00f8n\u0279s\u01dd d\u0250\u0287\u01dds, \u1d09n\u0254lnd\u1d09n\u0183 \u0250ss\u1d09\u0183n\u026f\u01ddn\u0287 d\u01dd\u0250dl\u1d09n\u01dds, \u028d\u1d09ll b\u01dd d\u1d09sdl\u0250\u028e\u01ddd \u1d09n \u028e\u00f8n\u0279 b\u0279\u00f8\u028ds\u01dd\u0279's l\u00f8\u0254\u0250l \u0287\u1d09\u026f\u01dd z\u00f8n\u01dd.",
"Select turnaround": "S\u01ddl\u01dd\u0254\u0287 \u0287n\u0279n\u0250\u0279\u00f8nnd",
- "Selected blocks": "S\u01ddl\u01dd\u0254\u0287\u01ddd bl\u00f8\u0254\u029es",
"Selected tab": "S\u01ddl\u01dd\u0254\u0287\u01ddd \u0287\u0250b",
"Send to:": "S\u01ddnd \u0287\u00f8:",
"Sent By": "S\u01ddn\u0287 \u0243\u028e",
@@ -1859,7 +1858,6 @@
"Unable to get report generation status.": "\u0244n\u0250bl\u01dd \u0287\u00f8 \u0183\u01dd\u0287 \u0279\u01ddd\u00f8\u0279\u0287 \u0183\u01ddn\u01dd\u0279\u0250\u0287\u1d09\u00f8n s\u0287\u0250\u0287ns.",
"Unable to submit application": "\u0244n\u0250bl\u01dd \u0287\u00f8 snb\u026f\u1d09\u0287 \u0250ddl\u1d09\u0254\u0250\u0287\u1d09\u00f8n",
"Unable to submit request to generate report.": "\u0244n\u0250bl\u01dd \u0287\u00f8 snb\u026f\u1d09\u0287 \u0279\u01ddbn\u01dds\u0287 \u0287\u00f8 \u0183\u01ddn\u01dd\u0279\u0250\u0287\u01dd \u0279\u01ddd\u00f8\u0279\u0287.",
- "Unable to update settings": "\u0244n\u0250bl\u01dd \u0287\u00f8 ndd\u0250\u0287\u01dd s\u01dd\u0287\u0287\u1d09n\u0183s",
"Underline": "\u0244nd\u01dd\u0279l\u1d09n\u01dd",
"Undo": "\u0244nd\u00f8",
"Undo (Ctrl+Z)": "\u0244nd\u00f8 (\u023b\u0287\u0279l+\u01b5)",
@@ -2000,6 +1998,7 @@
"View all errors": "V\u1d09\u01dd\u028d \u0250ll \u01dd\u0279\u0279\u00f8\u0279s",
"View child items": "V\u1d09\u01dd\u028d \u0254\u0265\u1d09ld \u1d09\u0287\u01dd\u026fs",
"View discussion": "V\u1d09\u01dd\u028d d\u1d09s\u0254nss\u1d09\u00f8n",
+ "View files": "V\u1d09\u01dd\u028d \u025f\u1d09l\u01dds",
"View program": "V\u1d09\u01dd\u028d d\u0279\u00f8\u0183\u0279\u0250\u026f",
"View your receipts or modify your subscription on the {a_start}Orders and subscriptions{a_end} page": "V\u1d09\u01dd\u028d \u028e\u00f8n\u0279 \u0279\u01dd\u0254\u01dd\u1d09d\u0287s \u00f8\u0279 \u026f\u00f8d\u1d09\u025f\u028e \u028e\u00f8n\u0279 snbs\u0254\u0279\u1d09d\u0287\u1d09\u00f8n \u00f8n \u0287\u0265\u01dd {a_start}\u00d8\u0279d\u01dd\u0279s \u0250nd snbs\u0254\u0279\u1d09d\u0287\u1d09\u00f8ns{a_end} d\u0250\u0183\u01dd",
"View {span_start} {team_name} {span_end}": "V\u1d09\u01dd\u028d {span_start} {team_name} {span_end}",
diff --git a/cms/static/js/i18n/tr-tr/djangojs.js b/cms/static/js/i18n/tr-tr/djangojs.js
index f42eaa3300cd..2e3ec4546acb 100644
--- a/cms/static/js/i18n/tr-tr/djangojs.js
+++ b/cms/static/js/i18n/tr-tr/djangojs.js
@@ -1123,7 +1123,6 @@
"Loading more threads": "Daha fazla ileti dizisi y\u00fckl\u00fcyor",
"Loading posts list": "\u0130leti listesi y\u00fckleniyor",
"Loading your courses": "Dersleriniz y\u00fckleniyor",
- "Loading...": "Y\u00fckl\u00fcyor...",
"Location": "Yer",
"Location in Course": "Dersteki Konum",
"Lock this asset": "Bu veriyi kitle",
@@ -1578,7 +1577,6 @@
"Select prospective industry": "Hedef sekt\u00f6r\u00fc se\u00e7in",
"Select the course-wide discussion topics that you want to divide.": "B\u00f6lmek istedi\u011finiz ders-geneli tart\u0131\u015fma konular\u0131n\u0131 se\u00e7in.",
"Select the time zone for displaying course dates. If you do not specify a time zone, course dates, including assignment deadlines, will be displayed in your browser's local time zone.": "Ders tarihleri g\u00f6sterimi i\u00e7in saat dilimini se\u00e7in. Herhangi bir saat dilimini se\u00e7memeniz durumunda, g\u00f6rev teslimleri d\u00e2hil olmak \u00fczere t\u00fcm ders tarihleri, web taray\u0131c\u0131n\u0131z\u0131n yerel zaman\u0131na g\u00f6re g\u00f6sterilecektir. ",
- "Selected blocks": "Se\u00e7ili blocklar",
"Selected tab": "Se\u00e7ili sekme",
"Self": "Kendin",
"Send to:": "G\u00f6nderilecek ki\u015fi:",
@@ -1926,7 +1924,6 @@
"This learner will be removed from the team,allowing another learner to take the available spot.": "Bu \u00f6\u011frenci tak\u0131mdan \u00e7\u0131kar\u0131lacak ve ba\u015fka bir \u00f6\u011frencinin uygun yeri almas\u0131na izin verilecektir.",
"This link will open in a modal window": "Bu ba\u011flant\u0131 yeni bir kip penceresinde a\u00e7\u0131lacak",
"This link will open in a new browser window/tab": "Bu ba\u011flant\u0131 taray\u0131c\u0131da yeni bir pencere veya sekmede a\u00e7\u0131lacak",
- "This may be happening because of an error with our server or your internet connection. Try refreshing the page or making sure you are online.": "Bu durum sunucudaki bir hatadan veya \u0130nternet ba\u011flant\u0131n\u0131zdan kaynaklanm\u0131\u015f olabilir. Sayfay\u0131 yeniden y\u00fcklemeyi deneyin veya \u00e7evrimi\u00e7i oldu\u011funuza emin olun.",
"This page contains information about orders that you have placed with {platform_name}.": "Bu sayfa {platform_name} i\u00e7inde verdi\u011finiz sipari\u015fleriniz hakk\u0131nda bilgileri i\u00e7erir.",
"This post could not be closed. Refresh the page and try again.": "Bu g\u00f6nderi kapat\u0131lamaz. Sayfay\u0131 yenileyin ve tekrar deneyin.",
"This post could not be flagged for abuse. Refresh the page and try again.": "Bu g\u00f6nderiye taciz i\u015faretlemesi yap\u0131lamaz. Sayfay\u0131 yenileyin ve tekrar deneyin.",
@@ -2024,7 +2021,6 @@
"Unable to load": "Y\u00fcklenemedi",
"Unable to submit application": "Ba\u015fvuru g\u00f6nderilemedi",
"Unable to submit request to generate report.": "Rapor olu\u015fturma iste\u011fi g\u00f6nderilemedi.",
- "Unable to update settings": "Ayarlar g\u00fcncellenemedi",
"Underline": "Alt \u00e7izgi",
"Undo": "Geri",
"Undo (Ctrl+Z)": "Geri al (Ctrl-Z)",
diff --git a/cms/static/js/i18n/zh-cn/djangojs.js b/cms/static/js/i18n/zh-cn/djangojs.js
index 3d5621e10f00..57038f3be2f7 100644
--- a/cms/static/js/i18n/zh-cn/djangojs.js
+++ b/cms/static/js/i18n/zh-cn/djangojs.js
@@ -969,7 +969,6 @@
"Loading more threads": "\u8f7d\u5165\u66f4\u591a\u7684\u4e3b\u9898",
"Loading posts list": "\u6b63\u5728\u52a0\u8f7d\u5e16\u5b50\u5217\u8868",
"Loading your courses": "\u6b63\u5728\u52a0\u8f7d\u60a8\u7684\u8bfe\u7a0b",
- "Loading...": "\u8f7d\u5165\u4e2d...",
"Location": "\u4f4d\u7f6e",
"Location in Course": "\u8bfe\u7a0b\u4e2d\u7684\u4f4d\u7f6e",
"Lock this asset": "\u9501\u5b9a\u8be5\u8d44\u6e90",
@@ -1361,7 +1360,6 @@
"Select the course-wide discussion topics that you want to divide.": "\u9009\u62e9\u60a8\u60f3\u8981\u533a\u5206\u7684\u8bfe\u7a0b\u8303\u56f4\u5185\u7684\u8ba8\u8bba\u4e3b\u9898\u3002",
"Select the time zone for displaying course dates. If you do not specify a time zone, course dates, including assignment deadlines, will be displayed in your browser's local time zone.": "\u8bf7\u9009\u62e9\u7528\u4e8e\u663e\u793a\u8bfe\u7a0b\u65e5\u671f\u7684\u65f6\u533a\u3002\u5982\u679c\u60a8\u4e0d\u8bbe\u7f6e\u65f6\u533a\uff0c\u90a3\u4e48\u5982\u4f5c\u4e1a\u622a\u6b62\u65e5\u671f\u7b49\u8bfe\u7a0b\u65e5\u671f\u4fe1\u606f\u5c06\u6839\u636e\u60a8\u6d4f\u89c8\u5668\u7684\u672c\u5730\u65f6\u533a\u663e\u793a\u3002",
"Select turnaround": "\u9009\u62e9\u8f6c\u6362",
- "Selected blocks": "\u9009\u4e2d\u7684\u5757",
"Selected tab": "\u9009\u4e2d\u7684\u6807\u7b7e",
"Self": "\u81ea\u5df1",
"Send to:": "\u53d1\u81f3\uff1a",
@@ -1677,7 +1675,6 @@
"This learner will be removed from the team,allowing another learner to take the available spot.": "\u6b64\u6210\u5458\u5c06\u4f1a\u4ece\u8fd9\u4e2a\u961f\u4f0d\u79fb\u9664\u4ee5\u4fbf\u4e3a\u5176\u4ed6\u6210\u5458\u63d0\u4f9b\u7a7a\u4f59\u540d\u989d\u3002",
"This link will open in a modal window": "\u8be5\u94fe\u63a5\u5c06\u5728\u6a21\u5f0f\u7a97\u53e3\u4e2d\u6253\u5f00",
"This link will open in a new browser window/tab": "\u8be5\u94fe\u63a5\u5c06\u5728\u65b0\u6d4f\u89c8\u5668\u7a97\u53e3/\u6807\u7b7e\u9875\u4e2d\u6253\u5f00",
- "This may be happening because of an error with our server or your internet connection. Try refreshing the page or making sure you are online.": "\u6b64\u60c5\u51b5\u53ef\u80fd\u7531\u4e8e\u670d\u52a1\u5668\u9519\u8bef\u6216\u8005\u60a8\u7684\u7f51\u7edc\u8fde\u63a5\u9519\u8bef\u5bfc\u81f4\u3002\u5c1d\u8bd5\u5237\u65b0\u9875\u9762\u6216\u8005\u786e\u4fdd\u7f51\u7edc\u7545\u901a\u3002",
"This page contains information about orders that you have placed with {platform_name}.": "\u6b64\u9875\u9762\u5305\u542b\u60a8\u5728{platform_name}\u6240\u4e0b\u7684\u8ba2\u5355\u4fe1\u606f\u3002",
"This post could not be closed. Refresh the page and try again.": "\u65e0\u6cd5\u5173\u95ed\u6b64\u5e16\u5b50\uff0c\u8bf7\u5237\u65b0\u9875\u9762\u5e76\u91cd\u8bd5\u3002",
"This post could not be flagged for abuse. Refresh the page and try again.": "\u65e0\u6cd5\u5c06\u6b64\u5e16\u5b50\u4e3e\u62a5\u4e3a\u6ee5\u7528\uff0c\u8bf7\u5237\u65b0\u9875\u9762\u5e76\u91cd\u8bd5\u3002",
@@ -1759,7 +1756,6 @@
"Unable to determine whether we should give you a refund because of System Error. Please try again later.": "\u7cfb\u7edf\u53d1\u751f\u9519\u8bef\uff0c\u65e0\u6cd5\u5224\u65ad\u662f\u5426\u5e94\u7ed9\u60a8\u9000\u6b3e\uff0c\u8bf7\u7a0d\u540e\u91cd\u8bd5\u3002",
"Unable to load": "\u4e0d\u80fd\u52a0\u8f7d",
"Unable to submit application": "\u65e0\u6cd5\u63d0\u4ea4\u7533\u8bf7",
- "Unable to update settings": "\u65e0\u6cd5\u66f4\u65b0\u8bbe\u7f6e",
"Underline": "\u4e0b\u5212\u7ebf",
"Undo": "\u64a4\u9500",
"Undo (Ctrl+Z)": "\u64a4\u9500(Ctrl+Z)",
diff --git a/cms/static/js/views/course_outline.js b/cms/static/js/views/course_outline.js
index f7da4ab29fe8..0351f2e175d1 100644
--- a/cms/static/js/views/course_outline.js
+++ b/cms/static/js/views/course_outline.js
@@ -10,10 +10,11 @@
*/
define(['jquery', 'underscore', 'js/views/xblock_outline', 'edx-ui-toolkit/js/utils/string-utils',
'common/js/components/utils/view_utils', 'js/views/utils/xblock_utils',
- 'js/models/xblock_outline_info', 'js/views/modals/course_outline_modals', 'js/utils/drag_and_drop'],
+ 'js/models/xblock_outline_info', 'js/views/modals/course_outline_modals', 'js/utils/drag_and_drop',
+ 'common/js/components/views/feedback_notification', 'common/js/components/views/feedback_prompt',],
function(
$, _, XBlockOutlineView, StringUtils, ViewUtils, XBlockViewUtils,
- XBlockOutlineInfo, CourseOutlineModalsFactory, ContentDragger
+ XBlockOutlineInfo, CourseOutlineModalsFactory, ContentDragger, NotificationView, PromptView
) {
var CourseOutlineView = XBlockOutlineView.extend({
// takes XBlockOutlineInfo as a model
@@ -314,7 +315,11 @@ function(
<% });
} %>
diff --git a/common/static/data/geoip/GeoLite2-Country.mmdb b/common/static/data/geoip/GeoLite2-Country.mmdb
index e96abf7894c4..46e3379657bb 100644
Binary files a/common/static/data/geoip/GeoLite2-Country.mmdb and b/common/static/data/geoip/GeoLite2-Country.mmdb differ
diff --git a/conf/locale/ar/LC_MESSAGES/django.mo b/conf/locale/ar/LC_MESSAGES/django.mo
index c51abcf373fa..ac6a0c242a15 100644
Binary files a/conf/locale/ar/LC_MESSAGES/django.mo and b/conf/locale/ar/LC_MESSAGES/django.mo differ
diff --git a/conf/locale/ar/LC_MESSAGES/django.po b/conf/locale/ar/LC_MESSAGES/django.po
index f1c076b160e4..1b50849b9294 100644
--- a/conf/locale/ar/LC_MESSAGES/django.po
+++ b/conf/locale/ar/LC_MESSAGES/django.po
@@ -259,7 +259,7 @@ msgid ""
msgstr ""
"Project-Id-Version: 0.1a\n"
"Report-Msgid-Bugs-To: openedx-translation@googlegroups.com\n"
-"POT-Creation-Date: 2023-08-20 20:42+0000\n"
+"POT-Creation-Date: 2023-09-10 20:42+0000\n"
"PO-Revision-Date: 2019-01-20 20:43+0000\n"
"Last-Translator: NELC Open edX Translation , 2020\n"
"Language-Team: Arabic (https://app.transifex.com/open-edx/teams/6205/ar/)\n"
@@ -360,8 +360,8 @@ msgid "Video"
msgstr "فيديو"
#: cms/djangoapps/contentstore/views/component.py xmodule/capa_block.py
-msgid "Blank Advanced Problem"
-msgstr "مسألة متقدِّمة فارغة"
+msgid "Blank Problem"
+msgstr ""
#: cms/djangoapps/contentstore/views/component.py
#: xmodule/video_block/video_block.py
@@ -465,8 +465,8 @@ msgstr "التعليم المهني"
#: common/djangoapps/course_modes/models.py xmodule/annotatable_block.py
#: xmodule/capa_block.py xmodule/conditional_block.py
#: xmodule/discussion_block.py xmodule/html_block.py
-#: xmodule/library_content_block.py xmodule/library_sourced_block.py
-#: xmodule/lti_block.py xmodule/split_test_block.py xmodule/unit_block.py
+#: xmodule/library_content_block.py xmodule/lti_block.py
+#: xmodule/split_test_block.py xmodule/unit_block.py
#: xmodule/word_cloud_block.py xmodule/x_module.py
#: cms/templates/container.html cms/templates/library.html
msgid "Display Name"
@@ -3270,6 +3270,12 @@ msgstr "مهمة"
msgid "Open Response Assessment"
msgstr "تقييم الردود المفتوحة"
+#: lms/djangoapps/courseware/courses.py
+msgid ""
+"This Open Response Assessment's due dates are set by your instructor and "
+"can't be shifted."
+msgstr ""
+
#: lms/djangoapps/courseware/courses.py
msgid "Self Assessment"
msgstr "التقييم الذاتي"
@@ -3286,13 +3292,6 @@ msgstr "تقييم طاقم المساق"
msgid "Submission"
msgstr "إرسال"
-#: lms/djangoapps/courseware/courses.py
-msgid ""
-"Open Response Assessment due dates are set by your instructor and can't be "
-"shifted."
-msgstr ""
-"تم تحديد تواريخ انتهاء تقييم الإجابات المفتوحة من معلّمك ولايمكن تغييرها."
-
#. Translators: 'absolute' is a date such as "Jan 01,
#. 2020". 'relative' is a fuzzy description of the time until
#. 'absolute'. For example, 'absolute' might be "Jan 01, 2020",
@@ -5955,7 +5954,6 @@ msgstr ""
#: lms/templates/oauth2_provider/authorize.html
#: openedx/core/djangoapps/user_api/admin.py
-#: xmodule/templates/library-sourced-block-studio-view.html
#: cms/templates/course-create-rerun.html cms/templates/index.html
#: cms/templates/manage_users.html cms/templates/manage_users_lib.html
#: cms/templates/videos_index_pagination.html
@@ -6409,13 +6407,11 @@ msgid "Quotes"
msgstr "اقتباسات"
#: lms/templates/wiki/includes/editor_widget.html
-#, python-format
+#, python-brace-format
msgid ""
-"Markdown syntax is allowed. See the %(start_link)scheatsheet%(end_link)s for"
-" help."
+"Markdown syntax is allowed. See the {start_link}cheatsheet{end_link} for "
+"help."
msgstr ""
-"يسمح بناء الجملة Markdown. راجع %(start_link)s ورقة الغش %(end_link)s "
-"للحصول على المساعدة."
#: lms/templates/wiki/plugins/attachments/index.html
#: wiki/plugins/attachments/templates/wiki/plugins/attachments/index.html
@@ -7429,8 +7425,8 @@ msgstr ""
#: openedx/core/djangoapps/discussions/models.py
msgid ""
-"The Posting availabilty in discussions whether it will be enabled, scheduled"
-" or indefinitely disabled."
+"The Posting availability in discussions whether it will be enabled, "
+"scheduled or indefinitely disabled."
msgstr ""
#: openedx/core/djangoapps/discussions/models.py
@@ -9428,8 +9424,7 @@ msgstr "بيانات ’XML‘ للملاحظات التوضيحية"
#: xmodule/annotatable_block.py xmodule/capa_block.py
#: xmodule/conditional_block.py xmodule/discussion_block.py
#: xmodule/html_block.py xmodule/library_content_block.py
-#: xmodule/library_root_xblock.py xmodule/library_sourced_block.py
-#: xmodule/poll_block.py xmodule/unit_block.py
+#: xmodule/library_root_xblock.py xmodule/poll_block.py xmodule/unit_block.py
#: xmodule/video_block/video_xfields.py xmodule/word_cloud_block.py
#: xmodule/x_module.py
msgid "The display name for this component."
@@ -11639,34 +11634,6 @@ msgstr "اسم المكتبة المعروض"
msgid "Enter the names of the advanced components to use in your library."
msgstr "يُرجى إدخال أسماء المكوِّنات المتقدّمة التي ستُستخدم في مكتبتك."
-#: xmodule/library_sourced_block.py
-msgid "Library Blocks List"
-msgstr "قائمة كتل المكتبة"
-
-#: xmodule/library_sourced_block.py
-msgid "Enter the IDs of the library XBlocks that you wish to use."
-msgstr "أدخل معرّفات كتل المكتبة المجهولة التي ترغب في استخدامها."
-
-#: xmodule/library_sourced_block.py
-#, python-brace-format
-msgid "A maximum of {0} components may be added."
-msgstr "يمكن إضافة عددًا لا يتجاوز {0} من العناصر"
-
-#: xmodule/library_sourced_block.py
-msgid ""
-"No XBlock has been configured for this component. Use the editor to select "
-"the target blocks."
-msgstr ""
-"لم يتم تشكيل كتل معينة لهذا العنصر. استخدم المحرر لتحديد الكتل المستهدفة."
-
-#: xmodule/library_sourced_block.py
-msgid "Open Editor"
-msgstr "فتح المحرّر"
-
-#: xmodule/library_sourced_block.py
-msgid "Importing Library Block failed - are the IDs valid and readable?"
-msgstr "فشل استيراد كتلة المكتبة - هل المعرفات صحيحة ويمكن قراءتها؟"
-
#: xmodule/lti_block.py
msgid ""
"The display name for this component. Analytics reports may also use the "
@@ -12358,10 +12325,6 @@ msgstr "هناك مشاكل في تجربة المحتوى هذه، تؤثّر
msgid "External Discussion"
msgstr "مناقشة خارجية"
-#: xmodule/templates/library-sourced-block-studio-view.html
-msgid "Save and Import"
-msgstr "حفظ واستيراد"
-
#: xmodule/vertical_block.py
msgid "Enable in-context discussions for the Unit"
msgstr ""
@@ -16269,10 +16232,6 @@ msgstr "تنزيل درجات الطلاب"
msgid "Print or share your certificate:"
msgstr "اطبع أو شارك شهادتك:"
-#: lms/templates/certificates/_accomplishment-banner.html
-msgid "Click the link to see my certificate."
-msgstr "انقر على الرابط لمشاهدة شهادتي"
-
#: lms/templates/certificates/_accomplishment-banner.html
msgid "Post on Facebook"
msgstr "انشر على فيسبوك"
diff --git a/conf/locale/ar/LC_MESSAGES/djangojs.mo b/conf/locale/ar/LC_MESSAGES/djangojs.mo
index 6e575b7cc46e..34ce8b91f7ce 100644
Binary files a/conf/locale/ar/LC_MESSAGES/djangojs.mo and b/conf/locale/ar/LC_MESSAGES/djangojs.mo differ
diff --git a/conf/locale/ar/LC_MESSAGES/djangojs.po b/conf/locale/ar/LC_MESSAGES/djangojs.po
index 19d874a2b172..09d3be4a9554 100644
--- a/conf/locale/ar/LC_MESSAGES/djangojs.po
+++ b/conf/locale/ar/LC_MESSAGES/djangojs.po
@@ -194,7 +194,7 @@ msgid ""
msgstr ""
"Project-Id-Version: edx-platform\n"
"Report-Msgid-Bugs-To: openedx-translation@googlegroups.com\n"
-"POT-Creation-Date: 2023-08-27 20:42+0000\n"
+"POT-Creation-Date: 2023-09-17 20:42+0000\n"
"PO-Revision-Date: 2014-06-11 15:18+0000\n"
"Last-Translator: Abderraouf Mehdi Bouhali , 2022\n"
"Language-Team: Arabic (http://app.transifex.com/open-edx/edx-platform/language/ar/)\n"
@@ -205,16 +205,6 @@ msgstr ""
"Plural-Forms: nplurals=6; plural=n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 && n%100<=10 ? 3 : n%100>=11 && n%100<=99 ? 4 : 5;\n"
"Generated-By: Babel 2.8.0\n"
-#: cms/static/cms/js/main.js cms/static/js/views/active_video_upload_list.js
-#: cms/static/js/views/video_transcripts.js
-#: xmodule/assets/library_source_block/public/js/library_source_block.js
-msgid ""
-"This may be happening because of an error with our server or your internet "
-"connection. Try refreshing the page or making sure you are online."
-msgstr ""
-"توجد مشكلة في الخادم أو في الاتصال بالشبكة، يرجى تحديث الصفحة أو التأكد من "
-"الاتصال بالشبكة."
-
#: cms/static/cms/js/xblock/cms.runtime.v1.js
#: cms/static/js/certificates/views/signatory_details.js
#: cms/static/js/models/section.js cms/static/js/utils/drag_and_drop.js
@@ -226,7 +216,6 @@ msgstr ""
#: cms/static/js/views/modals/edit_xblock.js cms/static/js/views/tabs.js
#: cms/static/js/views/utils/xblock_utils.js lms/static/js/ccx/schedule.js
#: lms/static/js/views/fields.js
-#: xmodule/assets/library_source_block/public/js/library_source_block.js
msgid "Saving"
msgstr "جاري الحفظ"
@@ -4279,18 +4268,6 @@ msgstr "الملف الشخصي"
msgid "Updating with latest library content"
msgstr "جاري تحديث المحتوى"
-#: xmodule/assets/library_source_block/LibrarySourcedBlockPicker.jsx
-msgid "Loading..."
-msgstr ""
-
-#: xmodule/assets/library_source_block/LibrarySourcedBlockPicker.jsx
-msgid "Selected blocks"
-msgstr ""
-
-#: xmodule/assets/library_source_block/public/js/library_source_block.js
-msgid "Unable to update settings"
-msgstr "تعذر تحديث الإعدادات"
-
#: xmodule/assets/split_test/public/js/split_test_author_view.js
#: xmodule/js/public/js/split_test_author_view.js
msgid "Creating missing groups"
@@ -5991,6 +5968,13 @@ msgstr "عرض نص الكلام"
msgid "Turn off transcripts"
msgstr "إخفاء نص الكلام"
+#: cms/static/cms/js/main.js cms/static/js/views/active_video_upload_list.js
+#: cms/static/js/views/video_transcripts.js
+msgid ""
+"This may be happening because of an error with our server or your internet "
+"connection. Try refreshing the page or making sure you are online."
+msgstr ""
+
#: cms/static/cms/js/main.js
msgid "Studio's having trouble saving your work"
msgstr "يواجه نظام Studio صعوبة في حفظ عملك"
@@ -6547,7 +6531,7 @@ msgstr ""
#: cms/static/js/views/course_outline.js
#: cms/static/js/views/pages/container.js
-msgid "New files were added to this course's Files & Uploads"
+msgid "New file(s) added to Files & Uploads."
msgstr ""
#: cms/static/js/views/course_outline.js
@@ -6555,6 +6539,16 @@ msgstr ""
msgid "The following required files were imported to this course:"
msgstr ""
+#: cms/static/js/views/course_outline.js
+#: cms/static/js/views/pages/container.js
+msgid "View files"
+msgstr ""
+
+#: cms/static/js/views/course_outline.js
+#: cms/static/js/views/pages/container.js
+msgid "Dismiss"
+msgstr ""
+
#: cms/static/js/views/course_rerun.js
msgid "Create Re-run"
msgstr "خلق وحدة مُعاد تنفيذها"
diff --git a/conf/locale/ca/LC_MESSAGES/django.mo b/conf/locale/ca/LC_MESSAGES/django.mo
index 43e488a6803d..a0a8b569d337 100644
Binary files a/conf/locale/ca/LC_MESSAGES/django.mo and b/conf/locale/ca/LC_MESSAGES/django.mo differ
diff --git a/conf/locale/ca/LC_MESSAGES/django.po b/conf/locale/ca/LC_MESSAGES/django.po
index 32872852a5e2..f3e40b6a47f9 100644
--- a/conf/locale/ca/LC_MESSAGES/django.po
+++ b/conf/locale/ca/LC_MESSAGES/django.po
@@ -67,7 +67,7 @@ msgid ""
msgstr ""
"Project-Id-Version: 0.1a\n"
"Report-Msgid-Bugs-To: openedx-translation@googlegroups.com\n"
-"POT-Creation-Date: 2023-08-27 20:43+0000\n"
+"POT-Creation-Date: 2023-09-17 20:43+0000\n"
"PO-Revision-Date: 2019-01-20 20:43+0000\n"
"Last-Translator: Waheed Ahmed , 2019\n"
"Language-Team: Catalan (https://app.transifex.com/open-edx/teams/6205/ca/)\n"
@@ -166,7 +166,7 @@ msgid "Video"
msgstr "Video"
#: cms/djangoapps/contentstore/views/component.py xmodule/capa_block.py
-msgid "Blank Advanced Problem"
+msgid "Blank Problem"
msgstr ""
#: cms/djangoapps/contentstore/views/component.py
@@ -271,8 +271,8 @@ msgstr ""
#: common/djangoapps/course_modes/models.py xmodule/annotatable_block.py
#: xmodule/capa_block.py xmodule/conditional_block.py
#: xmodule/discussion_block.py xmodule/html_block.py
-#: xmodule/library_content_block.py xmodule/library_sourced_block.py
-#: xmodule/lti_block.py xmodule/split_test_block.py xmodule/unit_block.py
+#: xmodule/library_content_block.py xmodule/lti_block.py
+#: xmodule/split_test_block.py xmodule/unit_block.py
#: xmodule/word_cloud_block.py xmodule/x_module.py
#: cms/templates/container.html cms/templates/library.html
msgid "Display Name"
@@ -2761,6 +2761,12 @@ msgstr ""
msgid "Open Response Assessment"
msgstr ""
+#: lms/djangoapps/courseware/courses.py
+msgid ""
+"This Open Response Assessment's due dates are set by your instructor and "
+"can't be shifted."
+msgstr ""
+
#: lms/djangoapps/courseware/courses.py
msgid "Self Assessment"
msgstr ""
@@ -2777,12 +2783,6 @@ msgstr ""
msgid "Submission"
msgstr ""
-#: lms/djangoapps/courseware/courses.py
-msgid ""
-"Open Response Assessment due dates are set by your instructor and can't be "
-"shifted."
-msgstr ""
-
#. Translators: 'absolute' is a date such as "Jan 01,
#. 2020". 'relative' is a fuzzy description of the time until
#. 'absolute'. For example, 'absolute' might be "Jan 01, 2020",
@@ -5238,7 +5238,6 @@ msgstr ""
#: lms/templates/oauth2_provider/authorize.html
#: openedx/core/djangoapps/user_api/admin.py
-#: xmodule/templates/library-sourced-block-studio-view.html
msgid "Cancel"
msgstr "Cancel·lar"
@@ -5682,10 +5681,10 @@ msgid "Quotes"
msgstr "Cites"
#: lms/templates/wiki/includes/editor_widget.html
-#, python-format
+#, python-brace-format
msgid ""
-"Markdown syntax is allowed. See the %(start_link)scheatsheet%(end_link)s for"
-" help."
+"Markdown syntax is allowed. See the {start_link}cheatsheet{end_link} for "
+"help."
msgstr ""
#: lms/templates/wiki/plugins/attachments/index.html
@@ -6636,8 +6635,8 @@ msgstr ""
#: openedx/core/djangoapps/discussions/models.py
msgid ""
-"The Posting availabilty in discussions whether it will be enabled, scheduled"
-" or indefinitely disabled."
+"The Posting availability in discussions whether it will be enabled, "
+"scheduled or indefinitely disabled."
msgstr ""
#: openedx/core/djangoapps/discussions/models.py
@@ -8426,8 +8425,7 @@ msgstr ""
#: xmodule/annotatable_block.py xmodule/capa_block.py
#: xmodule/conditional_block.py xmodule/discussion_block.py
#: xmodule/html_block.py xmodule/library_content_block.py
-#: xmodule/library_root_xblock.py xmodule/library_sourced_block.py
-#: xmodule/poll_block.py xmodule/unit_block.py
+#: xmodule/library_root_xblock.py xmodule/poll_block.py xmodule/unit_block.py
#: xmodule/video_block/video_xfields.py xmodule/word_cloud_block.py
#: xmodule/x_module.py
msgid "The display name for this component."
@@ -10392,33 +10390,6 @@ msgstr ""
msgid "Enter the names of the advanced components to use in your library."
msgstr ""
-#: xmodule/library_sourced_block.py
-msgid "Library Blocks List"
-msgstr ""
-
-#: xmodule/library_sourced_block.py
-msgid "Enter the IDs of the library XBlocks that you wish to use."
-msgstr ""
-
-#: xmodule/library_sourced_block.py
-#, python-brace-format
-msgid "A maximum of {0} components may be added."
-msgstr ""
-
-#: xmodule/library_sourced_block.py
-msgid ""
-"No XBlock has been configured for this component. Use the editor to select "
-"the target blocks."
-msgstr ""
-
-#: xmodule/library_sourced_block.py
-msgid "Open Editor"
-msgstr ""
-
-#: xmodule/library_sourced_block.py
-msgid "Importing Library Block failed - are the IDs valid and readable?"
-msgstr ""
-
#: xmodule/lti_block.py
msgid ""
"The display name for this component. Analytics reports may also use the "
@@ -11005,10 +10976,6 @@ msgstr ""
msgid "External Discussion"
msgstr ""
-#: xmodule/templates/library-sourced-block-studio-view.html
-msgid "Save and Import"
-msgstr ""
-
#: xmodule/vertical_block.py
msgid "Enable in-context discussions for the Unit"
msgstr ""
@@ -14915,10 +14882,6 @@ msgstr "Baixa els graus dels estudiants"
msgid "Print or share your certificate:"
msgstr "Imprimiu o compartiu el vostre certificat:"
-#: lms/templates/certificates/_accomplishment-banner.html
-msgid "Click the link to see my certificate."
-msgstr "Feu clic a l'enllaç per veure el meu certificat."
-
#: lms/templates/certificates/_accomplishment-banner.html
msgid "Post on Facebook"
msgstr "Publica a Facebook"
diff --git a/conf/locale/ca/LC_MESSAGES/djangojs.po b/conf/locale/ca/LC_MESSAGES/djangojs.po
index 46736cbafb86..9e6413627be9 100644
--- a/conf/locale/ca/LC_MESSAGES/djangojs.po
+++ b/conf/locale/ca/LC_MESSAGES/djangojs.po
@@ -48,7 +48,7 @@ msgid ""
msgstr ""
"Project-Id-Version: edx-platform\n"
"Report-Msgid-Bugs-To: openedx-translation@googlegroups.com\n"
-"POT-Creation-Date: 2023-08-27 20:42+0000\n"
+"POT-Creation-Date: 2023-09-17 20:42+0000\n"
"PO-Revision-Date: 2014-06-11 15:18+0000\n"
"Last-Translator: Waheed Ahmed , 2019\n"
"Language-Team: Catalan (http://app.transifex.com/open-edx/edx-platform/language/ca/)\n"
@@ -59,14 +59,6 @@ msgstr ""
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
"Generated-By: Babel 2.8.0\n"
-#: cms/static/cms/js/main.js cms/static/js/views/active_video_upload_list.js
-#: cms/static/js/views/video_transcripts.js
-#: xmodule/assets/library_source_block/public/js/library_source_block.js
-msgid ""
-"This may be happening because of an error with our server or your internet "
-"connection. Try refreshing the page or making sure you are online."
-msgstr ""
-
#: cms/static/cms/js/xblock/cms.runtime.v1.js
#: cms/static/js/certificates/views/signatory_details.js
#: cms/static/js/models/section.js cms/static/js/utils/drag_and_drop.js
@@ -78,7 +70,6 @@ msgstr ""
#: cms/static/js/views/modals/edit_xblock.js cms/static/js/views/tabs.js
#: cms/static/js/views/utils/xblock_utils.js lms/static/js/ccx/schedule.js
#: lms/static/js/views/fields.js
-#: xmodule/assets/library_source_block/public/js/library_source_block.js
msgid "Saving"
msgstr ""
@@ -3704,18 +3695,6 @@ msgstr ""
msgid "Updating with latest library content"
msgstr ""
-#: xmodule/assets/library_source_block/LibrarySourcedBlockPicker.jsx
-msgid "Loading..."
-msgstr ""
-
-#: xmodule/assets/library_source_block/LibrarySourcedBlockPicker.jsx
-msgid "Selected blocks"
-msgstr ""
-
-#: xmodule/assets/library_source_block/public/js/library_source_block.js
-msgid "Unable to update settings"
-msgstr ""
-
#: xmodule/assets/split_test/public/js/split_test_author_view.js
#: xmodule/js/public/js/split_test_author_view.js
msgid "Creating missing groups"
@@ -5319,6 +5298,13 @@ msgstr ""
msgid "Turn off transcripts"
msgstr ""
+#: cms/static/cms/js/main.js cms/static/js/views/active_video_upload_list.js
+#: cms/static/js/views/video_transcripts.js
+msgid ""
+"This may be happening because of an error with our server or your internet "
+"connection. Try refreshing the page or making sure you are online."
+msgstr ""
+
#: cms/static/cms/js/main.js
msgid "Studio's having trouble saving your work"
msgstr ""
@@ -5878,7 +5864,7 @@ msgstr ""
#: cms/static/js/views/course_outline.js
#: cms/static/js/views/pages/container.js
-msgid "New files were added to this course's Files & Uploads"
+msgid "New file(s) added to Files & Uploads."
msgstr ""
#: cms/static/js/views/course_outline.js
@@ -5886,6 +5872,16 @@ msgstr ""
msgid "The following required files were imported to this course:"
msgstr ""
+#: cms/static/js/views/course_outline.js
+#: cms/static/js/views/pages/container.js
+msgid "View files"
+msgstr ""
+
+#: cms/static/js/views/course_outline.js
+#: cms/static/js/views/pages/container.js
+msgid "Dismiss"
+msgstr ""
+
#: cms/static/js/views/course_rerun.js
msgid "Create Re-run"
msgstr "Crea una reproducció nova"
diff --git a/conf/locale/de_DE/LC_MESSAGES/django.mo b/conf/locale/de_DE/LC_MESSAGES/django.mo
index 13bd2e94173d..eef55ba4bae9 100644
Binary files a/conf/locale/de_DE/LC_MESSAGES/django.mo and b/conf/locale/de_DE/LC_MESSAGES/django.mo differ
diff --git a/conf/locale/de_DE/LC_MESSAGES/django.po b/conf/locale/de_DE/LC_MESSAGES/django.po
index d8e6d89b20c1..618f52d388ea 100644
--- a/conf/locale/de_DE/LC_MESSAGES/django.po
+++ b/conf/locale/de_DE/LC_MESSAGES/django.po
@@ -177,7 +177,7 @@ msgid ""
msgstr ""
"Project-Id-Version: 0.1a\n"
"Report-Msgid-Bugs-To: openedx-translation@googlegroups.com\n"
-"POT-Creation-Date: 2023-08-20 20:42+0000\n"
+"POT-Creation-Date: 2023-09-10 20:42+0000\n"
"PO-Revision-Date: 2019-01-20 20:43+0000\n"
"Last-Translator: Stefania Trabucchi , 2019\n"
"Language-Team: German (Germany) (https://app.transifex.com/open-edx/teams/6205/de_DE/)\n"
@@ -278,8 +278,8 @@ msgid "Video"
msgstr "Video"
#: cms/djangoapps/contentstore/views/component.py xmodule/capa_block.py
-msgid "Blank Advanced Problem"
-msgstr "Leeres fortgeschrittenes Problem"
+msgid "Blank Problem"
+msgstr ""
#: cms/djangoapps/contentstore/views/component.py
#: xmodule/video_block/video_block.py
@@ -384,8 +384,8 @@ msgstr "Fachausbildung"
#: common/djangoapps/course_modes/models.py xmodule/annotatable_block.py
#: xmodule/capa_block.py xmodule/conditional_block.py
#: xmodule/discussion_block.py xmodule/html_block.py
-#: xmodule/library_content_block.py xmodule/library_sourced_block.py
-#: xmodule/lti_block.py xmodule/split_test_block.py xmodule/unit_block.py
+#: xmodule/library_content_block.py xmodule/lti_block.py
+#: xmodule/split_test_block.py xmodule/unit_block.py
#: xmodule/word_cloud_block.py xmodule/x_module.py
#: cms/templates/container.html cms/templates/library.html
msgid "Display Name"
@@ -3142,6 +3142,12 @@ msgstr "Aufgabe"
msgid "Open Response Assessment"
msgstr ""
+#: lms/djangoapps/courseware/courses.py
+msgid ""
+"This Open Response Assessment's due dates are set by your instructor and "
+"can't be shifted."
+msgstr ""
+
#: lms/djangoapps/courseware/courses.py
msgid "Self Assessment"
msgstr ""
@@ -3158,12 +3164,6 @@ msgstr ""
msgid "Submission"
msgstr ""
-#: lms/djangoapps/courseware/courses.py
-msgid ""
-"Open Response Assessment due dates are set by your instructor and can't be "
-"shifted."
-msgstr ""
-
#. Translators: 'absolute' is a date such as "Jan 01,
#. 2020". 'relative' is a fuzzy description of the time until
#. 'absolute'. For example, 'absolute' might be "Jan 01, 2020",
@@ -5887,7 +5887,6 @@ msgstr ""
#: lms/templates/oauth2_provider/authorize.html
#: openedx/core/djangoapps/user_api/admin.py
-#: xmodule/templates/library-sourced-block-studio-view.html
#: cms/templates/course-create-rerun.html cms/templates/index.html
#: cms/templates/manage_users.html cms/templates/manage_users_lib.html
#: cms/templates/videos_index_pagination.html
@@ -6352,13 +6351,11 @@ msgid "Quotes"
msgstr "Anführungszeichen"
#: lms/templates/wiki/includes/editor_widget.html
-#, python-format
+#, python-brace-format
msgid ""
-"Markdown syntax is allowed. See the %(start_link)scheatsheet%(end_link)s for"
-" help."
+"Markdown syntax is allowed. See the {start_link}cheatsheet{end_link} for "
+"help."
msgstr ""
-"Die Markdown Syntax ist erlaubt. Siehe %(start_link)sCheatsheet%(end_link)s "
-"für Hilfe."
#: lms/templates/wiki/plugins/attachments/index.html
#: wiki/plugins/attachments/templates/wiki/plugins/attachments/index.html
@@ -7387,8 +7384,8 @@ msgstr ""
#: openedx/core/djangoapps/discussions/models.py
msgid ""
-"The Posting availabilty in discussions whether it will be enabled, scheduled"
-" or indefinitely disabled."
+"The Posting availability in discussions whether it will be enabled, "
+"scheduled or indefinitely disabled."
msgstr ""
#: openedx/core/djangoapps/discussions/models.py
@@ -9430,8 +9427,7 @@ msgstr "XML-Daten für die Anmerkung"
#: xmodule/annotatable_block.py xmodule/capa_block.py
#: xmodule/conditional_block.py xmodule/discussion_block.py
#: xmodule/html_block.py xmodule/library_content_block.py
-#: xmodule/library_root_xblock.py xmodule/library_sourced_block.py
-#: xmodule/poll_block.py xmodule/unit_block.py
+#: xmodule/library_root_xblock.py xmodule/poll_block.py xmodule/unit_block.py
#: xmodule/video_block/video_xfields.py xmodule/word_cloud_block.py
#: xmodule/x_module.py
msgid "The display name for this component."
@@ -11712,33 +11708,6 @@ msgstr ""
"Geben Sie die Namen der erweiterten Komponenten ein, die in Ihrer Bibliothek"
" verwendet werden sollen."
-#: xmodule/library_sourced_block.py
-msgid "Library Blocks List"
-msgstr ""
-
-#: xmodule/library_sourced_block.py
-msgid "Enter the IDs of the library XBlocks that you wish to use."
-msgstr ""
-
-#: xmodule/library_sourced_block.py
-#, python-brace-format
-msgid "A maximum of {0} components may be added."
-msgstr ""
-
-#: xmodule/library_sourced_block.py
-msgid ""
-"No XBlock has been configured for this component. Use the editor to select "
-"the target blocks."
-msgstr ""
-
-#: xmodule/library_sourced_block.py
-msgid "Open Editor"
-msgstr ""
-
-#: xmodule/library_sourced_block.py
-msgid "Importing Library Block failed - are the IDs valid and readable?"
-msgstr ""
-
#: xmodule/lti_block.py
msgid ""
"The display name for this component. Analytics reports may also use the "
@@ -12465,10 +12434,6 @@ msgstr ""
msgid "External Discussion"
msgstr "Externes Forum"
-#: xmodule/templates/library-sourced-block-studio-view.html
-msgid "Save and Import"
-msgstr ""
-
#: xmodule/vertical_block.py
msgid "Enable in-context discussions for the Unit"
msgstr ""
@@ -16518,10 +16483,6 @@ msgstr "Laden Sie die Noten der Teilnehmer "
msgid "Print or share your certificate:"
msgstr "Zertifikat drucken oder teilen:"
-#: lms/templates/certificates/_accomplishment-banner.html
-msgid "Click the link to see my certificate."
-msgstr "Klicke auf den Link, um deine Zertifikate zu sehen."
-
#: lms/templates/certificates/_accomplishment-banner.html
msgid "Post on Facebook"
msgstr "Auf Facebook teilen"
diff --git a/conf/locale/de_DE/LC_MESSAGES/djangojs.mo b/conf/locale/de_DE/LC_MESSAGES/djangojs.mo
index c3c6acf45621..1758749e4223 100644
Binary files a/conf/locale/de_DE/LC_MESSAGES/djangojs.mo and b/conf/locale/de_DE/LC_MESSAGES/djangojs.mo differ
diff --git a/conf/locale/de_DE/LC_MESSAGES/djangojs.po b/conf/locale/de_DE/LC_MESSAGES/djangojs.po
index 40b6d5a94147..8dc44711bbbf 100644
--- a/conf/locale/de_DE/LC_MESSAGES/djangojs.po
+++ b/conf/locale/de_DE/LC_MESSAGES/djangojs.po
@@ -134,7 +134,7 @@ msgid ""
msgstr ""
"Project-Id-Version: edx-platform\n"
"Report-Msgid-Bugs-To: openedx-translation@googlegroups.com\n"
-"POT-Creation-Date: 2023-08-27 20:42+0000\n"
+"POT-Creation-Date: 2023-09-17 20:42+0000\n"
"PO-Revision-Date: 2014-06-11 15:18+0000\n"
"Last-Translator: Alfredo Guillem, 2022\n"
"Language-Team: German (Germany) (http://app.transifex.com/open-edx/edx-platform/language/de_DE/)\n"
@@ -145,17 +145,6 @@ msgstr ""
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
"Generated-By: Babel 2.8.0\n"
-#: cms/static/cms/js/main.js cms/static/js/views/active_video_upload_list.js
-#: cms/static/js/views/video_transcripts.js
-#: xmodule/assets/library_source_block/public/js/library_source_block.js
-msgid ""
-"This may be happening because of an error with our server or your internet "
-"connection. Try refreshing the page or making sure you are online."
-msgstr ""
-"Dieses Problem wurde durch einen Fehler auf unserem Server oder mit Ihrer "
-"Internetverbindung verursacht. Versuchen Sie die Seite neu zu laden und/oder"
-" prüfen Sie ihre Internetverbindung"
-
#: cms/static/cms/js/xblock/cms.runtime.v1.js
#: cms/static/js/certificates/views/signatory_details.js
#: cms/static/js/models/section.js cms/static/js/utils/drag_and_drop.js
@@ -167,7 +156,6 @@ msgstr ""
#: cms/static/js/views/modals/edit_xblock.js cms/static/js/views/tabs.js
#: cms/static/js/views/utils/xblock_utils.js lms/static/js/ccx/schedule.js
#: lms/static/js/views/fields.js
-#: xmodule/assets/library_source_block/public/js/library_source_block.js
msgid "Saving"
msgstr "Speichert"
@@ -4297,18 +4285,6 @@ msgstr "Profil"
msgid "Updating with latest library content"
msgstr "Aktualisiere mit den neuesten Bibliotheken"
-#: xmodule/assets/library_source_block/LibrarySourcedBlockPicker.jsx
-msgid "Loading..."
-msgstr "Lade..."
-
-#: xmodule/assets/library_source_block/LibrarySourcedBlockPicker.jsx
-msgid "Selected blocks"
-msgstr "Ausgewählte Blöcke"
-
-#: xmodule/assets/library_source_block/public/js/library_source_block.js
-msgid "Unable to update settings"
-msgstr "Einstellungen aktualisieren nicht möglich"
-
#: xmodule/assets/split_test/public/js/split_test_author_view.js
#: xmodule/js/public/js/split_test_author_view.js
msgid "Creating missing groups"
@@ -5978,6 +5954,13 @@ msgstr "Transkripte aktivieren"
msgid "Turn off transcripts"
msgstr "Transkripte deaktivieren"
+#: cms/static/cms/js/main.js cms/static/js/views/active_video_upload_list.js
+#: cms/static/js/views/video_transcripts.js
+msgid ""
+"This may be happening because of an error with our server or your internet "
+"connection. Try refreshing the page or making sure you are online."
+msgstr ""
+
#: cms/static/cms/js/main.js
msgid "Studio's having trouble saving your work"
msgstr "Studio hat Probleme beim Speichern Ihrer Arbeit"
@@ -6561,7 +6544,7 @@ msgstr ""
#: cms/static/js/views/course_outline.js
#: cms/static/js/views/pages/container.js
-msgid "New files were added to this course's Files & Uploads"
+msgid "New file(s) added to Files & Uploads."
msgstr ""
#: cms/static/js/views/course_outline.js
@@ -6569,6 +6552,16 @@ msgstr ""
msgid "The following required files were imported to this course:"
msgstr ""
+#: cms/static/js/views/course_outline.js
+#: cms/static/js/views/pages/container.js
+msgid "View files"
+msgstr ""
+
+#: cms/static/js/views/course_outline.js
+#: cms/static/js/views/pages/container.js
+msgid "Dismiss"
+msgstr ""
+
#: cms/static/js/views/course_rerun.js
msgid "Create Re-run"
msgstr "Erstelle Wiederholungslauf"
diff --git a/conf/locale/el/LC_MESSAGES/django.po b/conf/locale/el/LC_MESSAGES/django.po
index a8ff82a97688..6637c4de6f6b 100644
--- a/conf/locale/el/LC_MESSAGES/django.po
+++ b/conf/locale/el/LC_MESSAGES/django.po
@@ -98,7 +98,7 @@ msgid ""
msgstr ""
"Project-Id-Version: 0.1a\n"
"Report-Msgid-Bugs-To: openedx-translation@googlegroups.com\n"
-"POT-Creation-Date: 2023-08-27 20:43+0000\n"
+"POT-Creation-Date: 2023-09-17 20:43+0000\n"
"PO-Revision-Date: 2019-01-20 20:43+0000\n"
"Last-Translator: Waheed Ahmed , 2019\n"
"Language-Team: Greek (https://app.transifex.com/open-edx/teams/6205/el/)\n"
@@ -199,7 +199,7 @@ msgid "Video"
msgstr ""
#: cms/djangoapps/contentstore/views/component.py xmodule/capa_block.py
-msgid "Blank Advanced Problem"
+msgid "Blank Problem"
msgstr ""
#: cms/djangoapps/contentstore/views/component.py
@@ -302,8 +302,8 @@ msgstr ""
#: common/djangoapps/course_modes/models.py xmodule/annotatable_block.py
#: xmodule/capa_block.py xmodule/conditional_block.py
#: xmodule/discussion_block.py xmodule/html_block.py
-#: xmodule/library_content_block.py xmodule/library_sourced_block.py
-#: xmodule/lti_block.py xmodule/split_test_block.py xmodule/unit_block.py
+#: xmodule/library_content_block.py xmodule/lti_block.py
+#: xmodule/split_test_block.py xmodule/unit_block.py
#: xmodule/word_cloud_block.py xmodule/x_module.py
#: cms/templates/container.html cms/templates/library.html
msgid "Display Name"
@@ -2880,6 +2880,12 @@ msgstr ""
msgid "Open Response Assessment"
msgstr ""
+#: lms/djangoapps/courseware/courses.py
+msgid ""
+"This Open Response Assessment's due dates are set by your instructor and "
+"can't be shifted."
+msgstr ""
+
#: lms/djangoapps/courseware/courses.py
msgid "Self Assessment"
msgstr ""
@@ -2896,12 +2902,6 @@ msgstr ""
msgid "Submission"
msgstr ""
-#: lms/djangoapps/courseware/courses.py
-msgid ""
-"Open Response Assessment due dates are set by your instructor and can't be "
-"shifted."
-msgstr ""
-
#. Translators: 'absolute' is a date such as "Jan 01,
#. 2020". 'relative' is a fuzzy description of the time until
#. 'absolute'. For example, 'absolute' might be "Jan 01, 2020",
@@ -5396,7 +5396,6 @@ msgstr ""
#: lms/templates/oauth2_provider/authorize.html
#: openedx/core/djangoapps/user_api/admin.py
-#: xmodule/templates/library-sourced-block-studio-view.html
#: cms/templates/course-create-rerun.html cms/templates/index.html
#: cms/templates/manage_users.html cms/templates/manage_users_lib.html
#: cms/templates/videos_index_pagination.html
@@ -5832,10 +5831,10 @@ msgid "Quotes"
msgstr ""
#: lms/templates/wiki/includes/editor_widget.html
-#, python-format
+#, python-brace-format
msgid ""
-"Markdown syntax is allowed. See the %(start_link)scheatsheet%(end_link)s for"
-" help."
+"Markdown syntax is allowed. See the {start_link}cheatsheet{end_link} for "
+"help."
msgstr ""
#: lms/templates/wiki/plugins/attachments/index.html
@@ -6783,8 +6782,8 @@ msgstr ""
#: openedx/core/djangoapps/discussions/models.py
msgid ""
-"The Posting availabilty in discussions whether it will be enabled, scheduled"
-" or indefinitely disabled."
+"The Posting availability in discussions whether it will be enabled, "
+"scheduled or indefinitely disabled."
msgstr ""
#: openedx/core/djangoapps/discussions/models.py
@@ -8646,8 +8645,7 @@ msgstr ""
#: xmodule/annotatable_block.py xmodule/capa_block.py
#: xmodule/conditional_block.py xmodule/discussion_block.py
#: xmodule/html_block.py xmodule/library_content_block.py
-#: xmodule/library_root_xblock.py xmodule/library_sourced_block.py
-#: xmodule/poll_block.py xmodule/unit_block.py
+#: xmodule/library_root_xblock.py xmodule/poll_block.py xmodule/unit_block.py
#: xmodule/video_block/video_xfields.py xmodule/word_cloud_block.py
#: xmodule/x_module.py
msgid "The display name for this component."
@@ -10635,33 +10633,6 @@ msgstr ""
msgid "Enter the names of the advanced components to use in your library."
msgstr ""
-#: xmodule/library_sourced_block.py
-msgid "Library Blocks List"
-msgstr ""
-
-#: xmodule/library_sourced_block.py
-msgid "Enter the IDs of the library XBlocks that you wish to use."
-msgstr ""
-
-#: xmodule/library_sourced_block.py
-#, python-brace-format
-msgid "A maximum of {0} components may be added."
-msgstr ""
-
-#: xmodule/library_sourced_block.py
-msgid ""
-"No XBlock has been configured for this component. Use the editor to select "
-"the target blocks."
-msgstr ""
-
-#: xmodule/library_sourced_block.py
-msgid "Open Editor"
-msgstr ""
-
-#: xmodule/library_sourced_block.py
-msgid "Importing Library Block failed - are the IDs valid and readable?"
-msgstr ""
-
#: xmodule/lti_block.py
msgid ""
"The display name for this component. Analytics reports may also use the "
@@ -11252,10 +11223,6 @@ msgstr ""
msgid "External Discussion"
msgstr ""
-#: xmodule/templates/library-sourced-block-studio-view.html
-msgid "Save and Import"
-msgstr ""
-
#: xmodule/vertical_block.py
msgid "Enable in-context discussions for the Unit"
msgstr ""
@@ -14765,10 +14732,6 @@ msgstr ""
msgid "Print or share your certificate:"
msgstr ""
-#: lms/templates/certificates/_accomplishment-banner.html
-msgid "Click the link to see my certificate."
-msgstr ""
-
#: lms/templates/certificates/_accomplishment-banner.html
msgid "Post on Facebook"
msgstr "Κοινοποιήστε στο Facebook"
diff --git a/conf/locale/el/LC_MESSAGES/djangojs.po b/conf/locale/el/LC_MESSAGES/djangojs.po
index 3611118bae2d..19025b0dd51b 100644
--- a/conf/locale/el/LC_MESSAGES/djangojs.po
+++ b/conf/locale/el/LC_MESSAGES/djangojs.po
@@ -87,7 +87,7 @@ msgid ""
msgstr ""
"Project-Id-Version: edx-platform\n"
"Report-Msgid-Bugs-To: openedx-translation@googlegroups.com\n"
-"POT-Creation-Date: 2023-08-27 20:42+0000\n"
+"POT-Creation-Date: 2023-09-17 20:42+0000\n"
"PO-Revision-Date: 2014-06-11 15:18+0000\n"
"Last-Translator: Angelos Chraniotis, 2023\n"
"Language-Team: Greek (http://app.transifex.com/open-edx/edx-platform/language/el/)\n"
@@ -98,14 +98,6 @@ msgstr ""
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
"Generated-By: Babel 2.8.0\n"
-#: cms/static/cms/js/main.js cms/static/js/views/active_video_upload_list.js
-#: cms/static/js/views/video_transcripts.js
-#: xmodule/assets/library_source_block/public/js/library_source_block.js
-msgid ""
-"This may be happening because of an error with our server or your internet "
-"connection. Try refreshing the page or making sure you are online."
-msgstr ""
-
#: cms/static/cms/js/xblock/cms.runtime.v1.js
#: cms/static/js/certificates/views/signatory_details.js
#: cms/static/js/models/section.js cms/static/js/utils/drag_and_drop.js
@@ -117,7 +109,6 @@ msgstr ""
#: cms/static/js/views/modals/edit_xblock.js cms/static/js/views/tabs.js
#: cms/static/js/views/utils/xblock_utils.js lms/static/js/ccx/schedule.js
#: lms/static/js/views/fields.js
-#: xmodule/assets/library_source_block/public/js/library_source_block.js
msgid "Saving"
msgstr "Αποθήκευση σε εξέλιξη"
@@ -3856,18 +3847,6 @@ msgstr ""
msgid "Updating with latest library content"
msgstr ""
-#: xmodule/assets/library_source_block/LibrarySourcedBlockPicker.jsx
-msgid "Loading..."
-msgstr ""
-
-#: xmodule/assets/library_source_block/LibrarySourcedBlockPicker.jsx
-msgid "Selected blocks"
-msgstr ""
-
-#: xmodule/assets/library_source_block/public/js/library_source_block.js
-msgid "Unable to update settings"
-msgstr ""
-
#: xmodule/assets/split_test/public/js/split_test_author_view.js
#: xmodule/js/public/js/split_test_author_view.js
msgid "Creating missing groups"
@@ -5497,6 +5476,13 @@ msgstr ""
msgid "Turn off transcripts"
msgstr ""
+#: cms/static/cms/js/main.js cms/static/js/views/active_video_upload_list.js
+#: cms/static/js/views/video_transcripts.js
+msgid ""
+"This may be happening because of an error with our server or your internet "
+"connection. Try refreshing the page or making sure you are online."
+msgstr ""
+
#: cms/static/cms/js/main.js
msgid "Studio's having trouble saving your work"
msgstr ""
@@ -6037,7 +6023,7 @@ msgstr ""
#: cms/static/js/views/course_outline.js
#: cms/static/js/views/pages/container.js
-msgid "New files were added to this course's Files & Uploads"
+msgid "New file(s) added to Files & Uploads."
msgstr ""
#: cms/static/js/views/course_outline.js
@@ -6045,6 +6031,16 @@ msgstr ""
msgid "The following required files were imported to this course:"
msgstr ""
+#: cms/static/js/views/course_outline.js
+#: cms/static/js/views/pages/container.js
+msgid "View files"
+msgstr ""
+
+#: cms/static/js/views/course_outline.js
+#: cms/static/js/views/pages/container.js
+msgid "Dismiss"
+msgstr ""
+
#: cms/static/js/views/course_rerun.js
msgid "Create Re-run"
msgstr ""
diff --git a/conf/locale/en/LC_MESSAGES/django.po b/conf/locale/en/LC_MESSAGES/django.po
index 05504dc5b457..b746467a6a79 100644
--- a/conf/locale/en/LC_MESSAGES/django.po
+++ b/conf/locale/en/LC_MESSAGES/django.po
@@ -38,8 +38,8 @@ msgid ""
msgstr ""
"Project-Id-Version: 0.1a\n"
"Report-Msgid-Bugs-To: openedx-translation@googlegroups.com\n"
-"POT-Creation-Date: 2023-09-05 15:59+0000\n"
-"PO-Revision-Date: 2023-09-05 15:59:41.440074\n"
+"POT-Creation-Date: 2023-09-24 20:36+0000\n"
+"PO-Revision-Date: 2023-09-24 20:36:20.303017\n"
"Last-Translator: \n"
"Language-Team: openedx-translation \n"
"Language: en\n"
@@ -139,7 +139,7 @@ msgid "Video"
msgstr ""
#: cms/djangoapps/contentstore/views/component.py xmodule/capa_block.py
-msgid "Blank Advanced Problem"
+msgid "Blank Problem"
msgstr ""
#: cms/djangoapps/contentstore/views/component.py
@@ -242,8 +242,8 @@ msgstr ""
#: common/djangoapps/course_modes/models.py xmodule/annotatable_block.py
#: xmodule/capa_block.py xmodule/conditional_block.py
#: xmodule/discussion_block.py xmodule/html_block.py
-#: xmodule/library_content_block.py xmodule/library_sourced_block.py
-#: xmodule/lti_block.py xmodule/split_test_block.py xmodule/unit_block.py
+#: xmodule/library_content_block.py xmodule/lti_block.py
+#: xmodule/split_test_block.py xmodule/unit_block.py
#: xmodule/word_cloud_block.py xmodule/x_module.py
#: cms/templates/container.html cms/templates/library.html
msgid "Display Name"
@@ -2741,6 +2741,12 @@ msgstr ""
msgid "Open Response Assessment"
msgstr ""
+#: lms/djangoapps/courseware/courses.py
+msgid ""
+"This Open Response Assessment's due dates are set by your instructor and "
+"can't be shifted."
+msgstr ""
+
#: lms/djangoapps/courseware/courses.py
msgid "Self Assessment"
msgstr ""
@@ -2757,12 +2763,6 @@ msgstr ""
msgid "Submission"
msgstr ""
-#: lms/djangoapps/courseware/courses.py
-msgid ""
-"Open Response Assessment due dates are set by your instructor and can't be "
-"shifted."
-msgstr ""
-
#. Translators: 'absolute' is a date such as "Jan 01,
#. 2020". 'relative' is a fuzzy description of the time until
#. 'absolute'. For example, 'absolute' might be "Jan 01, 2020",
@@ -5250,7 +5250,6 @@ msgstr ""
#: lms/templates/oauth2_provider/authorize.html
#: openedx/core/djangoapps/user_api/admin.py
-#: xmodule/templates/library-sourced-block-studio-view.html
#: cms/templates/course-create-rerun.html cms/templates/index.html
#: cms/templates/manage_users.html cms/templates/manage_users_lib.html
#: cms/templates/videos_index_pagination.html
@@ -6375,6 +6374,17 @@ msgstr ""
msgid "Original usage key/ID of the thing that is in the clipboard."
msgstr ""
+#: openedx/core/djangoapps/content_tagging/models/base.py
+#: wiki/models/article.py
+msgid "owner"
+msgstr ""
+
+#: openedx/core/djangoapps/content_tagging/models/base.py
+msgid ""
+"Organization that is related to this taxonomy.If None, then this taxonomy is"
+" related to all organizations."
+msgstr ""
+
#: openedx/core/djangoapps/cors_csrf/models.py
msgid ""
"List of domains that are allowed to make cross-domain requests to this site."
@@ -8170,16 +8180,6 @@ msgid ""
"to date."
msgstr ""
-#: openedx/features/content_tagging/models/base.py wiki/models/article.py
-msgid "owner"
-msgstr ""
-
-#: openedx/features/content_tagging/models/base.py
-msgid ""
-"Organization that is related to this taxonomy.If None, then this taxonomy is"
-" related to all organizations."
-msgstr ""
-
#: openedx/features/content_type_gating/models.py
#: openedx/features/course_duration_limits/models.py
#: lms/templates/support/feature_based_enrollments.html
@@ -8454,8 +8454,7 @@ msgstr ""
#: xmodule/annotatable_block.py xmodule/capa_block.py
#: xmodule/conditional_block.py xmodule/discussion_block.py
#: xmodule/html_block.py xmodule/library_content_block.py
-#: xmodule/library_root_xblock.py xmodule/library_sourced_block.py
-#: xmodule/poll_block.py xmodule/unit_block.py
+#: xmodule/library_root_xblock.py xmodule/poll_block.py xmodule/unit_block.py
#: xmodule/video_block/video_xfields.py xmodule/word_cloud_block.py
#: xmodule/x_module.py
msgid "The display name for this component."
@@ -10420,33 +10419,6 @@ msgstr ""
msgid "Enter the names of the advanced components to use in your library."
msgstr ""
-#: xmodule/library_sourced_block.py
-msgid "Library Blocks List"
-msgstr ""
-
-#: xmodule/library_sourced_block.py
-msgid "Enter the IDs of the library XBlocks that you wish to use."
-msgstr ""
-
-#: xmodule/library_sourced_block.py
-#, python-brace-format
-msgid "A maximum of {0} components may be added."
-msgstr ""
-
-#: xmodule/library_sourced_block.py
-msgid ""
-"No XBlock has been configured for this component. Use the editor to select "
-"the target blocks."
-msgstr ""
-
-#: xmodule/library_sourced_block.py
-msgid "Open Editor"
-msgstr ""
-
-#: xmodule/library_sourced_block.py
-msgid "Importing Library Block failed - are the IDs valid and readable?"
-msgstr ""
-
#: xmodule/lti_block.py
msgid ""
"The display name for this component. Analytics reports may also use the "
@@ -11036,10 +11008,6 @@ msgstr ""
msgid "External Discussion"
msgstr ""
-#: xmodule/templates/library-sourced-block-studio-view.html
-msgid "Save and Import"
-msgstr ""
-
#: xmodule/vertical_block.py
msgid "Enable in-context discussions for the Unit"
msgstr ""
@@ -14504,10 +14472,6 @@ msgstr ""
msgid "Print or share your certificate:"
msgstr ""
-#: lms/templates/certificates/_accomplishment-banner.html
-msgid "Click the link to see my certificate."
-msgstr ""
-
#: lms/templates/certificates/_accomplishment-banner.html
msgid "Post on Facebook"
msgstr ""
diff --git a/conf/locale/en/LC_MESSAGES/djangojs.po b/conf/locale/en/LC_MESSAGES/djangojs.po
index 6e047d8430fd..8c7acf64fbae 100644
--- a/conf/locale/en/LC_MESSAGES/djangojs.po
+++ b/conf/locale/en/LC_MESSAGES/djangojs.po
@@ -32,8 +32,8 @@ msgid ""
msgstr ""
"Project-Id-Version: 0.1a\n"
"Report-Msgid-Bugs-To: openedx-translation@googlegroups.com\n"
-"POT-Creation-Date: 2023-09-05 15:59+0000\n"
-"PO-Revision-Date: 2023-09-05 15:59:41.261194\n"
+"POT-Creation-Date: 2023-09-24 20:36+0000\n"
+"PO-Revision-Date: 2023-09-24 20:36:20.294880\n"
"Last-Translator: \n"
"Language-Team: openedx-translation \n"
"Language: en\n"
@@ -43,14 +43,6 @@ msgstr ""
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
"Generated-By: Babel 2.8.0\n"
-#: cms/static/cms/js/main.js cms/static/js/views/active_video_upload_list.js
-#: cms/static/js/views/video_transcripts.js
-#: xmodule/assets/library_source_block/public/js/library_source_block.js
-msgid ""
-"This may be happening because of an error with our server or your internet "
-"connection. Try refreshing the page or making sure you are online."
-msgstr ""
-
#: cms/static/cms/js/xblock/cms.runtime.v1.js
#: cms/static/js/certificates/views/signatory_details.js
#: cms/static/js/models/section.js cms/static/js/utils/drag_and_drop.js
@@ -62,7 +54,6 @@ msgstr ""
#: cms/static/js/views/modals/edit_xblock.js cms/static/js/views/tabs.js
#: cms/static/js/views/utils/xblock_utils.js lms/static/js/ccx/schedule.js
#: lms/static/js/views/fields.js
-#: xmodule/assets/library_source_block/public/js/library_source_block.js
msgid "Saving"
msgstr ""
@@ -3733,18 +3724,6 @@ msgstr ""
msgid "Updating with latest library content"
msgstr ""
-#: xmodule/assets/library_source_block/LibrarySourcedBlockPicker.jsx
-msgid "Loading..."
-msgstr ""
-
-#: xmodule/assets/library_source_block/LibrarySourcedBlockPicker.jsx
-msgid "Selected blocks"
-msgstr ""
-
-#: xmodule/assets/library_source_block/public/js/library_source_block.js
-msgid "Unable to update settings"
-msgstr ""
-
#: xmodule/assets/split_test/public/js/split_test_author_view.js
#: xmodule/js/public/js/split_test_author_view.js
msgid "Creating missing groups"
@@ -5364,6 +5343,13 @@ msgstr ""
msgid "Turn off transcripts"
msgstr ""
+#: cms/static/cms/js/main.js cms/static/js/views/active_video_upload_list.js
+#: cms/static/js/views/video_transcripts.js
+msgid ""
+"This may be happening because of an error with our server or your internet "
+"connection. Try refreshing the page or making sure you are online."
+msgstr ""
+
#: cms/static/cms/js/main.js
msgid "Studio's having trouble saving your work"
msgstr ""
@@ -5905,7 +5891,7 @@ msgstr ""
#: cms/static/js/views/course_outline.js
#: cms/static/js/views/pages/container.js
-msgid "New files were added to this course's Files & Uploads"
+msgid "New file(s) added to Files & Uploads."
msgstr ""
#: cms/static/js/views/course_outline.js
@@ -5913,6 +5899,16 @@ msgstr ""
msgid "The following required files were imported to this course:"
msgstr ""
+#: cms/static/js/views/course_outline.js
+#: cms/static/js/views/pages/container.js
+msgid "View files"
+msgstr ""
+
+#: cms/static/js/views/course_outline.js
+#: cms/static/js/views/pages/container.js
+msgid "Dismiss"
+msgstr ""
+
#: cms/static/js/views/course_rerun.js
msgid "Create Re-run"
msgstr ""
diff --git a/conf/locale/eo/LC_MESSAGES/django.mo b/conf/locale/eo/LC_MESSAGES/django.mo
index ba4322971b24..cd2f6b730384 100644
Binary files a/conf/locale/eo/LC_MESSAGES/django.mo and b/conf/locale/eo/LC_MESSAGES/django.mo differ
diff --git a/conf/locale/eo/LC_MESSAGES/django.po b/conf/locale/eo/LC_MESSAGES/django.po
index 6160209a0e6c..459f71da15a1 100644
--- a/conf/locale/eo/LC_MESSAGES/django.po
+++ b/conf/locale/eo/LC_MESSAGES/django.po
@@ -38,8 +38,8 @@ msgid ""
msgstr ""
"Project-Id-Version: 0.1a\n"
"Report-Msgid-Bugs-To: openedx-translation@googlegroups.com\n"
-"POT-Creation-Date: 2023-09-05 15:59+0000\n"
-"PO-Revision-Date: 2023-09-05 15:59:41.440074\n"
+"POT-Creation-Date: 2023-09-24 20:36+0000\n"
+"PO-Revision-Date: 2023-09-24 20:36:20.303017\n"
"Last-Translator: \n"
"Language-Team: openedx-translation \n"
"Language: eo\n"
@@ -145,8 +145,8 @@ msgid "Video"
msgstr "Vïdéö Ⱡ'σяєм ιρѕ#"
#: cms/djangoapps/contentstore/views/component.py xmodule/capa_block.py
-msgid "Blank Advanced Problem"
-msgstr "Blänk Àdvänçéd Prößlém Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢#"
+msgid "Blank Problem"
+msgstr "Blänk Prößlém Ⱡ'σяєм ιρѕυм ∂σłσя ѕι#"
#: cms/djangoapps/contentstore/views/component.py
#: xmodule/video_block/video_block.py
@@ -262,8 +262,8 @@ msgstr "Pröféssïönäl Éd Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт α#"
#: common/djangoapps/course_modes/models.py xmodule/annotatable_block.py
#: xmodule/capa_block.py xmodule/conditional_block.py
#: xmodule/discussion_block.py xmodule/html_block.py
-#: xmodule/library_content_block.py xmodule/library_sourced_block.py
-#: xmodule/lti_block.py xmodule/split_test_block.py xmodule/unit_block.py
+#: xmodule/library_content_block.py xmodule/lti_block.py
+#: xmodule/split_test_block.py xmodule/unit_block.py
#: xmodule/word_cloud_block.py xmodule/x_module.py
#: cms/templates/container.html cms/templates/library.html
msgid "Display Name"
@@ -3501,6 +3501,14 @@ msgstr "Àssïgnmént Ⱡ'σяєм ιρѕυм ∂σłσ#"
msgid "Open Response Assessment"
msgstr "Öpén Réspönsé Àsséssmént Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢ση#"
+#: lms/djangoapps/courseware/courses.py
+msgid ""
+"This Open Response Assessment's due dates are set by your instructor and "
+"can't be shifted."
+msgstr ""
+"Thïs Öpén Réspönsé Àsséssmént's düé dätés äré sét ßý ýöür ïnstrüçtör änd "
+"çän't ßé shïftéd. Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢σηѕ#"
+
#: lms/djangoapps/courseware/courses.py
msgid "Self Assessment"
msgstr "Sélf Àsséssmént Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт α#"
@@ -3517,14 +3525,6 @@ msgstr "Stäff Àsséssmént Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αм#"
msgid "Submission"
msgstr "Süßmïssïön Ⱡ'σяєм ιρѕυм ∂σłσ#"
-#: lms/djangoapps/courseware/courses.py
-msgid ""
-"Open Response Assessment due dates are set by your instructor and can't be "
-"shifted."
-msgstr ""
-"Öpén Réspönsé Àsséssmént düé dätés äré sét ßý ýöür ïnstrüçtör änd çän't ßé "
-"shïftéd. Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢σηѕє¢т#"
-
#. Translators: 'absolute' is a date such as "Jan 01,
#. 2020". 'relative' is a fuzzy description of the time until
#. 'absolute'. For example, 'absolute' might be "Jan 01, 2020",
@@ -6695,7 +6695,6 @@ msgstr ""
#: lms/templates/oauth2_provider/authorize.html
#: openedx/core/djangoapps/user_api/admin.py
-#: xmodule/templates/library-sourced-block-studio-view.html
#: cms/templates/course-create-rerun.html cms/templates/index.html
#: cms/templates/manage_users.html cms/templates/manage_users_lib.html
#: cms/templates/videos_index_pagination.html
@@ -8052,6 +8051,19 @@ msgstr ""
"Örïgïnäl üsägé kéý/ÌD öf thé thïng thät ïs ïn thé çlïpßöärd. Ⱡ'σяєм ιρѕυм "
"∂σłσя ѕιт αмєт, ¢σηѕє¢тєтυя α#"
+#: openedx/core/djangoapps/content_tagging/models/base.py
+#: wiki/models/article.py
+msgid "owner"
+msgstr "öwnér Ⱡ'σяєм ιρѕ#"
+
+#: openedx/core/djangoapps/content_tagging/models/base.py
+msgid ""
+"Organization that is related to this taxonomy.If None, then this taxonomy is"
+" related to all organizations."
+msgstr ""
+"Örgänïzätïön thät ïs rélätéd tö thïs täxönömý.Ìf Nöné, thén thïs täxönömý ïs"
+" rélätéd tö äll örgänïzätïöns. Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт #"
+
#: openedx/core/djangoapps/cors_csrf/models.py
msgid ""
"List of domains that are allowed to make cross-domain requests to this site."
@@ -10428,18 +10440,6 @@ msgstr ""
"Ýöü hävé süççéssfüllý shïftéd ýöür çöürsé sçhédülé änd ýöür çäléndär ïs üp "
"tö däté. Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢σηѕє¢т#"
-#: openedx/features/content_tagging/models/base.py wiki/models/article.py
-msgid "owner"
-msgstr "öwnér Ⱡ'σяєм ιρѕ#"
-
-#: openedx/features/content_tagging/models/base.py
-msgid ""
-"Organization that is related to this taxonomy.If None, then this taxonomy is"
-" related to all organizations."
-msgstr ""
-"Örgänïzätïön thät ïs rélätéd tö thïs täxönömý.Ìf Nöné, thén thïs täxönömý ïs"
-" rélätéd tö äll örgänïzätïöns. Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт #"
-
#: openedx/features/content_type_gating/models.py
#: openedx/features/course_duration_limits/models.py
#: lms/templates/support/feature_based_enrollments.html
@@ -10815,8 +10815,7 @@ msgstr "XML dätä för thé ännötätïön Ⱡ'σяєм ιρѕυм ∂σłσя
#: xmodule/annotatable_block.py xmodule/capa_block.py
#: xmodule/conditional_block.py xmodule/discussion_block.py
#: xmodule/html_block.py xmodule/library_content_block.py
-#: xmodule/library_root_xblock.py xmodule/library_sourced_block.py
-#: xmodule/poll_block.py xmodule/unit_block.py
+#: xmodule/library_root_xblock.py xmodule/poll_block.py xmodule/unit_block.py
#: xmodule/video_block/video_xfields.py xmodule/word_cloud_block.py
#: xmodule/x_module.py
msgid "The display name for this component."
@@ -13415,41 +13414,6 @@ msgstr ""
"Éntér thé nämés öf thé ädvänçéd çömpönénts tö üsé ïn ýöür lïßrärý. Ⱡ'σяєм "
"ιρѕυм ∂σłσя ѕιт αмєт, ¢σηѕє¢тєтυя #"
-#: xmodule/library_sourced_block.py
-msgid "Library Blocks List"
-msgstr "Lïßrärý Blöçks Lïst Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт,#"
-
-#: xmodule/library_sourced_block.py
-msgid "Enter the IDs of the library XBlocks that you wish to use."
-msgstr ""
-"Éntér thé ÌDs öf thé lïßrärý XBlöçks thät ýöü wïsh tö üsé. Ⱡ'σяєм ιρѕυм "
-"∂σłσя ѕιт αмєт, ¢σηѕє¢тєтυя α#"
-
-#: xmodule/library_sourced_block.py
-#, python-brace-format
-msgid "A maximum of {0} components may be added."
-msgstr ""
-"À mäxïmüm öf {0} çömpönénts mäý ßé äddéd. Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, "
-"¢σηѕє¢тєтυя #"
-
-#: xmodule/library_sourced_block.py
-msgid ""
-"No XBlock has been configured for this component. Use the editor to select "
-"the target blocks."
-msgstr ""
-"Nö XBlöçk häs ßéén çönfïgüréd för thïs çömpönént. Ûsé thé édïtör tö séléçt "
-"thé tärgét ßlöçks. Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢σ#"
-
-#: xmodule/library_sourced_block.py
-msgid "Open Editor"
-msgstr "Öpén Édïtör Ⱡ'σяєм ιρѕυм ∂σłσя #"
-
-#: xmodule/library_sourced_block.py
-msgid "Importing Library Block failed - are the IDs valid and readable?"
-msgstr ""
-"Ìmpörtïng Lïßrärý Blöçk fäïléd - äré thé ÌDs välïd änd réädäßlé? Ⱡ'σяєм "
-"ιρѕυм ∂σłσя ѕιт αмєт, ¢σηѕє¢тєтυя α#"
-
#: xmodule/lti_block.py
msgid ""
"The display name for this component. Analytics reports may also use the "
@@ -14268,10 +14232,6 @@ msgstr ""
msgid "External Discussion"
msgstr "Éxtérnäl Dïsçüssïön Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт,#"
-#: xmodule/templates/library-sourced-block-studio-view.html
-msgid "Save and Import"
-msgstr "Sävé änd Ìmpört Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт α#"
-
#: xmodule/vertical_block.py
msgid "Enable in-context discussions for the Unit"
msgstr ""
@@ -18686,12 +18646,6 @@ msgid "Print or share your certificate:"
msgstr ""
"Prïnt ör shäré ýöür çértïfïçäté: Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢σηѕє¢тє#"
-#: lms/templates/certificates/_accomplishment-banner.html
-msgid "Click the link to see my certificate."
-msgstr ""
-"Çlïçk thé lïnk tö séé mý çértïfïçäté. Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, "
-"¢σηѕє¢тєтυ#"
-
#: lms/templates/certificates/_accomplishment-banner.html
msgid "Post on Facebook"
msgstr "Pöst ön Fäçéßöök Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αм#"
diff --git a/conf/locale/eo/LC_MESSAGES/djangojs.mo b/conf/locale/eo/LC_MESSAGES/djangojs.mo
index 81c818d12de1..a037d84d765b 100644
Binary files a/conf/locale/eo/LC_MESSAGES/djangojs.mo and b/conf/locale/eo/LC_MESSAGES/djangojs.mo differ
diff --git a/conf/locale/eo/LC_MESSAGES/djangojs.po b/conf/locale/eo/LC_MESSAGES/djangojs.po
index 1fe23fa55d4a..981fb3c7383d 100644
--- a/conf/locale/eo/LC_MESSAGES/djangojs.po
+++ b/conf/locale/eo/LC_MESSAGES/djangojs.po
@@ -32,8 +32,8 @@ msgid ""
msgstr ""
"Project-Id-Version: 0.1a\n"
"Report-Msgid-Bugs-To: openedx-translation@googlegroups.com\n"
-"POT-Creation-Date: 2023-09-05 15:59+0000\n"
-"PO-Revision-Date: 2023-09-05 15:59:41.261194\n"
+"POT-Creation-Date: 2023-09-24 20:36+0000\n"
+"PO-Revision-Date: 2023-09-24 20:36:20.294880\n"
"Last-Translator: \n"
"Language-Team: openedx-translation \n"
"Language: eo\n"
@@ -43,22 +43,6 @@ msgstr ""
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
"Generated-By: Babel 2.8.0\n"
-#: cms/static/cms/js/main.js cms/static/js/views/active_video_upload_list.js
-#: cms/static/js/views/video_transcripts.js
-#: xmodule/assets/library_source_block/public/js/library_source_block.js
-msgid ""
-"This may be happening because of an error with our server or your internet "
-"connection. Try refreshing the page or making sure you are online."
-msgstr ""
-"Thïs mäý ßé häppénïng ßéçäüsé öf än érrör wïth öür sérvér ör ýöür ïntérnét "
-"çönnéçtïön. Trý réfréshïng thé pägé ör mäkïng süré ýöü äré önlïné. Ⱡ'σяєм "
-"ιρѕυм ∂σłσя ѕιт αмєт, ¢σηѕє¢тєтυя α∂ιριѕι¢ιηg єłιт, ѕє∂ ∂σ єιυѕмσ∂ тємρσя "
-"ιη¢ι∂ι∂υηт υт łαвσяє єт ∂σłσяє мαgηα αłιqυα. υт єηιм α∂ мιηιм νєηιαм, qυιѕ "
-"ησѕтяυ∂ єχєя¢ιтαтιση υłłαм¢σ łαвσяιѕ ηιѕι υт αłιqυιρ єχ єα ¢σммσ∂σ "
-"¢σηѕєqυαт. ∂υιѕ αυтє ιяυяє ∂σłσя ιη яєρяєнєη∂єяιт ιη νσłυρтαтє νєłιт єѕѕє "
-"¢ιłłυм ∂σłσяє єυ ƒυgιαт ηυłłα ραяιαтυя. єχ¢єρтєυя ѕιηт σ¢¢αє¢αт ¢υρι∂αтαт "
-"ηση ρяσι∂єηт, ѕυηт ιη ¢υłρα qυι σƒƒι¢ια ∂єѕєяυηт мσłłιт αηιм ι∂ єѕт #"
-
#: cms/static/cms/js/xblock/cms.runtime.v1.js
#: cms/static/js/certificates/views/signatory_details.js
#: cms/static/js/models/section.js cms/static/js/utils/drag_and_drop.js
@@ -70,7 +54,6 @@ msgstr ""
#: cms/static/js/views/modals/edit_xblock.js cms/static/js/views/tabs.js
#: cms/static/js/views/utils/xblock_utils.js lms/static/js/ccx/schedule.js
#: lms/static/js/views/fields.js
-#: xmodule/assets/library_source_block/public/js/library_source_block.js
msgid "Saving"
msgstr "Sävïng Ⱡ'σяєм ιρѕυ#"
@@ -4704,18 +4687,6 @@ msgstr ""
"Ûpdätïng wïth lätést lïßrärý çöntént Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, "
"¢σηѕє¢тєтυ#"
-#: xmodule/assets/library_source_block/LibrarySourcedBlockPicker.jsx
-msgid "Loading..."
-msgstr "Löädïng... Ⱡ'σяєм ιρѕυм ∂σłσ#"
-
-#: xmodule/assets/library_source_block/LibrarySourcedBlockPicker.jsx
-msgid "Selected blocks"
-msgstr "Séléçtéd ßlöçks Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт α#"
-
-#: xmodule/assets/library_source_block/public/js/library_source_block.js
-msgid "Unable to update settings"
-msgstr "Ûnäßlé tö üpdäté séttïngs Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢σηѕ#"
-
#: xmodule/assets/split_test/public/js/split_test_author_view.js
#: xmodule/js/public/js/split_test_author_view.js
msgid "Creating missing groups"
@@ -6441,6 +6412,21 @@ msgstr "Türn ön tränsçrïpts Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αм
msgid "Turn off transcripts"
msgstr "Türn öff tränsçrïpts Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, #"
+#: cms/static/cms/js/main.js cms/static/js/views/active_video_upload_list.js
+#: cms/static/js/views/video_transcripts.js
+msgid ""
+"This may be happening because of an error with our server or your internet "
+"connection. Try refreshing the page or making sure you are online."
+msgstr ""
+"Thïs mäý ßé häppénïng ßéçäüsé öf än érrör wïth öür sérvér ör ýöür ïntérnét "
+"çönnéçtïön. Trý réfréshïng thé pägé ör mäkïng süré ýöü äré önlïné. Ⱡ'σяєм "
+"ιρѕυм ∂σłσя ѕιт αмєт, ¢σηѕє¢тєтυя α∂ιριѕι¢ιηg єłιт, ѕє∂ ∂σ єιυѕмσ∂ тємρσя "
+"ιη¢ι∂ι∂υηт υт łαвσяє єт ∂σłσяє мαgηα αłιqυα. υт єηιм α∂ мιηιм νєηιαм, qυιѕ "
+"ησѕтяυ∂ єχєя¢ιтαтιση υłłαм¢σ łαвσяιѕ ηιѕι υт αłιqυιρ єχ єα ¢σммσ∂σ "
+"¢σηѕєqυαт. ∂υιѕ αυтє ιяυяє ∂σłσя ιη яєρяєнєη∂єяιт ιη νσłυρтαтє νєłιт єѕѕє "
+"¢ιłłυм ∂σłσяє єυ ƒυgιαт ηυłłα ραяιαтυя. єχ¢єρтєυя ѕιηт σ¢¢αє¢αт ¢υρι∂αтαт "
+"ηση ρяσι∂єηт, ѕυηт ιη ¢υłρα qυι σƒƒι¢ια ∂єѕєяυηт мσłłιт αηιм ι∂ єѕт #"
+
#: cms/static/cms/js/main.js
msgid "Studio's having trouble saving your work"
msgstr ""
@@ -7099,10 +7085,10 @@ msgstr ""
#: cms/static/js/views/course_outline.js
#: cms/static/js/views/pages/container.js
-msgid "New files were added to this course's Files & Uploads"
+msgid "New file(s) added to Files & Uploads."
msgstr ""
-"Néw fïlés wéré äddéd tö thïs çöürsé's Fïlés & Ûplöäds Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт"
-" αмєт, ¢σηѕє¢тєтυя α#"
+"Néw fïlé(s) äddéd tö Fïlés & Ûplöäds. Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, "
+"¢σηѕє¢тєтυ#"
#: cms/static/js/views/course_outline.js
#: cms/static/js/views/pages/container.js
@@ -7111,6 +7097,16 @@ msgstr ""
"Thé föllöwïng réqüïréd fïlés wéré ïmpörtéd tö thïs çöürsé: Ⱡ'σяєм ιρѕυм "
"∂σłσя ѕιт αмєт, ¢σηѕє¢тєтυя α#"
+#: cms/static/js/views/course_outline.js
+#: cms/static/js/views/pages/container.js
+msgid "View files"
+msgstr "Vïéw fïlés Ⱡ'σяєм ιρѕυм ∂σłσ#"
+
+#: cms/static/js/views/course_outline.js
+#: cms/static/js/views/pages/container.js
+msgid "Dismiss"
+msgstr "Dïsmïss Ⱡ'σяєм ιρѕυм #"
+
#: cms/static/js/views/course_rerun.js
msgid "Create Re-run"
msgstr "Çréäté Ré-rün Ⱡ'σяєм ιρѕυм ∂σłσя ѕι#"
diff --git a/conf/locale/es_419/LC_MESSAGES/django.mo b/conf/locale/es_419/LC_MESSAGES/django.mo
index 1da08893b840..e4fb596cebe3 100644
Binary files a/conf/locale/es_419/LC_MESSAGES/django.mo and b/conf/locale/es_419/LC_MESSAGES/django.mo differ
diff --git a/conf/locale/es_419/LC_MESSAGES/django.po b/conf/locale/es_419/LC_MESSAGES/django.po
index f4885b793207..78a6156a7a2a 100644
--- a/conf/locale/es_419/LC_MESSAGES/django.po
+++ b/conf/locale/es_419/LC_MESSAGES/django.po
@@ -82,6 +82,7 @@
# Paulina Rodriguez , 2020
# rcelaya , 2014
# rcelaya , 2014
+# Robert R , 2023
# Sarina Canelake , 2014-2015
# Ernesto Sánchez Benitez , 2016
# sebasco , 2014
@@ -295,7 +296,7 @@ msgid ""
msgstr ""
"Project-Id-Version: 0.1a\n"
"Report-Msgid-Bugs-To: openedx-translation@googlegroups.com\n"
-"POT-Creation-Date: 2023-08-20 20:42+0000\n"
+"POT-Creation-Date: 2023-09-10 20:42+0000\n"
"PO-Revision-Date: 2019-01-20 20:43+0000\n"
"Last-Translator: Albeiro Gonzalez , 2019\n"
"Language-Team: Spanish (Latin America) (https://app.transifex.com/open-edx/teams/6205/es_419/)\n"
@@ -398,8 +399,8 @@ msgid "Video"
msgstr "Video"
#: cms/djangoapps/contentstore/views/component.py xmodule/capa_block.py
-msgid "Blank Advanced Problem"
-msgstr "Problema avanzado genérico"
+msgid "Blank Problem"
+msgstr "Problema en blanco"
#: cms/djangoapps/contentstore/views/component.py
#: xmodule/video_block/video_block.py
@@ -504,8 +505,8 @@ msgstr "Profesional en educación"
#: common/djangoapps/course_modes/models.py xmodule/annotatable_block.py
#: xmodule/capa_block.py xmodule/conditional_block.py
#: xmodule/discussion_block.py xmodule/html_block.py
-#: xmodule/library_content_block.py xmodule/library_sourced_block.py
-#: xmodule/lti_block.py xmodule/split_test_block.py xmodule/unit_block.py
+#: xmodule/library_content_block.py xmodule/lti_block.py
+#: xmodule/split_test_block.py xmodule/unit_block.py
#: xmodule/word_cloud_block.py xmodule/x_module.py
#: cms/templates/container.html cms/templates/library.html
msgid "Display Name"
@@ -3399,6 +3400,14 @@ msgstr "Tarea"
msgid "Open Response Assessment"
msgstr "Calificación de respuestas abiertas"
+#: lms/djangoapps/courseware/courses.py
+msgid ""
+"This Open Response Assessment's due dates are set by your instructor and "
+"can't be shifted."
+msgstr ""
+"Las fechas límite de esta evaluación de respuesta abierta las establece su "
+"instructor y no se pueden cambiar."
+
#: lms/djangoapps/courseware/courses.py
msgid "Self Assessment"
msgstr "Auto revisión"
@@ -3415,14 +3424,6 @@ msgstr "Evaluación del equipo del curso"
msgid "Submission"
msgstr "Entrega"
-#: lms/djangoapps/courseware/courses.py
-msgid ""
-"Open Response Assessment due dates are set by your instructor and can't be "
-"shifted."
-msgstr ""
-"Las fechas límites para las pruebas de respuesta abierta serán establecidas "
-"por tu instructor y no podrán ser modificadas."
-
#. Translators: 'absolute' is a date such as "Jan 01,
#. 2020". 'relative' is a fuzzy description of the time until
#. 'absolute'. For example, 'absolute' might be "Jan 01, 2020",
@@ -6242,7 +6243,6 @@ msgstr ""
#: lms/templates/oauth2_provider/authorize.html
#: openedx/core/djangoapps/user_api/admin.py
-#: xmodule/templates/library-sourced-block-studio-view.html
#: cms/templates/course-create-rerun.html cms/templates/index.html
#: cms/templates/manage_users.html cms/templates/manage_users_lib.html
#: cms/templates/videos_index_pagination.html
@@ -6706,13 +6706,13 @@ msgid "Quotes"
msgstr "Citas"
#: lms/templates/wiki/includes/editor_widget.html
-#, python-format
+#, python-brace-format
msgid ""
-"Markdown syntax is allowed. See the %(start_link)scheatsheet%(end_link)s for"
-" help."
+"Markdown syntax is allowed. See the {start_link}cheatsheet{end_link} for "
+"help."
msgstr ""
-"Se permite la sintaxis de marcadores Markdown. Vea el %(start_link)sresumen "
-"de wiki%(end_link)s para más información."
+"Se permite la sintaxis de Markdown. Consulte la hoja de referencia "
+"{start_link} {end_link} para obtener ayuda."
#: lms/templates/wiki/plugins/attachments/index.html
#: wiki/plugins/attachments/templates/wiki/plugins/attachments/index.html
@@ -7772,11 +7772,11 @@ msgstr ""
#: openedx/core/djangoapps/discussions/models.py
msgid ""
-"The Posting availabilty in discussions whether it will be enabled, scheduled"
-" or indefinitely disabled."
+"The Posting availability in discussions whether it will be enabled, "
+"scheduled or indefinitely disabled."
msgstr ""
-"La disponibilidad de publicación en las discusiones si se habilitará, "
-"programará o deshabilitará indefinidamente."
+"La disponibilidad de publicación en discusiones sobre si estará habilitada, "
+"programada o deshabilitada indefinidamente."
#: openedx/core/djangoapps/discussions/models.py
msgid "The LTI configuration data for this context/provider."
@@ -7992,6 +7992,8 @@ msgid ""
"<{p}><{strong}>{username}{strong}> posted "
"<{strong}>{post_title}{strong}>{p}>"
msgstr ""
+"<{p}><{strong}>{username}{strong}> respondió a su publicación "
+"<{strong}>{post_title}{strong}>{p}>"
#: openedx/core/djangoapps/notifications/base_notification.py
#, python-brace-format
@@ -7999,6 +8001,8 @@ msgid ""
"<{p}><{strong}>{username}{strong}> asked "
"<{strong}>{post_title}{strong}>{p}>"
msgstr ""
+"<{p}><{strong}>{username}{strong}> preguntó "
+"<{strong}>{post_title}{strong}>{p}>"
#: openedx/core/djangoapps/notifications/base_notification.py
msgid ""
@@ -9882,8 +9886,7 @@ msgstr "Datos XML para la anotación"
#: xmodule/annotatable_block.py xmodule/capa_block.py
#: xmodule/conditional_block.py xmodule/discussion_block.py
#: xmodule/html_block.py xmodule/library_content_block.py
-#: xmodule/library_root_xblock.py xmodule/library_sourced_block.py
-#: xmodule/poll_block.py xmodule/unit_block.py
+#: xmodule/library_root_xblock.py xmodule/poll_block.py xmodule/unit_block.py
#: xmodule/video_block/video_xfields.py xmodule/word_cloud_block.py
#: xmodule/x_module.py
msgid "The display name for this component."
@@ -12186,37 +12189,6 @@ msgid "Enter the names of the advanced components to use in your library."
msgstr ""
"Ingrese el nombre de los componentes avanzados para utilizar en su Librería."
-#: xmodule/library_sourced_block.py
-msgid "Library Blocks List"
-msgstr "Lista de Bloques de Librería"
-
-#: xmodule/library_sourced_block.py
-msgid "Enter the IDs of the library XBlocks that you wish to use."
-msgstr "Ingresa los IDs de la librería XBlocks que deseas usar."
-
-#: xmodule/library_sourced_block.py
-#, python-brace-format
-msgid "A maximum of {0} components may be added."
-msgstr "Un máximo de {0} componentes pueden ser agregados."
-
-#: xmodule/library_sourced_block.py
-msgid ""
-"No XBlock has been configured for this component. Use the editor to select "
-"the target blocks."
-msgstr ""
-"No se ha configurado ningún XBlock para este componente. Utilice el editor "
-"para seleccionar el tipo de blocks. "
-
-#: xmodule/library_sourced_block.py
-msgid "Open Editor"
-msgstr "Abrir Editor"
-
-#: xmodule/library_sourced_block.py
-msgid "Importing Library Block failed - are the IDs valid and readable?"
-msgstr ""
-"Importanción de Libreria de Blocks fallida - ¿Estan correctas las "
-"identificaciones?"
-
#: xmodule/lti_block.py
msgid ""
"The display name for this component. Analytics reports may also use the "
@@ -12952,10 +12924,6 @@ msgstr ""
msgid "External Discussion"
msgstr "Discusión externa"
-#: xmodule/templates/library-sourced-block-studio-view.html
-msgid "Save and Import"
-msgstr "Guardar e Importar"
-
#: xmodule/vertical_block.py
msgid "Enable in-context discussions for the Unit"
msgstr "Habilita discusiones de contexto para la unidad."
@@ -17009,10 +16977,6 @@ msgstr "Descargar calificaciones de estudiantes"
msgid "Print or share your certificate:"
msgstr "Imprime o comparte tu certificado:"
-#: lms/templates/certificates/_accomplishment-banner.html
-msgid "Click the link to see my certificate."
-msgstr "Haz click en el enlace para ver mi certificado."
-
#: lms/templates/certificates/_accomplishment-banner.html
msgid "Post on Facebook"
msgstr "Compartir en Facebook"
diff --git a/conf/locale/es_419/LC_MESSAGES/djangojs.mo b/conf/locale/es_419/LC_MESSAGES/djangojs.mo
index f1f48686dbca..e22b2349dcef 100644
Binary files a/conf/locale/es_419/LC_MESSAGES/djangojs.mo and b/conf/locale/es_419/LC_MESSAGES/djangojs.mo differ
diff --git a/conf/locale/es_419/LC_MESSAGES/djangojs.po b/conf/locale/es_419/LC_MESSAGES/djangojs.po
index 933ac9575d00..81688ff41598 100644
--- a/conf/locale/es_419/LC_MESSAGES/djangojs.po
+++ b/conf/locale/es_419/LC_MESSAGES/djangojs.po
@@ -182,7 +182,7 @@ msgid ""
msgstr ""
"Project-Id-Version: edx-platform\n"
"Report-Msgid-Bugs-To: openedx-translation@googlegroups.com\n"
-"POT-Creation-Date: 2023-08-27 20:42+0000\n"
+"POT-Creation-Date: 2023-09-17 20:42+0000\n"
"PO-Revision-Date: 2014-06-11 15:18+0000\n"
"Last-Translator: Jesica Greco, 2023\n"
"Language-Team: Spanish (Latin America) (http://app.transifex.com/open-edx/edx-platform/language/es_419/)\n"
@@ -193,17 +193,6 @@ msgstr ""
"Plural-Forms: nplurals=3; plural=n == 1 ? 0 : n != 0 && n % 1000000 == 0 ? 1 : 2;\n"
"Generated-By: Babel 2.8.0\n"
-#: cms/static/cms/js/main.js cms/static/js/views/active_video_upload_list.js
-#: cms/static/js/views/video_transcripts.js
-#: xmodule/assets/library_source_block/public/js/library_source_block.js
-msgid ""
-"This may be happening because of an error with our server or your internet "
-"connection. Try refreshing the page or making sure you are online."
-msgstr ""
-"Esto puede estar sucediendo debido a un error con nuestros servidores o con "
-"tu conexión a Internet. Intenta refrescar la página o verifica tu acceso a "
-"Internet."
-
#: cms/static/cms/js/xblock/cms.runtime.v1.js
#: cms/static/js/certificates/views/signatory_details.js
#: cms/static/js/models/section.js cms/static/js/utils/drag_and_drop.js
@@ -215,7 +204,6 @@ msgstr ""
#: cms/static/js/views/modals/edit_xblock.js cms/static/js/views/tabs.js
#: cms/static/js/views/utils/xblock_utils.js lms/static/js/ccx/schedule.js
#: lms/static/js/views/fields.js
-#: xmodule/assets/library_source_block/public/js/library_source_block.js
msgid "Saving"
msgstr "Guardando"
@@ -4362,18 +4350,6 @@ msgstr "Perfil"
msgid "Updating with latest library content"
msgstr "Actualizando con el más reciente contenido de la librería"
-#: xmodule/assets/library_source_block/LibrarySourcedBlockPicker.jsx
-msgid "Loading..."
-msgstr "Cargando..."
-
-#: xmodule/assets/library_source_block/LibrarySourcedBlockPicker.jsx
-msgid "Selected blocks"
-msgstr "Bloques seleccionados"
-
-#: xmodule/assets/library_source_block/public/js/library_source_block.js
-msgid "Unable to update settings"
-msgstr "No es posible modificar las configuraciones"
-
#: xmodule/assets/split_test/public/js/split_test_author_view.js
#: xmodule/js/public/js/split_test_author_view.js
msgid "Creating missing groups"
@@ -6049,6 +6025,16 @@ msgstr "Activar transcripción"
msgid "Turn off transcripts"
msgstr "Desactivar transcripción"
+#: cms/static/cms/js/main.js cms/static/js/views/active_video_upload_list.js
+#: cms/static/js/views/video_transcripts.js
+msgid ""
+"This may be happening because of an error with our server or your internet "
+"connection. Try refreshing the page or making sure you are online."
+msgstr ""
+"Esto puede estar sucediendo debido a un error con nuestros servidores o con "
+"tu conexión a Internet. Intenta refrescar la página o verifica tu acceso a "
+"Internet."
+
#: cms/static/cms/js/main.js
msgid "Studio's having trouble saving your work"
msgstr "Studio tiene problemas para guardar tu trabajo"
@@ -6628,15 +6614,24 @@ msgstr ""
#: cms/static/js/views/course_outline.js
#: cms/static/js/views/pages/container.js
-msgid "New files were added to this course's Files & Uploads"
-msgstr ""
-"Se agregaron nuevos archivos a la sección Archivos y Cargas de este curso"
+msgid "New file(s) added to Files & Uploads."
+msgstr "Nuevos archivos agregados a Archivos y cargas."
#: cms/static/js/views/course_outline.js
#: cms/static/js/views/pages/container.js
msgid "The following required files were imported to this course:"
msgstr "Los siguientes archivos obligatorios no se pudieron agregar al curso:"
+#: cms/static/js/views/course_outline.js
+#: cms/static/js/views/pages/container.js
+msgid "View files"
+msgstr "Archivos de vista"
+
+#: cms/static/js/views/course_outline.js
+#: cms/static/js/views/pages/container.js
+msgid "Dismiss"
+msgstr "Descartar"
+
#: cms/static/js/views/course_rerun.js
msgid "Create Re-run"
msgstr "Crear reapertura"
diff --git a/conf/locale/eu_ES/LC_MESSAGES/django.mo b/conf/locale/eu_ES/LC_MESSAGES/django.mo
index b92e9dde1a75..a190293cb3df 100644
Binary files a/conf/locale/eu_ES/LC_MESSAGES/django.mo and b/conf/locale/eu_ES/LC_MESSAGES/django.mo differ
diff --git a/conf/locale/eu_ES/LC_MESSAGES/django.po b/conf/locale/eu_ES/LC_MESSAGES/django.po
index f4d99f3e1faf..022886794f09 100644
--- a/conf/locale/eu_ES/LC_MESSAGES/django.po
+++ b/conf/locale/eu_ES/LC_MESSAGES/django.po
@@ -64,7 +64,7 @@ msgid ""
msgstr ""
"Project-Id-Version: 0.1a\n"
"Report-Msgid-Bugs-To: openedx-translation@googlegroups.com\n"
-"POT-Creation-Date: 2023-08-27 20:43+0000\n"
+"POT-Creation-Date: 2023-09-17 20:43+0000\n"
"PO-Revision-Date: 2019-01-20 20:43+0000\n"
"Last-Translator: Abel Camacho , 2019\n"
"Language-Team: Basque (Spain) (https://app.transifex.com/open-edx/teams/6205/eu_ES/)\n"
@@ -168,8 +168,8 @@ msgid "Video"
msgstr "Bideoa"
#: cms/djangoapps/contentstore/views/component.py xmodule/capa_block.py
-msgid "Blank Advanced Problem"
-msgstr "Ariketa aurreratua hutsik"
+msgid "Blank Problem"
+msgstr ""
#: cms/djangoapps/contentstore/views/component.py
#: xmodule/video_block/video_block.py
@@ -271,8 +271,8 @@ msgstr "Hezkuntzako profesionala"
#: common/djangoapps/course_modes/models.py xmodule/annotatable_block.py
#: xmodule/capa_block.py xmodule/conditional_block.py
#: xmodule/discussion_block.py xmodule/html_block.py
-#: xmodule/library_content_block.py xmodule/library_sourced_block.py
-#: xmodule/lti_block.py xmodule/split_test_block.py xmodule/unit_block.py
+#: xmodule/library_content_block.py xmodule/lti_block.py
+#: xmodule/split_test_block.py xmodule/unit_block.py
#: xmodule/word_cloud_block.py xmodule/x_module.py
#: cms/templates/container.html cms/templates/library.html
msgid "Display Name"
@@ -2815,6 +2815,12 @@ msgstr ""
msgid "Open Response Assessment"
msgstr "Erantzun irekiko ebaluazioa"
+#: lms/djangoapps/courseware/courses.py
+msgid ""
+"This Open Response Assessment's due dates are set by your instructor and "
+"can't be shifted."
+msgstr ""
+
#: lms/djangoapps/courseware/courses.py
msgid "Self Assessment"
msgstr "Autoebaluazioa"
@@ -2831,12 +2837,6 @@ msgstr ""
msgid "Submission"
msgstr "Bidalketa"
-#: lms/djangoapps/courseware/courses.py
-msgid ""
-"Open Response Assessment due dates are set by your instructor and can't be "
-"shifted."
-msgstr ""
-
#. Translators: 'absolute' is a date such as "Jan 01,
#. 2020". 'relative' is a fuzzy description of the time until
#. 'absolute'. For example, 'absolute' might be "Jan 01, 2020",
@@ -5352,7 +5352,6 @@ msgstr ""
#: lms/templates/oauth2_provider/authorize.html
#: openedx/core/djangoapps/user_api/admin.py
-#: xmodule/templates/library-sourced-block-studio-view.html
#: cms/templates/course-create-rerun.html cms/templates/index.html
#: cms/templates/manage_users.html cms/templates/manage_users_lib.html
#: cms/templates/videos_index_pagination.html
@@ -5792,10 +5791,10 @@ msgid "Quotes"
msgstr "Aipamenak"
#: lms/templates/wiki/includes/editor_widget.html
-#, python-format
+#, python-brace-format
msgid ""
-"Markdown syntax is allowed. See the %(start_link)scheatsheet%(end_link)s for"
-" help."
+"Markdown syntax is allowed. See the {start_link}cheatsheet{end_link} for "
+"help."
msgstr ""
#: lms/templates/wiki/plugins/attachments/index.html
@@ -6744,8 +6743,8 @@ msgstr ""
#: openedx/core/djangoapps/discussions/models.py
msgid ""
-"The Posting availabilty in discussions whether it will be enabled, scheduled"
-" or indefinitely disabled."
+"The Posting availability in discussions whether it will be enabled, "
+"scheduled or indefinitely disabled."
msgstr ""
#: openedx/core/djangoapps/discussions/models.py
@@ -8581,8 +8580,7 @@ msgstr "XML datuak oharpenerako"
#: xmodule/annotatable_block.py xmodule/capa_block.py
#: xmodule/conditional_block.py xmodule/discussion_block.py
#: xmodule/html_block.py xmodule/library_content_block.py
-#: xmodule/library_root_xblock.py xmodule/library_sourced_block.py
-#: xmodule/poll_block.py xmodule/unit_block.py
+#: xmodule/library_root_xblock.py xmodule/poll_block.py xmodule/unit_block.py
#: xmodule/video_block/video_xfields.py xmodule/word_cloud_block.py
#: xmodule/x_module.py
msgid "The display name for this component."
@@ -10624,33 +10622,6 @@ msgstr "Erakutsiko den liburutegiaren izena"
msgid "Enter the names of the advanced components to use in your library."
msgstr "Idatzi zure liburutegian erabiliko diren osagai aurreratuen izenak."
-#: xmodule/library_sourced_block.py
-msgid "Library Blocks List"
-msgstr ""
-
-#: xmodule/library_sourced_block.py
-msgid "Enter the IDs of the library XBlocks that you wish to use."
-msgstr ""
-
-#: xmodule/library_sourced_block.py
-#, python-brace-format
-msgid "A maximum of {0} components may be added."
-msgstr ""
-
-#: xmodule/library_sourced_block.py
-msgid ""
-"No XBlock has been configured for this component. Use the editor to select "
-"the target blocks."
-msgstr ""
-
-#: xmodule/library_sourced_block.py
-msgid "Open Editor"
-msgstr ""
-
-#: xmodule/library_sourced_block.py
-msgid "Importing Library Block failed - are the IDs valid and readable?"
-msgstr ""
-
#: xmodule/lti_block.py
msgid ""
"The display name for this component. Analytics reports may also use the "
@@ -11255,10 +11226,6 @@ msgstr ""
msgid "External Discussion"
msgstr "Kanpoko eztabaida"
-#: xmodule/templates/library-sourced-block-studio-view.html
-msgid "Save and Import"
-msgstr ""
-
#: xmodule/vertical_block.py
msgid "Enable in-context discussions for the Unit"
msgstr ""
@@ -14756,10 +14723,6 @@ msgstr "Jaitsi ikaslearen kalifikazioak"
msgid "Print or share your certificate:"
msgstr "Inprimatu edo partekatu zure ziurtagiria:"
-#: lms/templates/certificates/_accomplishment-banner.html
-msgid "Click the link to see my certificate."
-msgstr "Sakatu estekari nire ziurtagiria ikusteko."
-
#: lms/templates/certificates/_accomplishment-banner.html
msgid "Post on Facebook"
msgstr "Mezua Facebook-en"
diff --git a/conf/locale/eu_ES/LC_MESSAGES/djangojs.mo b/conf/locale/eu_ES/LC_MESSAGES/djangojs.mo
index 4d226ec1d198..f87f26ca6ea1 100644
Binary files a/conf/locale/eu_ES/LC_MESSAGES/djangojs.mo and b/conf/locale/eu_ES/LC_MESSAGES/djangojs.mo differ
diff --git a/conf/locale/eu_ES/LC_MESSAGES/djangojs.po b/conf/locale/eu_ES/LC_MESSAGES/djangojs.po
index 49bacbc690ad..93b1d94852be 100644
--- a/conf/locale/eu_ES/LC_MESSAGES/djangojs.po
+++ b/conf/locale/eu_ES/LC_MESSAGES/djangojs.po
@@ -50,7 +50,7 @@ msgid ""
msgstr ""
"Project-Id-Version: edx-platform\n"
"Report-Msgid-Bugs-To: openedx-translation@googlegroups.com\n"
-"POT-Creation-Date: 2023-08-27 20:42+0000\n"
+"POT-Creation-Date: 2023-09-17 20:42+0000\n"
"PO-Revision-Date: 2014-06-11 15:18+0000\n"
"Last-Translator: Abel Camacho , 2017,2019-2020\n"
"Language-Team: Basque (Spain) (http://app.transifex.com/open-edx/edx-platform/language/eu_ES/)\n"
@@ -61,17 +61,6 @@ msgstr ""
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
"Generated-By: Babel 2.8.0\n"
-#: cms/static/cms/js/main.js cms/static/js/views/active_video_upload_list.js
-#: cms/static/js/views/video_transcripts.js
-#: xmodule/assets/library_source_block/public/js/library_source_block.js
-msgid ""
-"This may be happening because of an error with our server or your internet "
-"connection. Try refreshing the page or making sure you are online."
-msgstr ""
-"Zure zerbitzarearen edo zure interneteko konexioaren arazo batengatik "
-"gertatuko zen hau agian. Saiatu orria freskatzen eta ziurtatu on-line "
-"zaudela."
-
#: cms/static/cms/js/xblock/cms.runtime.v1.js
#: cms/static/js/certificates/views/signatory_details.js
#: cms/static/js/models/section.js cms/static/js/utils/drag_and_drop.js
@@ -83,7 +72,6 @@ msgstr ""
#: cms/static/js/views/modals/edit_xblock.js cms/static/js/views/tabs.js
#: cms/static/js/views/utils/xblock_utils.js lms/static/js/ccx/schedule.js
#: lms/static/js/views/fields.js
-#: xmodule/assets/library_source_block/public/js/library_source_block.js
msgid "Saving"
msgstr "Gordetzen"
@@ -3801,18 +3789,6 @@ msgstr "Profila"
msgid "Updating with latest library content"
msgstr "Liburutegiaren azken edukiarekin eguneratzen"
-#: xmodule/assets/library_source_block/LibrarySourcedBlockPicker.jsx
-msgid "Loading..."
-msgstr ""
-
-#: xmodule/assets/library_source_block/LibrarySourcedBlockPicker.jsx
-msgid "Selected blocks"
-msgstr ""
-
-#: xmodule/assets/library_source_block/public/js/library_source_block.js
-msgid "Unable to update settings"
-msgstr ""
-
#: xmodule/assets/split_test/public/js/split_test_author_view.js
#: xmodule/js/public/js/split_test_author_view.js
msgid "Creating missing groups"
@@ -5465,6 +5441,13 @@ msgstr "Gaitu transkripzioak"
msgid "Turn off transcripts"
msgstr "Desgaitu transkripzioak"
+#: cms/static/cms/js/main.js cms/static/js/views/active_video_upload_list.js
+#: cms/static/js/views/video_transcripts.js
+msgid ""
+"This may be happening because of an error with our server or your internet "
+"connection. Try refreshing the page or making sure you are online."
+msgstr ""
+
#: cms/static/cms/js/main.js
msgid "Studio's having trouble saving your work"
msgstr "Studiok arazoak ditu zure lana gordetzeko"
@@ -6014,7 +5997,7 @@ msgstr ""
#: cms/static/js/views/course_outline.js
#: cms/static/js/views/pages/container.js
-msgid "New files were added to this course's Files & Uploads"
+msgid "New file(s) added to Files & Uploads."
msgstr ""
#: cms/static/js/views/course_outline.js
@@ -6022,6 +6005,16 @@ msgstr ""
msgid "The following required files were imported to this course:"
msgstr ""
+#: cms/static/js/views/course_outline.js
+#: cms/static/js/views/pages/container.js
+msgid "View files"
+msgstr ""
+
+#: cms/static/js/views/course_outline.js
+#: cms/static/js/views/pages/container.js
+msgid "Dismiss"
+msgstr ""
+
#: cms/static/js/views/course_rerun.js
msgid "Create Re-run"
msgstr "Sortu ikastaroaren beste edizio bat"
diff --git a/conf/locale/fa_IR/LC_MESSAGES/django.mo b/conf/locale/fa_IR/LC_MESSAGES/django.mo
index 22927a24eb7f..715a732d5ba0 100644
Binary files a/conf/locale/fa_IR/LC_MESSAGES/django.mo and b/conf/locale/fa_IR/LC_MESSAGES/django.mo differ
diff --git a/conf/locale/fa_IR/LC_MESSAGES/django.po b/conf/locale/fa_IR/LC_MESSAGES/django.po
index 5dc74495fdf3..96738391aef7 100644
--- a/conf/locale/fa_IR/LC_MESSAGES/django.po
+++ b/conf/locale/fa_IR/LC_MESSAGES/django.po
@@ -134,7 +134,7 @@ msgid ""
msgstr ""
"Project-Id-Version: 0.1a\n"
"Report-Msgid-Bugs-To: openedx-translation@googlegroups.com\n"
-"POT-Creation-Date: 2023-08-13 20:42+0000\n"
+"POT-Creation-Date: 2023-09-03 20:43+0000\n"
"PO-Revision-Date: 2019-01-20 20:43+0000\n"
"Last-Translator: Somaye Joolaee, 2022\n"
"Language-Team: Persian (Iran) (https://app.transifex.com/open-edx/teams/6205/fa_IR/)\n"
@@ -235,8 +235,8 @@ msgid "Video"
msgstr "ویدیو"
#: cms/djangoapps/contentstore/views/component.py xmodule/capa_block.py
-msgid "Blank Advanced Problem"
-msgstr "مساله پیشرفته خالی"
+msgid "Blank Problem"
+msgstr ""
#: cms/djangoapps/contentstore/views/component.py
#: xmodule/video_block/video_block.py
@@ -340,8 +340,8 @@ msgstr "تحصیلات حرفهای"
#: common/djangoapps/course_modes/models.py xmodule/annotatable_block.py
#: xmodule/capa_block.py xmodule/conditional_block.py
#: xmodule/discussion_block.py xmodule/html_block.py
-#: xmodule/library_content_block.py xmodule/library_sourced_block.py
-#: xmodule/lti_block.py xmodule/split_test_block.py xmodule/unit_block.py
+#: xmodule/library_content_block.py xmodule/lti_block.py
+#: xmodule/split_test_block.py xmodule/unit_block.py
#: xmodule/word_cloud_block.py xmodule/x_module.py
#: cms/templates/container.html cms/templates/library.html
msgid "Display Name"
@@ -3119,6 +3119,12 @@ msgstr "تکلیف"
msgid "Open Response Assessment"
msgstr "سنجش باز پاسخ"
+#: lms/djangoapps/courseware/courses.py
+msgid ""
+"This Open Response Assessment's due dates are set by your instructor and "
+"can't be shifted."
+msgstr ""
+
#: lms/djangoapps/courseware/courses.py
msgid "Self Assessment"
msgstr "خودآزمایی"
@@ -3135,13 +3141,6 @@ msgstr "ارزیابی کارکنان"
msgid "Submission"
msgstr "تأکید"
-#: lms/djangoapps/courseware/courses.py
-msgid ""
-"Open Response Assessment due dates are set by your instructor and can't be "
-"shifted."
-msgstr ""
-"تاریخ تأیید ارزیابی پاسخ باز توسط مربی شما تعیین می شود و قابل تغییر نیست."
-
#. Translators: 'absolute' is a date such as "Jan 01,
#. 2020". 'relative' is a fuzzy description of the time until
#. 'absolute'. For example, 'absolute' might be "Jan 01, 2020",
@@ -5865,7 +5864,6 @@ msgstr ""
#: lms/templates/oauth2_provider/authorize.html
#: openedx/core/djangoapps/user_api/admin.py
-#: xmodule/templates/library-sourced-block-studio-view.html
#: cms/templates/course-create-rerun.html cms/templates/index.html
#: cms/templates/manage_users.html cms/templates/manage_users_lib.html
#: cms/templates/videos_index_pagination.html
@@ -6325,13 +6323,11 @@ msgid "Quotes"
msgstr "نقلقولها"
#: lms/templates/wiki/includes/editor_widget.html
-#, python-format
+#, python-brace-format
msgid ""
-"Markdown syntax is allowed. See the %(start_link)scheatsheet%(end_link)s for"
-" help."
+"Markdown syntax is allowed. See the {start_link}cheatsheet{end_link} for "
+"help."
msgstr ""
-"به کار بردن Markdown syntax مجاز است. برای راهنمایی %(start_link)sبرگههای "
-"آماده%(end_link)s را بببنید"
#: lms/templates/wiki/plugins/attachments/index.html
#: wiki/plugins/attachments/templates/wiki/plugins/attachments/index.html
@@ -7367,11 +7363,9 @@ msgstr ""
#: openedx/core/djangoapps/discussions/models.py
msgid ""
-"The Posting availabilty in discussions whether it will be enabled, scheduled"
-" or indefinitely disabled."
+"The Posting availability in discussions whether it will be enabled, "
+"scheduled or indefinitely disabled."
msgstr ""
-"در دسترس بودن ارسال در بحث فعال، برنامه ریزی شده یا به طور نامحدود غیرفعال "
-"می شود."
#: openedx/core/djangoapps/discussions/models.py
msgid "The LTI configuration data for this context/provider."
@@ -9418,8 +9412,7 @@ msgstr "داده های XML برای یادداشت"
#: xmodule/annotatable_block.py xmodule/capa_block.py
#: xmodule/conditional_block.py xmodule/discussion_block.py
#: xmodule/html_block.py xmodule/library_content_block.py
-#: xmodule/library_root_xblock.py xmodule/library_sourced_block.py
-#: xmodule/poll_block.py xmodule/unit_block.py
+#: xmodule/library_root_xblock.py xmodule/poll_block.py xmodule/unit_block.py
#: xmodule/video_block/video_xfields.py xmodule/word_cloud_block.py
#: xmodule/x_module.py
msgid "The display name for this component."
@@ -11664,35 +11657,6 @@ msgstr "نام نمایشی کتابخانه"
msgid "Enter the names of the advanced components to use in your library."
msgstr "نام مولفههای پیشرفته را برای استفاده در کتابخانه خود وارد کنید."
-#: xmodule/library_sourced_block.py
-msgid "Library Blocks List"
-msgstr "فهرست بلوکهای کتابخانه"
-
-#: xmodule/library_sourced_block.py
-msgid "Enter the IDs of the library XBlocks that you wish to use."
-msgstr "شناسههای XBlocks کتابخانهای را وارد کنید که مایلید استفاده کنید."
-
-#: xmodule/library_sourced_block.py
-#, python-brace-format
-msgid "A maximum of {0} components may be added."
-msgstr "ممکن است بیشینه {0} مؤلفه اضافه شود."
-
-#: xmodule/library_sourced_block.py
-msgid ""
-"No XBlock has been configured for this component. Use the editor to select "
-"the target blocks."
-msgstr ""
-"هیچ XBlock برای این مؤلفه پیکربندی نشدهاست. برای انتخاب بلوکهای هدف از "
-"ویرایشگر استفاده کنید."
-
-#: xmodule/library_sourced_block.py
-msgid "Open Editor"
-msgstr "گشودن ویرایشگر"
-
-#: xmodule/library_sourced_block.py
-msgid "Importing Library Block failed - are the IDs valid and readable?"
-msgstr "ورود بلوک کتابخانه موفق نبود- آیا شناسهها معتبر و قابلخواندن هستند؟"
-
#: xmodule/lti_block.py
msgid ""
"The display name for this component. Analytics reports may also use the "
@@ -12401,10 +12365,6 @@ msgstr ""
msgid "External Discussion"
msgstr "گفتگوی خارجی"
-#: xmodule/templates/library-sourced-block-studio-view.html
-msgid "Save and Import"
-msgstr "ذخیره و ورود"
-
#: xmodule/vertical_block.py
msgid "Enable in-context discussions for the Unit"
msgstr "گفتگوهای درونمتنی را برای این واحد فعال کنید"
@@ -16335,10 +16295,6 @@ msgstr "بارگذاری نمرات یادگیرنده"
msgid "Print or share your certificate:"
msgstr "تهیه نسخه چاپی یا اشتراکگذاری گواهینامه:"
-#: lms/templates/certificates/_accomplishment-banner.html
-msgid "Click the link to see my certificate."
-msgstr "روی پیوند کلیک کنید تا گواهینامه مرا ببینید."
-
#: lms/templates/certificates/_accomplishment-banner.html
msgid "Post on Facebook"
msgstr "انتشار در فیسبوک"
diff --git a/conf/locale/fa_IR/LC_MESSAGES/djangojs.mo b/conf/locale/fa_IR/LC_MESSAGES/djangojs.mo
index 6bbe54cb0e58..5b52193cdf0a 100644
Binary files a/conf/locale/fa_IR/LC_MESSAGES/djangojs.mo and b/conf/locale/fa_IR/LC_MESSAGES/djangojs.mo differ
diff --git a/conf/locale/fa_IR/LC_MESSAGES/djangojs.po b/conf/locale/fa_IR/LC_MESSAGES/djangojs.po
index 676b0e3d58c7..24db4fbf75a6 100644
--- a/conf/locale/fa_IR/LC_MESSAGES/djangojs.po
+++ b/conf/locale/fa_IR/LC_MESSAGES/djangojs.po
@@ -88,7 +88,7 @@ msgid ""
msgstr ""
"Project-Id-Version: edx-platform\n"
"Report-Msgid-Bugs-To: openedx-translation@googlegroups.com\n"
-"POT-Creation-Date: 2023-08-27 20:42+0000\n"
+"POT-Creation-Date: 2023-09-17 20:42+0000\n"
"PO-Revision-Date: 2014-06-11 15:18+0000\n"
"Last-Translator: SeyedMahdi Saeid , 2023\n"
"Language-Team: Persian (Iran) (http://app.transifex.com/open-edx/edx-platform/language/fa_IR/)\n"
@@ -99,16 +99,6 @@ msgstr ""
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
"Generated-By: Babel 2.8.0\n"
-#: cms/static/cms/js/main.js cms/static/js/views/active_video_upload_list.js
-#: cms/static/js/views/video_transcripts.js
-#: xmodule/assets/library_source_block/public/js/library_source_block.js
-msgid ""
-"This may be happening because of an error with our server or your internet "
-"connection. Try refreshing the page or making sure you are online."
-msgstr ""
-"عامل این اتفاق ممکن است سرور ما یا اتصال شما به اینترنت باشد. بار دیگر صفحه "
-"را باز کنید و یا از اتصال به اینترنت اطمینان حاصل نمایید."
-
#: cms/static/cms/js/xblock/cms.runtime.v1.js
#: cms/static/js/certificates/views/signatory_details.js
#: cms/static/js/models/section.js cms/static/js/utils/drag_and_drop.js
@@ -120,7 +110,6 @@ msgstr ""
#: cms/static/js/views/modals/edit_xblock.js cms/static/js/views/tabs.js
#: cms/static/js/views/utils/xblock_utils.js lms/static/js/ccx/schedule.js
#: lms/static/js/views/fields.js
-#: xmodule/assets/library_source_block/public/js/library_source_block.js
msgid "Saving"
msgstr "در حال ذخیرهسازی"
@@ -4141,18 +4130,6 @@ msgstr "پرونده کاربری"
msgid "Updating with latest library content"
msgstr "روزآمدسازی با آخرین محتوای کتابخانه"
-#: xmodule/assets/library_source_block/LibrarySourcedBlockPicker.jsx
-msgid "Loading..."
-msgstr "در حال بارگیری ..."
-
-#: xmodule/assets/library_source_block/LibrarySourcedBlockPicker.jsx
-msgid "Selected blocks"
-msgstr "بلوکهای منتخب"
-
-#: xmodule/assets/library_source_block/public/js/library_source_block.js
-msgid "Unable to update settings"
-msgstr "تنظیمات روزآمد نشد"
-
#: xmodule/assets/split_test/public/js/split_test_author_view.js
#: xmodule/js/public/js/split_test_author_view.js
msgid "Creating missing groups"
@@ -5814,6 +5791,13 @@ msgstr "فعالسازی زیرنویس"
msgid "Turn off transcripts"
msgstr "غیرفعالسازی زیرنویس"
+#: cms/static/cms/js/main.js cms/static/js/views/active_video_upload_list.js
+#: cms/static/js/views/video_transcripts.js
+msgid ""
+"This may be happening because of an error with our server or your internet "
+"connection. Try refreshing the page or making sure you are online."
+msgstr ""
+
#: cms/static/cms/js/main.js
msgid "Studio's having trouble saving your work"
msgstr "استودیو برای ذخیره کار شما مشکل دارد"
@@ -6378,14 +6362,24 @@ msgstr ""
#: cms/static/js/views/course_outline.js
#: cms/static/js/views/pages/container.js
-msgid "New files were added to this course's Files & Uploads"
-msgstr "فایل های جدید به \"فایل ها و آپلودها\"ی این دوره اضافه شد"
+msgid "New file(s) added to Files & Uploads."
+msgstr ""
#: cms/static/js/views/course_outline.js
#: cms/static/js/views/pages/container.js
msgid "The following required files were imported to this course:"
msgstr "فایل های مورد نیاز زیر به این دوره وارد شدند:"
+#: cms/static/js/views/course_outline.js
+#: cms/static/js/views/pages/container.js
+msgid "View files"
+msgstr ""
+
+#: cms/static/js/views/course_outline.js
+#: cms/static/js/views/pages/container.js
+msgid "Dismiss"
+msgstr ""
+
#: cms/static/js/views/course_rerun.js
msgid "Create Re-run"
msgstr "اجرای دوباره را فعال کنید"
diff --git a/conf/locale/fr/LC_MESSAGES/django.mo b/conf/locale/fr/LC_MESSAGES/django.mo
index 391d24e36d45..591585f86349 100644
Binary files a/conf/locale/fr/LC_MESSAGES/django.mo and b/conf/locale/fr/LC_MESSAGES/django.mo differ
diff --git a/conf/locale/fr/LC_MESSAGES/django.po b/conf/locale/fr/LC_MESSAGES/django.po
index 1d7dd80ce7ed..4278151bbf14 100644
--- a/conf/locale/fr/LC_MESSAGES/django.po
+++ b/conf/locale/fr/LC_MESSAGES/django.po
@@ -316,7 +316,7 @@ msgid ""
msgstr ""
"Project-Id-Version: 0.1a\n"
"Report-Msgid-Bugs-To: openedx-translation@googlegroups.com\n"
-"POT-Creation-Date: 2023-08-27 20:43+0000\n"
+"POT-Creation-Date: 2023-09-17 20:43+0000\n"
"PO-Revision-Date: 2019-01-20 20:43+0000\n"
"Last-Translator: Alexandre DS , 2020\n"
"Language-Team: French (https://app.transifex.com/open-edx/teams/6205/fr/)\n"
@@ -419,8 +419,8 @@ msgid "Video"
msgstr "Vidéo"
#: cms/djangoapps/contentstore/views/component.py xmodule/capa_block.py
-msgid "Blank Advanced Problem"
-msgstr "Problème avancé vierge"
+msgid "Blank Problem"
+msgstr ""
#: cms/djangoapps/contentstore/views/component.py
#: xmodule/video_block/video_block.py
@@ -526,8 +526,8 @@ msgstr "Professionnel de l'éducation"
#: common/djangoapps/course_modes/models.py xmodule/annotatable_block.py
#: xmodule/capa_block.py xmodule/conditional_block.py
#: xmodule/discussion_block.py xmodule/html_block.py
-#: xmodule/library_content_block.py xmodule/library_sourced_block.py
-#: xmodule/lti_block.py xmodule/split_test_block.py xmodule/unit_block.py
+#: xmodule/library_content_block.py xmodule/lti_block.py
+#: xmodule/split_test_block.py xmodule/unit_block.py
#: xmodule/word_cloud_block.py xmodule/x_module.py
#: cms/templates/container.html cms/templates/library.html
msgid "Display Name"
@@ -3419,6 +3419,12 @@ msgstr "Devoir"
msgid "Open Response Assessment"
msgstr "Évaluation par les pairs"
+#: lms/djangoapps/courseware/courses.py
+msgid ""
+"This Open Response Assessment's due dates are set by your instructor and "
+"can't be shifted."
+msgstr ""
+
#: lms/djangoapps/courseware/courses.py
msgid "Self Assessment"
msgstr "Auto-évaluation"
@@ -3435,14 +3441,6 @@ msgstr "Evaluation par l'équipe pédagogique"
msgid "Submission"
msgstr "Soumission"
-#: lms/djangoapps/courseware/courses.py
-msgid ""
-"Open Response Assessment due dates are set by your instructor and can't be "
-"shifted."
-msgstr ""
-"Les dates limites de Open Response Assessment sont prescrits par votre "
-"instructeur et ne peuvent pas être modifiés."
-
#. Translators: 'absolute' is a date such as "Jan 01,
#. 2020". 'relative' is a fuzzy description of the time until
#. 'absolute'. For example, 'absolute' might be "Jan 01, 2020",
@@ -6251,7 +6249,6 @@ msgstr ""
#: lms/templates/oauth2_provider/authorize.html
#: openedx/core/djangoapps/user_api/admin.py
-#: xmodule/templates/library-sourced-block-studio-view.html
#: cms/templates/course-create-rerun.html cms/templates/index.html
#: cms/templates/manage_users.html cms/templates/manage_users_lib.html
#: cms/templates/videos_index_pagination.html
@@ -6721,13 +6718,11 @@ msgid "Quotes"
msgstr "Citations"
#: lms/templates/wiki/includes/editor_widget.html
-#, python-format
+#, python-brace-format
msgid ""
-"Markdown syntax is allowed. See the %(start_link)scheatsheet%(end_link)s for"
-" help."
+"Markdown syntax is allowed. See the {start_link}cheatsheet{end_link} for "
+"help."
msgstr ""
-"La syntaxe Markdown est autorisée. Lisez l' "
-"%(start_link)santiséche%(end_link)s pour avoir de l'aide."
#: lms/templates/wiki/plugins/attachments/index.html
#: wiki/plugins/attachments/templates/wiki/plugins/attachments/index.html
@@ -7783,8 +7778,8 @@ msgstr ""
#: openedx/core/djangoapps/discussions/models.py
msgid ""
-"The Posting availabilty in discussions whether it will be enabled, scheduled"
-" or indefinitely disabled."
+"The Posting availability in discussions whether it will be enabled, "
+"scheduled or indefinitely disabled."
msgstr ""
#: openedx/core/djangoapps/discussions/models.py
@@ -9882,8 +9877,7 @@ msgstr "données XML pour l'annotation"
#: xmodule/annotatable_block.py xmodule/capa_block.py
#: xmodule/conditional_block.py xmodule/discussion_block.py
#: xmodule/html_block.py xmodule/library_content_block.py
-#: xmodule/library_root_xblock.py xmodule/library_sourced_block.py
-#: xmodule/poll_block.py xmodule/unit_block.py
+#: xmodule/library_root_xblock.py xmodule/poll_block.py xmodule/unit_block.py
#: xmodule/video_block/video_xfields.py xmodule/word_cloud_block.py
#: xmodule/x_module.py
msgid "The display name for this component."
@@ -12171,37 +12165,6 @@ msgid "Enter the names of the advanced components to use in your library."
msgstr ""
"Entrer les noms des composants avancés à utiliser dans votre bibliothèque."
-#: xmodule/library_sourced_block.py
-msgid "Library Blocks List"
-msgstr "Liste des blocs de la bibliothèque"
-
-#: xmodule/library_sourced_block.py
-msgid "Enter the IDs of the library XBlocks that you wish to use."
-msgstr "Entrez les ID de la bibliothèque XBlocks que vous souhaitez utiliser."
-
-#: xmodule/library_sourced_block.py
-#, python-brace-format
-msgid "A maximum of {0} components may be added."
-msgstr "Un maximum de {0} composants peut être ajouté."
-
-#: xmodule/library_sourced_block.py
-msgid ""
-"No XBlock has been configured for this component. Use the editor to select "
-"the target blocks."
-msgstr ""
-"Aucun XBlock n'a été configuré pour ce composant. Utilisez l'éditeur pour "
-"sélectionner les blocs cibles."
-
-#: xmodule/library_sourced_block.py
-msgid "Open Editor"
-msgstr "Ouvrir l'éditeur"
-
-#: xmodule/library_sourced_block.py
-msgid "Importing Library Block failed - are the IDs valid and readable?"
-msgstr ""
-"Échec de l'importation du Bloc Bibliothèque - est-ce que les ID sont valides"
-" et lisibles?"
-
#: xmodule/lti_block.py
msgid ""
"The display name for this component. Analytics reports may also use the "
@@ -12930,10 +12893,6 @@ msgstr ""
msgid "External Discussion"
msgstr "Discussion externe"
-#: xmodule/templates/library-sourced-block-studio-view.html
-msgid "Save and Import"
-msgstr "Enregistrer et importer"
-
#: xmodule/vertical_block.py
msgid "Enable in-context discussions for the Unit"
msgstr "Activer les discussions contextuelles pour cet unité"
@@ -17007,10 +16966,6 @@ msgstr "Télécharger les notes des étudiants"
msgid "Print or share your certificate:"
msgstr "Imprimer ou partager votre certificat:"
-#: lms/templates/certificates/_accomplishment-banner.html
-msgid "Click the link to see my certificate."
-msgstr "Cliquer sur le lien pour voir mon certificat."
-
#: lms/templates/certificates/_accomplishment-banner.html
msgid "Post on Facebook"
msgstr "Poster sur Facebook"
diff --git a/conf/locale/fr/LC_MESSAGES/djangojs.mo b/conf/locale/fr/LC_MESSAGES/djangojs.mo
index f464597ec51c..d9affed43100 100644
Binary files a/conf/locale/fr/LC_MESSAGES/djangojs.mo and b/conf/locale/fr/LC_MESSAGES/djangojs.mo differ
diff --git a/conf/locale/fr/LC_MESSAGES/djangojs.po b/conf/locale/fr/LC_MESSAGES/djangojs.po
index 668890055d81..ea4134d7730f 100644
--- a/conf/locale/fr/LC_MESSAGES/djangojs.po
+++ b/conf/locale/fr/LC_MESSAGES/djangojs.po
@@ -220,7 +220,7 @@ msgid ""
msgstr ""
"Project-Id-Version: edx-platform\n"
"Report-Msgid-Bugs-To: openedx-translation@googlegroups.com\n"
-"POT-Creation-Date: 2023-08-27 20:42+0000\n"
+"POT-Creation-Date: 2023-09-17 20:42+0000\n"
"PO-Revision-Date: 2014-06-11 15:18+0000\n"
"Last-Translator: Pierre Mailhot , 2023\n"
"Language-Team: French (http://app.transifex.com/open-edx/edx-platform/language/fr/)\n"
@@ -231,17 +231,6 @@ msgstr ""
"Plural-Forms: nplurals=3; plural=(n == 0 || n == 1) ? 0 : n != 0 && n % 1000000 == 0 ? 1 : 2;\n"
"Generated-By: Babel 2.8.0\n"
-#: cms/static/cms/js/main.js cms/static/js/views/active_video_upload_list.js
-#: cms/static/js/views/video_transcripts.js
-#: xmodule/assets/library_source_block/public/js/library_source_block.js
-msgid ""
-"This may be happening because of an error with our server or your internet "
-"connection. Try refreshing the page or making sure you are online."
-msgstr ""
-"Cet incident vous affecte à cause d'une erreur sur notre serveur ou d'un "
-"problème de votre connexion internet. Essayez de rafraîchir la page ou "
-"vérifiez que votre connexion est bien active."
-
#: cms/static/cms/js/xblock/cms.runtime.v1.js
#: cms/static/js/certificates/views/signatory_details.js
#: cms/static/js/models/section.js cms/static/js/utils/drag_and_drop.js
@@ -253,7 +242,6 @@ msgstr ""
#: cms/static/js/views/modals/edit_xblock.js cms/static/js/views/tabs.js
#: cms/static/js/views/utils/xblock_utils.js lms/static/js/ccx/schedule.js
#: lms/static/js/views/fields.js
-#: xmodule/assets/library_source_block/public/js/library_source_block.js
msgid "Saving"
msgstr "Enregistrement en cours"
@@ -4395,18 +4383,6 @@ msgstr "Profil"
msgid "Updating with latest library content"
msgstr "Mise à jour des derniers ajouts à la bibliothèque"
-#: xmodule/assets/library_source_block/LibrarySourcedBlockPicker.jsx
-msgid "Loading..."
-msgstr ""
-
-#: xmodule/assets/library_source_block/LibrarySourcedBlockPicker.jsx
-msgid "Selected blocks"
-msgstr ""
-
-#: xmodule/assets/library_source_block/public/js/library_source_block.js
-msgid "Unable to update settings"
-msgstr "Impossible de mettre à jours les paramètres"
-
#: xmodule/assets/split_test/public/js/split_test_author_view.js
#: xmodule/js/public/js/split_test_author_view.js
msgid "Creating missing groups"
@@ -6083,6 +6059,13 @@ msgstr "Activer la transcription"
msgid "Turn off transcripts"
msgstr "Désactiver la transcription"
+#: cms/static/cms/js/main.js cms/static/js/views/active_video_upload_list.js
+#: cms/static/js/views/video_transcripts.js
+msgid ""
+"This may be happening because of an error with our server or your internet "
+"connection. Try refreshing the page or making sure you are online."
+msgstr ""
+
#: cms/static/cms/js/main.js
msgid "Studio's having trouble saving your work"
msgstr "Studio a des problèmes pour sauvegarder votre travail"
@@ -6667,7 +6650,7 @@ msgstr ""
#: cms/static/js/views/course_outline.js
#: cms/static/js/views/pages/container.js
-msgid "New files were added to this course's Files & Uploads"
+msgid "New file(s) added to Files & Uploads."
msgstr ""
#: cms/static/js/views/course_outline.js
@@ -6675,6 +6658,16 @@ msgstr ""
msgid "The following required files were imported to this course:"
msgstr ""
+#: cms/static/js/views/course_outline.js
+#: cms/static/js/views/pages/container.js
+msgid "View files"
+msgstr ""
+
+#: cms/static/js/views/course_outline.js
+#: cms/static/js/views/pages/container.js
+msgid "Dismiss"
+msgstr ""
+
#: cms/static/js/views/course_rerun.js
msgid "Create Re-run"
msgstr "Créer une relance"
diff --git a/conf/locale/id/LC_MESSAGES/django.mo b/conf/locale/id/LC_MESSAGES/django.mo
index 190c25838327..3ad0a149eb11 100644
Binary files a/conf/locale/id/LC_MESSAGES/django.mo and b/conf/locale/id/LC_MESSAGES/django.mo differ
diff --git a/conf/locale/id/LC_MESSAGES/django.po b/conf/locale/id/LC_MESSAGES/django.po
index 5ba6639ee79d..b83ecbae8309 100644
--- a/conf/locale/id/LC_MESSAGES/django.po
+++ b/conf/locale/id/LC_MESSAGES/django.po
@@ -106,7 +106,7 @@ msgid ""
msgstr ""
"Project-Id-Version: 0.1a\n"
"Report-Msgid-Bugs-To: openedx-translation@googlegroups.com\n"
-"POT-Creation-Date: 2023-08-27 20:43+0000\n"
+"POT-Creation-Date: 2023-09-17 20:43+0000\n"
"PO-Revision-Date: 2019-01-20 20:43+0000\n"
"Last-Translator: Aprisa Chrysantina , 2019\n"
"Language-Team: Indonesian (https://app.transifex.com/open-edx/teams/6205/id/)\n"
@@ -206,8 +206,8 @@ msgid "Video"
msgstr "Video"
#: cms/djangoapps/contentstore/views/component.py xmodule/capa_block.py
-msgid "Blank Advanced Problem"
-msgstr "Permasalahan Lanjut Kosong"
+msgid "Blank Problem"
+msgstr ""
#: cms/djangoapps/contentstore/views/component.py
#: xmodule/video_block/video_block.py
@@ -312,8 +312,8 @@ msgstr "Edukasi Profesional"
#: common/djangoapps/course_modes/models.py xmodule/annotatable_block.py
#: xmodule/capa_block.py xmodule/conditional_block.py
#: xmodule/discussion_block.py xmodule/html_block.py
-#: xmodule/library_content_block.py xmodule/library_sourced_block.py
-#: xmodule/lti_block.py xmodule/split_test_block.py xmodule/unit_block.py
+#: xmodule/library_content_block.py xmodule/lti_block.py
+#: xmodule/split_test_block.py xmodule/unit_block.py
#: xmodule/word_cloud_block.py xmodule/x_module.py
#: cms/templates/container.html cms/templates/library.html
msgid "Display Name"
@@ -2937,6 +2937,12 @@ msgstr ""
msgid "Open Response Assessment"
msgstr ""
+#: lms/djangoapps/courseware/courses.py
+msgid ""
+"This Open Response Assessment's due dates are set by your instructor and "
+"can't be shifted."
+msgstr ""
+
#: lms/djangoapps/courseware/courses.py
msgid "Self Assessment"
msgstr ""
@@ -2953,12 +2959,6 @@ msgstr ""
msgid "Submission"
msgstr ""
-#: lms/djangoapps/courseware/courses.py
-msgid ""
-"Open Response Assessment due dates are set by your instructor and can't be "
-"shifted."
-msgstr ""
-
#. Translators: 'absolute' is a date such as "Jan 01,
#. 2020". 'relative' is a fuzzy description of the time until
#. 'absolute'. For example, 'absolute' might be "Jan 01, 2020",
@@ -5568,7 +5568,6 @@ msgstr ""
#: lms/templates/oauth2_provider/authorize.html
#: openedx/core/djangoapps/user_api/admin.py
-#: xmodule/templates/library-sourced-block-studio-view.html
msgid "Cancel"
msgstr "Batalkan"
@@ -6013,10 +6012,10 @@ msgid "Quotes"
msgstr "Kutipan"
#: lms/templates/wiki/includes/editor_widget.html
-#, python-format
+#, python-brace-format
msgid ""
-"Markdown syntax is allowed. See the %(start_link)scheatsheet%(end_link)s for"
-" help."
+"Markdown syntax is allowed. See the {start_link}cheatsheet{end_link} for "
+"help."
msgstr ""
#: lms/templates/wiki/plugins/attachments/index.html
@@ -6972,8 +6971,8 @@ msgstr ""
#: openedx/core/djangoapps/discussions/models.py
msgid ""
-"The Posting availabilty in discussions whether it will be enabled, scheduled"
-" or indefinitely disabled."
+"The Posting availability in discussions whether it will be enabled, "
+"scheduled or indefinitely disabled."
msgstr ""
#: openedx/core/djangoapps/discussions/models.py
@@ -8852,8 +8851,7 @@ msgstr "Data XML untuk anotasi"
#: xmodule/annotatable_block.py xmodule/capa_block.py
#: xmodule/conditional_block.py xmodule/discussion_block.py
#: xmodule/html_block.py xmodule/library_content_block.py
-#: xmodule/library_root_xblock.py xmodule/library_sourced_block.py
-#: xmodule/poll_block.py xmodule/unit_block.py
+#: xmodule/library_root_xblock.py xmodule/poll_block.py xmodule/unit_block.py
#: xmodule/video_block/video_xfields.py xmodule/word_cloud_block.py
#: xmodule/x_module.py
msgid "The display name for this component."
@@ -11041,33 +11039,6 @@ msgstr "Nama Tampilan Library"
msgid "Enter the names of the advanced components to use in your library."
msgstr "Masukkan nama komponen lanjutan untuk digunakan di perpustakaan Anda."
-#: xmodule/library_sourced_block.py
-msgid "Library Blocks List"
-msgstr ""
-
-#: xmodule/library_sourced_block.py
-msgid "Enter the IDs of the library XBlocks that you wish to use."
-msgstr ""
-
-#: xmodule/library_sourced_block.py
-#, python-brace-format
-msgid "A maximum of {0} components may be added."
-msgstr ""
-
-#: xmodule/library_sourced_block.py
-msgid ""
-"No XBlock has been configured for this component. Use the editor to select "
-"the target blocks."
-msgstr ""
-
-#: xmodule/library_sourced_block.py
-msgid "Open Editor"
-msgstr ""
-
-#: xmodule/library_sourced_block.py
-msgid "Importing Library Block failed - are the IDs valid and readable?"
-msgstr ""
-
#: xmodule/lti_block.py
msgid ""
"The display name for this component. Analytics reports may also use the "
@@ -11756,10 +11727,6 @@ msgstr ""
msgid "External Discussion"
msgstr "Diskusi Eksternal"
-#: xmodule/templates/library-sourced-block-studio-view.html
-msgid "Save and Import"
-msgstr ""
-
#: xmodule/vertical_block.py
msgid "Enable in-context discussions for the Unit"
msgstr ""
@@ -15659,10 +15626,6 @@ msgstr "Unduh nilai siswa"
msgid "Print or share your certificate:"
msgstr "Cetak atau bagikan sertifikat Anda:"
-#: lms/templates/certificates/_accomplishment-banner.html
-msgid "Click the link to see my certificate."
-msgstr "Klik tautan untuk melihat sertifikat saya."
-
#: lms/templates/certificates/_accomplishment-banner.html
msgid "Post on Facebook"
msgstr "Bagikan di Facebook"
diff --git a/conf/locale/id/LC_MESSAGES/djangojs.po b/conf/locale/id/LC_MESSAGES/djangojs.po
index 5673563c3b64..fab593b619b1 100644
--- a/conf/locale/id/LC_MESSAGES/djangojs.po
+++ b/conf/locale/id/LC_MESSAGES/djangojs.po
@@ -84,7 +84,7 @@ msgid ""
msgstr ""
"Project-Id-Version: edx-platform\n"
"Report-Msgid-Bugs-To: openedx-translation@googlegroups.com\n"
-"POT-Creation-Date: 2023-08-27 20:42+0000\n"
+"POT-Creation-Date: 2023-09-17 20:42+0000\n"
"PO-Revision-Date: 2014-06-11 15:18+0000\n"
"Last-Translator: Faizar Septiawan , 2023\n"
"Language-Team: Indonesian (http://app.transifex.com/open-edx/edx-platform/language/id/)\n"
@@ -95,14 +95,6 @@ msgstr ""
"Plural-Forms: nplurals=1; plural=0;\n"
"Generated-By: Babel 2.8.0\n"
-#: cms/static/cms/js/main.js cms/static/js/views/active_video_upload_list.js
-#: cms/static/js/views/video_transcripts.js
-#: xmodule/assets/library_source_block/public/js/library_source_block.js
-msgid ""
-"This may be happening because of an error with our server or your internet "
-"connection. Try refreshing the page or making sure you are online."
-msgstr ""
-
#: cms/static/cms/js/xblock/cms.runtime.v1.js
#: cms/static/js/certificates/views/signatory_details.js
#: cms/static/js/models/section.js cms/static/js/utils/drag_and_drop.js
@@ -114,7 +106,6 @@ msgstr ""
#: cms/static/js/views/modals/edit_xblock.js cms/static/js/views/tabs.js
#: cms/static/js/views/utils/xblock_utils.js lms/static/js/ccx/schedule.js
#: lms/static/js/views/fields.js
-#: xmodule/assets/library_source_block/public/js/library_source_block.js
msgid "Saving"
msgstr "Menyimpan"
@@ -4008,18 +3999,6 @@ msgstr "Profil"
msgid "Updating with latest library content"
msgstr "Mengupdate dengan konten library terakhir"
-#: xmodule/assets/library_source_block/LibrarySourcedBlockPicker.jsx
-msgid "Loading..."
-msgstr ""
-
-#: xmodule/assets/library_source_block/LibrarySourcedBlockPicker.jsx
-msgid "Selected blocks"
-msgstr ""
-
-#: xmodule/assets/library_source_block/public/js/library_source_block.js
-msgid "Unable to update settings"
-msgstr ""
-
#: xmodule/assets/split_test/public/js/split_test_author_view.js
#: xmodule/js/public/js/split_test_author_view.js
msgid "Creating missing groups"
@@ -5656,6 +5635,13 @@ msgstr "Aktifkan transkrip"
msgid "Turn off transcripts"
msgstr "Matikan transkrip"
+#: cms/static/cms/js/main.js cms/static/js/views/active_video_upload_list.js
+#: cms/static/js/views/video_transcripts.js
+msgid ""
+"This may be happening because of an error with our server or your internet "
+"connection. Try refreshing the page or making sure you are online."
+msgstr ""
+
#: cms/static/cms/js/main.js
msgid "Studio's having trouble saving your work"
msgstr "Studio mengalami kesulitan menyimpan hasil kerja Anda"
@@ -6200,7 +6186,7 @@ msgstr ""
#: cms/static/js/views/course_outline.js
#: cms/static/js/views/pages/container.js
-msgid "New files were added to this course's Files & Uploads"
+msgid "New file(s) added to Files & Uploads."
msgstr ""
#: cms/static/js/views/course_outline.js
@@ -6208,6 +6194,16 @@ msgstr ""
msgid "The following required files were imported to this course:"
msgstr ""
+#: cms/static/js/views/course_outline.js
+#: cms/static/js/views/pages/container.js
+msgid "View files"
+msgstr ""
+
+#: cms/static/js/views/course_outline.js
+#: cms/static/js/views/pages/container.js
+msgid "Dismiss"
+msgstr ""
+
#: cms/static/js/views/course_rerun.js
msgid "Create Re-run"
msgstr ""
diff --git a/conf/locale/it_IT/LC_MESSAGES/django.mo b/conf/locale/it_IT/LC_MESSAGES/django.mo
index 24e492708837..b460b89f009a 100644
Binary files a/conf/locale/it_IT/LC_MESSAGES/django.mo and b/conf/locale/it_IT/LC_MESSAGES/django.mo differ
diff --git a/conf/locale/it_IT/LC_MESSAGES/django.po b/conf/locale/it_IT/LC_MESSAGES/django.po
index 72e64058b0fe..7d693ff66c2f 100644
--- a/conf/locale/it_IT/LC_MESSAGES/django.po
+++ b/conf/locale/it_IT/LC_MESSAGES/django.po
@@ -127,7 +127,7 @@ msgid ""
msgstr ""
"Project-Id-Version: 0.1a\n"
"Report-Msgid-Bugs-To: openedx-translation@googlegroups.com\n"
-"POT-Creation-Date: 2023-08-20 20:42+0000\n"
+"POT-Creation-Date: 2023-09-10 20:42+0000\n"
"PO-Revision-Date: 2019-01-20 20:43+0000\n"
"Last-Translator: Ilaria Botti , 2021\n"
"Language-Team: Italian (Italy) (https://app.transifex.com/open-edx/teams/6205/it_IT/)\n"
@@ -230,8 +230,8 @@ msgid "Video"
msgstr "Video"
#: cms/djangoapps/contentstore/views/component.py xmodule/capa_block.py
-msgid "Blank Advanced Problem"
-msgstr "Problema avanzato vuoto"
+msgid "Blank Problem"
+msgstr ""
#: cms/djangoapps/contentstore/views/component.py
#: xmodule/video_block/video_block.py
@@ -337,8 +337,8 @@ msgstr "Formazione professionale"
#: common/djangoapps/course_modes/models.py xmodule/annotatable_block.py
#: xmodule/capa_block.py xmodule/conditional_block.py
#: xmodule/discussion_block.py xmodule/html_block.py
-#: xmodule/library_content_block.py xmodule/library_sourced_block.py
-#: xmodule/lti_block.py xmodule/split_test_block.py xmodule/unit_block.py
+#: xmodule/library_content_block.py xmodule/lti_block.py
+#: xmodule/split_test_block.py xmodule/unit_block.py
#: xmodule/word_cloud_block.py xmodule/x_module.py
#: cms/templates/container.html cms/templates/library.html
msgid "Display Name"
@@ -3242,6 +3242,12 @@ msgstr "Compito"
msgid "Open Response Assessment"
msgstr "Valutazione a Risposta Aperta"
+#: lms/djangoapps/courseware/courses.py
+msgid ""
+"This Open Response Assessment's due dates are set by your instructor and "
+"can't be shifted."
+msgstr ""
+
#: lms/djangoapps/courseware/courses.py
msgid "Self Assessment"
msgstr "Valutazione autonoma"
@@ -3258,14 +3264,6 @@ msgstr "Valutazione dello Staff"
msgid "Submission"
msgstr "Invio"
-#: lms/djangoapps/courseware/courses.py
-msgid ""
-"Open Response Assessment due dates are set by your instructor and can't be "
-"shifted."
-msgstr ""
-"Le date di scadenza di Valutazione a risposta aperta sono impostate dal tuo "
-"istruttore e non possono essere spostate."
-
#. Translators: 'absolute' is a date such as "Jan 01,
#. 2020". 'relative' is a fuzzy description of the time until
#. 'absolute'. For example, 'absolute' might be "Jan 01, 2020",
@@ -6086,7 +6084,6 @@ msgstr ""
#: lms/templates/oauth2_provider/authorize.html
#: openedx/core/djangoapps/user_api/admin.py
-#: xmodule/templates/library-sourced-block-studio-view.html
#: cms/templates/course-create-rerun.html cms/templates/index.html
#: cms/templates/manage_users.html cms/templates/manage_users_lib.html
#: cms/templates/videos_index_pagination.html
@@ -6555,13 +6552,11 @@ msgid "Quotes"
msgstr "Citazioni"
#: lms/templates/wiki/includes/editor_widget.html
-#, python-format
+#, python-brace-format
msgid ""
-"Markdown syntax is allowed. See the %(start_link)scheatsheet%(end_link)s for"
-" help."
+"Markdown syntax is allowed. See the {start_link}cheatsheet{end_link} for "
+"help."
msgstr ""
-"La sintassi markdown è consentita. Consultare "
-"%(start_link)scheatsheet%(end_link)s per assistenza."
#: lms/templates/wiki/plugins/attachments/index.html
#: wiki/plugins/attachments/templates/wiki/plugins/attachments/index.html
@@ -7624,8 +7619,8 @@ msgstr ""
#: openedx/core/djangoapps/discussions/models.py
msgid ""
-"The Posting availabilty in discussions whether it will be enabled, scheduled"
-" or indefinitely disabled."
+"The Posting availability in discussions whether it will be enabled, "
+"scheduled or indefinitely disabled."
msgstr ""
#: openedx/core/djangoapps/discussions/models.py
@@ -9711,8 +9706,7 @@ msgstr "Dati XML associati all'annotazione"
#: xmodule/annotatable_block.py xmodule/capa_block.py
#: xmodule/conditional_block.py xmodule/discussion_block.py
#: xmodule/html_block.py xmodule/library_content_block.py
-#: xmodule/library_root_xblock.py xmodule/library_sourced_block.py
-#: xmodule/poll_block.py xmodule/unit_block.py
+#: xmodule/library_root_xblock.py xmodule/poll_block.py xmodule/unit_block.py
#: xmodule/video_block/video_xfields.py xmodule/word_cloud_block.py
#: xmodule/x_module.py
msgid "The display name for this component."
@@ -12006,36 +12000,6 @@ msgstr ""
"Immettere i nomi dei componenti avanzati da utilizzare nella propria "
"libreria."
-#: xmodule/library_sourced_block.py
-msgid "Library Blocks List"
-msgstr "Elenco blocchi libreria"
-
-#: xmodule/library_sourced_block.py
-msgid "Enter the IDs of the library XBlocks that you wish to use."
-msgstr "Immettere gli ID di XBlock della libreria che si desidera utilizzare."
-
-#: xmodule/library_sourced_block.py
-#, python-brace-format
-msgid "A maximum of {0} components may be added."
-msgstr "È possibile aggiungere un massimo di {0} componenti."
-
-#: xmodule/library_sourced_block.py
-msgid ""
-"No XBlock has been configured for this component. Use the editor to select "
-"the target blocks."
-msgstr ""
-"Nessun XBlock è stato configurato per questo componente. Utilizzare l'editor"
-" per selezionare i blocchi di destinazione."
-
-#: xmodule/library_sourced_block.py
-msgid "Open Editor"
-msgstr "Apri editor"
-
-#: xmodule/library_sourced_block.py
-msgid "Importing Library Block failed - are the IDs valid and readable?"
-msgstr ""
-"Importazione blocco libreria non riuscita - gli ID sono validi e leggibili?"
-
#: xmodule/lti_block.py
msgid ""
"The display name for this component. Analytics reports may also use the "
@@ -12765,10 +12729,6 @@ msgstr ""
msgid "External Discussion"
msgstr "Discussione esterna"
-#: xmodule/templates/library-sourced-block-studio-view.html
-msgid "Save and Import"
-msgstr "Salva e importa"
-
#: xmodule/vertical_block.py
msgid "Enable in-context discussions for the Unit"
msgstr "Abilita discussioni contestualizzate per l'Unità"
@@ -16814,10 +16774,6 @@ msgstr "Scarica le valutazioni dello studente"
msgid "Print or share your certificate:"
msgstr "Stampa o condividi il tuo certificato:"
-#: lms/templates/certificates/_accomplishment-banner.html
-msgid "Click the link to see my certificate."
-msgstr "Fai clic sul link per vedere il mio certificato."
-
#: lms/templates/certificates/_accomplishment-banner.html
msgid "Post on Facebook"
msgstr "Pubblica su Facebook"
diff --git a/conf/locale/it_IT/LC_MESSAGES/djangojs.mo b/conf/locale/it_IT/LC_MESSAGES/djangojs.mo
index 0f87dabf8940..5690cb9077ac 100644
Binary files a/conf/locale/it_IT/LC_MESSAGES/djangojs.mo and b/conf/locale/it_IT/LC_MESSAGES/djangojs.mo differ
diff --git a/conf/locale/it_IT/LC_MESSAGES/djangojs.po b/conf/locale/it_IT/LC_MESSAGES/djangojs.po
index 72f9fbb8d1eb..fc3081764fd6 100644
--- a/conf/locale/it_IT/LC_MESSAGES/djangojs.po
+++ b/conf/locale/it_IT/LC_MESSAGES/djangojs.po
@@ -113,7 +113,7 @@ msgid ""
msgstr ""
"Project-Id-Version: edx-platform\n"
"Report-Msgid-Bugs-To: openedx-translation@googlegroups.com\n"
-"POT-Creation-Date: 2023-08-27 20:42+0000\n"
+"POT-Creation-Date: 2023-09-17 20:42+0000\n"
"PO-Revision-Date: 2014-06-11 15:18+0000\n"
"Last-Translator: Ilaria Botti , 2022\n"
"Language-Team: Italian (Italy) (http://app.transifex.com/open-edx/edx-platform/language/it_IT/)\n"
@@ -124,17 +124,6 @@ msgstr ""
"Plural-Forms: nplurals=3; plural=n == 1 ? 0 : n != 0 && n % 1000000 == 0 ? 1 : 2;\n"
"Generated-By: Babel 2.8.0\n"
-#: cms/static/cms/js/main.js cms/static/js/views/active_video_upload_list.js
-#: cms/static/js/views/video_transcripts.js
-#: xmodule/assets/library_source_block/public/js/library_source_block.js
-msgid ""
-"This may be happening because of an error with our server or your internet "
-"connection. Try refreshing the page or making sure you are online."
-msgstr ""
-"L'errore può essere conseguenza di un errore nei nostri server o nella tua "
-"connessione Internet. Prova a ricaricare la pagina e assicurati di essere "
-"online."
-
#: cms/static/cms/js/xblock/cms.runtime.v1.js
#: cms/static/js/certificates/views/signatory_details.js
#: cms/static/js/models/section.js cms/static/js/utils/drag_and_drop.js
@@ -146,7 +135,6 @@ msgstr ""
#: cms/static/js/views/modals/edit_xblock.js cms/static/js/views/tabs.js
#: cms/static/js/views/utils/xblock_utils.js lms/static/js/ccx/schedule.js
#: lms/static/js/views/fields.js
-#: xmodule/assets/library_source_block/public/js/library_source_block.js
msgid "Saving"
msgstr "Salvataggio in corso"
@@ -4261,18 +4249,6 @@ msgstr "Profilo"
msgid "Updating with latest library content"
msgstr "Aggiornamento con gli ultimi contenuti della libreria"
-#: xmodule/assets/library_source_block/LibrarySourcedBlockPicker.jsx
-msgid "Loading..."
-msgstr "Caricamento..."
-
-#: xmodule/assets/library_source_block/LibrarySourcedBlockPicker.jsx
-msgid "Selected blocks"
-msgstr "Blocchi selezionati"
-
-#: xmodule/assets/library_source_block/public/js/library_source_block.js
-msgid "Unable to update settings"
-msgstr "Impossibile aggiornare le impostazioni"
-
#: xmodule/assets/split_test/public/js/split_test_author_view.js
#: xmodule/js/public/js/split_test_author_view.js
msgid "Creating missing groups"
@@ -5947,6 +5923,13 @@ msgstr "Attiva le trascrizioni"
msgid "Turn off transcripts"
msgstr "Disattiva le trascrizioni"
+#: cms/static/cms/js/main.js cms/static/js/views/active_video_upload_list.js
+#: cms/static/js/views/video_transcripts.js
+msgid ""
+"This may be happening because of an error with our server or your internet "
+"connection. Try refreshing the page or making sure you are online."
+msgstr ""
+
#: cms/static/cms/js/main.js
msgid "Studio's having trouble saving your work"
msgstr "Studio ha problemi a salvare i tuoi progressi."
@@ -6523,7 +6506,7 @@ msgstr ""
#: cms/static/js/views/course_outline.js
#: cms/static/js/views/pages/container.js
-msgid "New files were added to this course's Files & Uploads"
+msgid "New file(s) added to Files & Uploads."
msgstr ""
#: cms/static/js/views/course_outline.js
@@ -6531,6 +6514,16 @@ msgstr ""
msgid "The following required files were imported to this course:"
msgstr ""
+#: cms/static/js/views/course_outline.js
+#: cms/static/js/views/pages/container.js
+msgid "View files"
+msgstr ""
+
+#: cms/static/js/views/course_outline.js
+#: cms/static/js/views/pages/container.js
+msgid "Dismiss"
+msgstr ""
+
#: cms/static/js/views/course_rerun.js
msgid "Create Re-run"
msgstr "Crea un riavvio"
diff --git a/conf/locale/ja_JP/LC_MESSAGES/django.mo b/conf/locale/ja_JP/LC_MESSAGES/django.mo
index 037f62ef44f8..4bac8c4e47d8 100644
Binary files a/conf/locale/ja_JP/LC_MESSAGES/django.mo and b/conf/locale/ja_JP/LC_MESSAGES/django.mo differ
diff --git a/conf/locale/ja_JP/LC_MESSAGES/django.po b/conf/locale/ja_JP/LC_MESSAGES/django.po
index 1ae043a1104c..ed5767dc03ef 100644
--- a/conf/locale/ja_JP/LC_MESSAGES/django.po
+++ b/conf/locale/ja_JP/LC_MESSAGES/django.po
@@ -114,7 +114,7 @@ msgid ""
msgstr ""
"Project-Id-Version: 0.1a\n"
"Report-Msgid-Bugs-To: openedx-translation@googlegroups.com\n"
-"POT-Creation-Date: 2023-08-27 20:43+0000\n"
+"POT-Creation-Date: 2023-09-17 20:43+0000\n"
"PO-Revision-Date: 2019-01-20 20:43+0000\n"
"Last-Translator: Waheed Ahmed , 2019\n"
"Language-Team: Japanese (Japan) (https://app.transifex.com/open-edx/teams/6205/ja_JP/)\n"
@@ -213,8 +213,8 @@ msgid "Video"
msgstr "動画"
#: cms/djangoapps/contentstore/views/component.py xmodule/capa_block.py
-msgid "Blank Advanced Problem"
-msgstr "空欄補充問題"
+msgid "Blank Problem"
+msgstr ""
#: cms/djangoapps/contentstore/views/component.py
#: xmodule/video_block/video_block.py
@@ -316,8 +316,8 @@ msgstr "Professional Ed"
#: common/djangoapps/course_modes/models.py xmodule/annotatable_block.py
#: xmodule/capa_block.py xmodule/conditional_block.py
#: xmodule/discussion_block.py xmodule/html_block.py
-#: xmodule/library_content_block.py xmodule/library_sourced_block.py
-#: xmodule/lti_block.py xmodule/split_test_block.py xmodule/unit_block.py
+#: xmodule/library_content_block.py xmodule/lti_block.py
+#: xmodule/split_test_block.py xmodule/unit_block.py
#: xmodule/word_cloud_block.py xmodule/x_module.py
#: cms/templates/container.html cms/templates/library.html
msgid "Display Name"
@@ -2815,6 +2815,12 @@ msgstr ""
msgid "Open Response Assessment"
msgstr ""
+#: lms/djangoapps/courseware/courses.py
+msgid ""
+"This Open Response Assessment's due dates are set by your instructor and "
+"can't be shifted."
+msgstr ""
+
#: lms/djangoapps/courseware/courses.py
msgid "Self Assessment"
msgstr ""
@@ -2831,12 +2837,6 @@ msgstr ""
msgid "Submission"
msgstr ""
-#: lms/djangoapps/courseware/courses.py
-msgid ""
-"Open Response Assessment due dates are set by your instructor and can't be "
-"shifted."
-msgstr ""
-
#. Translators: 'absolute' is a date such as "Jan 01,
#. 2020". 'relative' is a fuzzy description of the time until
#. 'absolute'. For example, 'absolute' might be "Jan 01, 2020",
@@ -5335,7 +5335,6 @@ msgstr "上記のアプリを許可するには、'許可'ボタンをクリッ
#: lms/templates/oauth2_provider/authorize.html
#: openedx/core/djangoapps/user_api/admin.py
-#: xmodule/templates/library-sourced-block-studio-view.html
msgid "Cancel"
msgstr "キャンセル"
@@ -5752,10 +5751,10 @@ msgid "Quotes"
msgstr "引用"
#: lms/templates/wiki/includes/editor_widget.html
-#, python-format
+#, python-brace-format
msgid ""
-"Markdown syntax is allowed. See the %(start_link)scheatsheet%(end_link)s for"
-" help."
+"Markdown syntax is allowed. See the {start_link}cheatsheet{end_link} for "
+"help."
msgstr ""
#: lms/templates/wiki/plugins/attachments/index.html
@@ -6684,8 +6683,8 @@ msgstr ""
#: openedx/core/djangoapps/discussions/models.py
msgid ""
-"The Posting availabilty in discussions whether it will be enabled, scheduled"
-" or indefinitely disabled."
+"The Posting availability in discussions whether it will be enabled, "
+"scheduled or indefinitely disabled."
msgstr ""
#: openedx/core/djangoapps/discussions/models.py
@@ -8496,8 +8495,7 @@ msgstr "注釈用のXMLデータ"
#: xmodule/annotatable_block.py xmodule/capa_block.py
#: xmodule/conditional_block.py xmodule/discussion_block.py
#: xmodule/html_block.py xmodule/library_content_block.py
-#: xmodule/library_root_xblock.py xmodule/library_sourced_block.py
-#: xmodule/poll_block.py xmodule/unit_block.py
+#: xmodule/library_root_xblock.py xmodule/poll_block.py xmodule/unit_block.py
#: xmodule/video_block/video_xfields.py xmodule/word_cloud_block.py
#: xmodule/x_module.py
msgid "The display name for this component."
@@ -10496,33 +10494,6 @@ msgstr "ライブラリ表示名"
msgid "Enter the names of the advanced components to use in your library."
msgstr "ライブラリで使用する拡張コンポーネントの名前を入力してください。"
-#: xmodule/library_sourced_block.py
-msgid "Library Blocks List"
-msgstr ""
-
-#: xmodule/library_sourced_block.py
-msgid "Enter the IDs of the library XBlocks that you wish to use."
-msgstr ""
-
-#: xmodule/library_sourced_block.py
-#, python-brace-format
-msgid "A maximum of {0} components may be added."
-msgstr ""
-
-#: xmodule/library_sourced_block.py
-msgid ""
-"No XBlock has been configured for this component. Use the editor to select "
-"the target blocks."
-msgstr ""
-
-#: xmodule/library_sourced_block.py
-msgid "Open Editor"
-msgstr ""
-
-#: xmodule/library_sourced_block.py
-msgid "Importing Library Block failed - are the IDs valid and readable?"
-msgstr ""
-
#: xmodule/lti_block.py
msgid ""
"The display name for this component. Analytics reports may also use the "
@@ -11126,10 +11097,6 @@ msgstr "このコンテンツ実験はコンテンツの表示に影響を与え
msgid "External Discussion"
msgstr "外部ディスカッション"
-#: xmodule/templates/library-sourced-block-studio-view.html
-msgid "Save and Import"
-msgstr ""
-
#: xmodule/vertical_block.py
msgid "Enable in-context discussions for the Unit"
msgstr ""
@@ -14644,10 +14611,6 @@ msgstr "受講者の成績をダウンロード"
msgid "Print or share your certificate:"
msgstr "修了証を印刷またはシェア: "
-#: lms/templates/certificates/_accomplishment-banner.html
-msgid "Click the link to see my certificate."
-msgstr "リンクをクリックして修了書を見る。"
-
#: lms/templates/certificates/_accomplishment-banner.html
msgid "Post on Facebook"
msgstr "フェースブックに投稿"
diff --git a/conf/locale/ja_JP/LC_MESSAGES/djangojs.po b/conf/locale/ja_JP/LC_MESSAGES/djangojs.po
index 880aa4c9084f..8bcde9742439 100644
--- a/conf/locale/ja_JP/LC_MESSAGES/djangojs.po
+++ b/conf/locale/ja_JP/LC_MESSAGES/djangojs.po
@@ -78,7 +78,7 @@ msgid ""
msgstr ""
"Project-Id-Version: edx-platform\n"
"Report-Msgid-Bugs-To: openedx-translation@googlegroups.com\n"
-"POT-Creation-Date: 2023-08-27 20:42+0000\n"
+"POT-Creation-Date: 2023-09-17 20:42+0000\n"
"PO-Revision-Date: 2014-06-11 15:18+0000\n"
"Last-Translator: Kyoto University , 2017\n"
"Language-Team: Japanese (Japan) (http://app.transifex.com/open-edx/edx-platform/language/ja_JP/)\n"
@@ -89,14 +89,6 @@ msgstr ""
"Plural-Forms: nplurals=1; plural=0;\n"
"Generated-By: Babel 2.8.0\n"
-#: cms/static/cms/js/main.js cms/static/js/views/active_video_upload_list.js
-#: cms/static/js/views/video_transcripts.js
-#: xmodule/assets/library_source_block/public/js/library_source_block.js
-msgid ""
-"This may be happening because of an error with our server or your internet "
-"connection. Try refreshing the page or making sure you are online."
-msgstr ""
-
#: cms/static/cms/js/xblock/cms.runtime.v1.js
#: cms/static/js/certificates/views/signatory_details.js
#: cms/static/js/models/section.js cms/static/js/utils/drag_and_drop.js
@@ -108,7 +100,6 @@ msgstr ""
#: cms/static/js/views/modals/edit_xblock.js cms/static/js/views/tabs.js
#: cms/static/js/views/utils/xblock_utils.js lms/static/js/ccx/schedule.js
#: lms/static/js/views/fields.js
-#: xmodule/assets/library_source_block/public/js/library_source_block.js
msgid "Saving"
msgstr "保存中"
@@ -3749,18 +3740,6 @@ msgstr "プロフィール"
msgid "Updating with latest library content"
msgstr "最新のライブラリコンテンツで更新中"
-#: xmodule/assets/library_source_block/LibrarySourcedBlockPicker.jsx
-msgid "Loading..."
-msgstr ""
-
-#: xmodule/assets/library_source_block/LibrarySourcedBlockPicker.jsx
-msgid "Selected blocks"
-msgstr ""
-
-#: xmodule/assets/library_source_block/public/js/library_source_block.js
-msgid "Unable to update settings"
-msgstr ""
-
#: xmodule/assets/split_test/public/js/split_test_author_view.js
#: xmodule/js/public/js/split_test_author_view.js
msgid "Creating missing groups"
@@ -5355,6 +5334,13 @@ msgstr ""
msgid "Turn off transcripts"
msgstr ""
+#: cms/static/cms/js/main.js cms/static/js/views/active_video_upload_list.js
+#: cms/static/js/views/video_transcripts.js
+msgid ""
+"This may be happening because of an error with our server or your internet "
+"connection. Try refreshing the page or making sure you are online."
+msgstr ""
+
#: cms/static/cms/js/main.js
msgid "Studio's having trouble saving your work"
msgstr ""
@@ -5897,7 +5883,7 @@ msgstr ""
#: cms/static/js/views/course_outline.js
#: cms/static/js/views/pages/container.js
-msgid "New files were added to this course's Files & Uploads"
+msgid "New file(s) added to Files & Uploads."
msgstr ""
#: cms/static/js/views/course_outline.js
@@ -5905,6 +5891,16 @@ msgstr ""
msgid "The following required files were imported to this course:"
msgstr ""
+#: cms/static/js/views/course_outline.js
+#: cms/static/js/views/pages/container.js
+msgid "View files"
+msgstr ""
+
+#: cms/static/js/views/course_outline.js
+#: cms/static/js/views/pages/container.js
+msgid "Dismiss"
+msgstr ""
+
#: cms/static/js/views/course_rerun.js
msgid "Create Re-run"
msgstr "Re-runを作成"
diff --git a/conf/locale/ka/LC_MESSAGES/django.mo b/conf/locale/ka/LC_MESSAGES/django.mo
index 23f5e593f9bf..41bd814d4e22 100644
Binary files a/conf/locale/ka/LC_MESSAGES/django.mo and b/conf/locale/ka/LC_MESSAGES/django.mo differ
diff --git a/conf/locale/ka/LC_MESSAGES/django.po b/conf/locale/ka/LC_MESSAGES/django.po
index 101bd58bdadd..30851f85297e 100644
--- a/conf/locale/ka/LC_MESSAGES/django.po
+++ b/conf/locale/ka/LC_MESSAGES/django.po
@@ -60,7 +60,7 @@ msgid ""
msgstr ""
"Project-Id-Version: 0.1a\n"
"Report-Msgid-Bugs-To: openedx-translation@googlegroups.com\n"
-"POT-Creation-Date: 2023-08-27 20:43+0000\n"
+"POT-Creation-Date: 2023-09-17 20:43+0000\n"
"PO-Revision-Date: 2019-01-20 20:43+0000\n"
"Last-Translator: Waheed Ahmed , 2019\n"
"Language-Team: Georgian (https://app.transifex.com/open-edx/teams/6205/ka/)\n"
@@ -159,8 +159,8 @@ msgid "Video"
msgstr "ვიდეო"
#: cms/djangoapps/contentstore/views/component.py xmodule/capa_block.py
-msgid "Blank Advanced Problem"
-msgstr "ცარიელი დამატებითი პამოცანა"
+msgid "Blank Problem"
+msgstr ""
#: cms/djangoapps/contentstore/views/component.py
#: xmodule/video_block/video_block.py
@@ -265,8 +265,8 @@ msgstr "პროფესიული განათლება"
#: common/djangoapps/course_modes/models.py xmodule/annotatable_block.py
#: xmodule/capa_block.py xmodule/conditional_block.py
#: xmodule/discussion_block.py xmodule/html_block.py
-#: xmodule/library_content_block.py xmodule/library_sourced_block.py
-#: xmodule/lti_block.py xmodule/split_test_block.py xmodule/unit_block.py
+#: xmodule/library_content_block.py xmodule/lti_block.py
+#: xmodule/split_test_block.py xmodule/unit_block.py
#: xmodule/word_cloud_block.py xmodule/x_module.py
#: cms/templates/container.html cms/templates/library.html
msgid "Display Name"
@@ -2856,6 +2856,12 @@ msgstr ""
msgid "Open Response Assessment"
msgstr ""
+#: lms/djangoapps/courseware/courses.py
+msgid ""
+"This Open Response Assessment's due dates are set by your instructor and "
+"can't be shifted."
+msgstr ""
+
#: lms/djangoapps/courseware/courses.py
msgid "Self Assessment"
msgstr ""
@@ -2872,12 +2878,6 @@ msgstr ""
msgid "Submission"
msgstr ""
-#: lms/djangoapps/courseware/courses.py
-msgid ""
-"Open Response Assessment due dates are set by your instructor and can't be "
-"shifted."
-msgstr ""
-
#. Translators: 'absolute' is a date such as "Jan 01,
#. 2020". 'relative' is a fuzzy description of the time until
#. 'absolute'. For example, 'absolute' might be "Jan 01, 2020",
@@ -5467,7 +5467,6 @@ msgstr ""
#: lms/templates/oauth2_provider/authorize.html
#: openedx/core/djangoapps/user_api/admin.py
-#: xmodule/templates/library-sourced-block-studio-view.html
msgid "Cancel"
msgstr "გაუქმება"
@@ -5897,10 +5896,10 @@ msgid "Quotes"
msgstr "ციტატები"
#: lms/templates/wiki/includes/editor_widget.html
-#, python-format
+#, python-brace-format
msgid ""
-"Markdown syntax is allowed. See the %(start_link)scheatsheet%(end_link)s for"
-" help."
+"Markdown syntax is allowed. See the {start_link}cheatsheet{end_link} for "
+"help."
msgstr ""
#: lms/templates/wiki/plugins/attachments/index.html
@@ -6857,8 +6856,8 @@ msgstr ""
#: openedx/core/djangoapps/discussions/models.py
msgid ""
-"The Posting availabilty in discussions whether it will be enabled, scheduled"
-" or indefinitely disabled."
+"The Posting availability in discussions whether it will be enabled, "
+"scheduled or indefinitely disabled."
msgstr ""
#: openedx/core/djangoapps/discussions/models.py
@@ -8696,8 +8695,7 @@ msgstr "XML მონაცემები ანოტაციისთვი
#: xmodule/annotatable_block.py xmodule/capa_block.py
#: xmodule/conditional_block.py xmodule/discussion_block.py
#: xmodule/html_block.py xmodule/library_content_block.py
-#: xmodule/library_root_xblock.py xmodule/library_sourced_block.py
-#: xmodule/poll_block.py xmodule/unit_block.py
+#: xmodule/library_root_xblock.py xmodule/poll_block.py xmodule/unit_block.py
#: xmodule/video_block/video_xfields.py xmodule/word_cloud_block.py
#: xmodule/x_module.py
msgid "The display name for this component."
@@ -10870,33 +10868,6 @@ msgstr ""
"დამატებითი კომპონენტების სახელები თქვენს ბიბლიოთეკაში გამოყენების მიზნით "
"შეიყვანეთ."
-#: xmodule/library_sourced_block.py
-msgid "Library Blocks List"
-msgstr ""
-
-#: xmodule/library_sourced_block.py
-msgid "Enter the IDs of the library XBlocks that you wish to use."
-msgstr ""
-
-#: xmodule/library_sourced_block.py
-#, python-brace-format
-msgid "A maximum of {0} components may be added."
-msgstr ""
-
-#: xmodule/library_sourced_block.py
-msgid ""
-"No XBlock has been configured for this component. Use the editor to select "
-"the target blocks."
-msgstr ""
-
-#: xmodule/library_sourced_block.py
-msgid "Open Editor"
-msgstr ""
-
-#: xmodule/library_sourced_block.py
-msgid "Importing Library Block failed - are the IDs valid and readable?"
-msgstr ""
-
#: xmodule/lti_block.py
msgid ""
"The display name for this component. Analytics reports may also use the "
@@ -11581,10 +11552,6 @@ msgstr ""
msgid "External Discussion"
msgstr "გარე დისკუსია"
-#: xmodule/templates/library-sourced-block-studio-view.html
-msgid "Save and Import"
-msgstr ""
-
#: xmodule/vertical_block.py
msgid "Enable in-context discussions for the Unit"
msgstr ""
@@ -15310,10 +15277,6 @@ msgstr "სტუდენტის ნიშნების ჩამოტვ
msgid "Print or share your certificate:"
msgstr "თქვენი სერტიფიკატის ბეჭდვა ან გაზიარება:"
-#: lms/templates/certificates/_accomplishment-banner.html
-msgid "Click the link to see my certificate."
-msgstr "ჩემი სერტიფიკატის სანახავად დააწკაპუნეთ ბმულზე."
-
#: lms/templates/certificates/_accomplishment-banner.html
msgid "Post on Facebook"
msgstr "დაპოსტეთ Facebook-ზე"
diff --git a/conf/locale/ka/LC_MESSAGES/djangojs.po b/conf/locale/ka/LC_MESSAGES/djangojs.po
index 6ed5c48f6ccb..20eaf4425c99 100644
--- a/conf/locale/ka/LC_MESSAGES/djangojs.po
+++ b/conf/locale/ka/LC_MESSAGES/djangojs.po
@@ -56,7 +56,7 @@ msgid ""
msgstr ""
"Project-Id-Version: edx-platform\n"
"Report-Msgid-Bugs-To: openedx-translation@googlegroups.com\n"
-"POT-Creation-Date: 2023-08-27 20:42+0000\n"
+"POT-Creation-Date: 2023-09-17 20:42+0000\n"
"PO-Revision-Date: 2014-06-11 15:18+0000\n"
"Last-Translator: Lasha Kokilashvili, 2018\n"
"Language-Team: Georgian (http://app.transifex.com/open-edx/edx-platform/language/ka/)\n"
@@ -67,14 +67,6 @@ msgstr ""
"Plural-Forms: nplurals=2; plural=(n!=1);\n"
"Generated-By: Babel 2.8.0\n"
-#: cms/static/cms/js/main.js cms/static/js/views/active_video_upload_list.js
-#: cms/static/js/views/video_transcripts.js
-#: xmodule/assets/library_source_block/public/js/library_source_block.js
-msgid ""
-"This may be happening because of an error with our server or your internet "
-"connection. Try refreshing the page or making sure you are online."
-msgstr ""
-
#: cms/static/cms/js/xblock/cms.runtime.v1.js
#: cms/static/js/certificates/views/signatory_details.js
#: cms/static/js/models/section.js cms/static/js/utils/drag_and_drop.js
@@ -86,7 +78,6 @@ msgstr ""
#: cms/static/js/views/modals/edit_xblock.js cms/static/js/views/tabs.js
#: cms/static/js/views/utils/xblock_utils.js lms/static/js/ccx/schedule.js
#: lms/static/js/views/fields.js
-#: xmodule/assets/library_source_block/public/js/library_source_block.js
msgid "Saving"
msgstr "შენახვა"
@@ -3861,18 +3852,6 @@ msgstr ""
msgid "Updating with latest library content"
msgstr "ბიბლიოთეკის უახლესი შინაარსით განახლება"
-#: xmodule/assets/library_source_block/LibrarySourcedBlockPicker.jsx
-msgid "Loading..."
-msgstr ""
-
-#: xmodule/assets/library_source_block/LibrarySourcedBlockPicker.jsx
-msgid "Selected blocks"
-msgstr ""
-
-#: xmodule/assets/library_source_block/public/js/library_source_block.js
-msgid "Unable to update settings"
-msgstr ""
-
#: xmodule/assets/split_test/public/js/split_test_author_view.js
#: xmodule/js/public/js/split_test_author_view.js
msgid "Creating missing groups"
@@ -5476,6 +5455,13 @@ msgstr ""
msgid "Turn off transcripts"
msgstr ""
+#: cms/static/cms/js/main.js cms/static/js/views/active_video_upload_list.js
+#: cms/static/js/views/video_transcripts.js
+msgid ""
+"This may be happening because of an error with our server or your internet "
+"connection. Try refreshing the page or making sure you are online."
+msgstr ""
+
#: cms/static/cms/js/main.js
msgid "Studio's having trouble saving your work"
msgstr ""
@@ -6031,7 +6017,7 @@ msgstr ""
#: cms/static/js/views/course_outline.js
#: cms/static/js/views/pages/container.js
-msgid "New files were added to this course's Files & Uploads"
+msgid "New file(s) added to Files & Uploads."
msgstr ""
#: cms/static/js/views/course_outline.js
@@ -6039,6 +6025,16 @@ msgstr ""
msgid "The following required files were imported to this course:"
msgstr ""
+#: cms/static/js/views/course_outline.js
+#: cms/static/js/views/pages/container.js
+msgid "View files"
+msgstr ""
+
+#: cms/static/js/views/course_outline.js
+#: cms/static/js/views/pages/container.js
+msgid "Dismiss"
+msgstr ""
+
#: cms/static/js/views/course_rerun.js
msgid "Create Re-run"
msgstr "ხელახლა გაშვების შექმნა"
diff --git a/conf/locale/lt_LT/LC_MESSAGES/django.mo b/conf/locale/lt_LT/LC_MESSAGES/django.mo
index 1d1dcbdc48bc..4e37e56dc0da 100644
Binary files a/conf/locale/lt_LT/LC_MESSAGES/django.mo and b/conf/locale/lt_LT/LC_MESSAGES/django.mo differ
diff --git a/conf/locale/lt_LT/LC_MESSAGES/django.po b/conf/locale/lt_LT/LC_MESSAGES/django.po
index 9827ff23ca27..feddb2b7f665 100644
--- a/conf/locale/lt_LT/LC_MESSAGES/django.po
+++ b/conf/locale/lt_LT/LC_MESSAGES/django.po
@@ -72,7 +72,7 @@ msgid ""
msgstr ""
"Project-Id-Version: 0.1a\n"
"Report-Msgid-Bugs-To: openedx-translation@googlegroups.com\n"
-"POT-Creation-Date: 2023-08-27 20:43+0000\n"
+"POT-Creation-Date: 2023-09-17 20:43+0000\n"
"PO-Revision-Date: 2019-01-20 20:43+0000\n"
"Last-Translator: Waheed Ahmed , 2019\n"
"Language-Team: Lithuanian (Lithuania) (https://app.transifex.com/open-edx/teams/6205/lt_LT/)\n"
@@ -169,7 +169,7 @@ msgid "Video"
msgstr ""
#: cms/djangoapps/contentstore/views/component.py xmodule/capa_block.py
-msgid "Blank Advanced Problem"
+msgid "Blank Problem"
msgstr ""
#: cms/djangoapps/contentstore/views/component.py
@@ -2781,6 +2781,12 @@ msgstr ""
msgid "Open Response Assessment"
msgstr ""
+#: lms/djangoapps/courseware/courses.py
+msgid ""
+"This Open Response Assessment's due dates are set by your instructor and "
+"can't be shifted."
+msgstr ""
+
#: lms/djangoapps/courseware/courses.py
msgid "Self Assessment"
msgstr ""
@@ -2797,12 +2803,6 @@ msgstr ""
msgid "Submission"
msgstr ""
-#: lms/djangoapps/courseware/courses.py
-msgid ""
-"Open Response Assessment due dates are set by your instructor and can't be "
-"shifted."
-msgstr ""
-
#. Translators: 'absolute' is a date such as "Jan 01,
#. 2020". 'relative' is a fuzzy description of the time until
#. 'absolute'. For example, 'absolute' might be "Jan 01, 2020",
@@ -5240,7 +5240,6 @@ msgstr ""
#: lms/templates/oauth2_provider/authorize.html
#: openedx/core/djangoapps/user_api/admin.py
-#: xmodule/templates/library-sourced-block-studio-view.html
#: cms/templates/course-create-rerun.html cms/templates/index.html
#: cms/templates/manage_users.html cms/templates/manage_users_lib.html
#: cms/templates/videos_index_pagination.html
@@ -5673,10 +5672,10 @@ msgid "Quotes"
msgstr "Kabutės"
#: lms/templates/wiki/includes/editor_widget.html
-#, python-format
+#, python-brace-format
msgid ""
-"Markdown syntax is allowed. See the %(start_link)scheatsheet%(end_link)s for"
-" help."
+"Markdown syntax is allowed. See the {start_link}cheatsheet{end_link} for "
+"help."
msgstr ""
#: lms/templates/wiki/plugins/attachments/index.html
@@ -6600,8 +6599,8 @@ msgstr ""
#: openedx/core/djangoapps/discussions/models.py
msgid ""
-"The Posting availabilty in discussions whether it will be enabled, scheduled"
-" or indefinitely disabled."
+"The Posting availability in discussions whether it will be enabled, "
+"scheduled or indefinitely disabled."
msgstr ""
#: openedx/core/djangoapps/discussions/models.py
@@ -8380,8 +8379,7 @@ msgstr ""
#: xmodule/annotatable_block.py xmodule/capa_block.py
#: xmodule/conditional_block.py xmodule/discussion_block.py
#: xmodule/html_block.py xmodule/library_content_block.py
-#: xmodule/library_root_xblock.py xmodule/library_sourced_block.py
-#: xmodule/poll_block.py xmodule/unit_block.py
+#: xmodule/library_root_xblock.py xmodule/poll_block.py xmodule/unit_block.py
#: xmodule/video_block/video_xfields.py xmodule/word_cloud_block.py
#: xmodule/x_module.py
msgid "The display name for this component."
@@ -10356,33 +10354,6 @@ msgstr ""
msgid "Enter the names of the advanced components to use in your library."
msgstr ""
-#: xmodule/library_sourced_block.py
-msgid "Library Blocks List"
-msgstr ""
-
-#: xmodule/library_sourced_block.py
-msgid "Enter the IDs of the library XBlocks that you wish to use."
-msgstr ""
-
-#: xmodule/library_sourced_block.py
-#, python-brace-format
-msgid "A maximum of {0} components may be added."
-msgstr ""
-
-#: xmodule/library_sourced_block.py
-msgid ""
-"No XBlock has been configured for this component. Use the editor to select "
-"the target blocks."
-msgstr ""
-
-#: xmodule/library_sourced_block.py
-msgid "Open Editor"
-msgstr ""
-
-#: xmodule/library_sourced_block.py
-msgid "Importing Library Block failed - are the IDs valid and readable?"
-msgstr ""
-
#: xmodule/lti_block.py
msgid ""
"The display name for this component. Analytics reports may also use the "
@@ -10970,10 +10941,6 @@ msgstr ""
msgid "External Discussion"
msgstr ""
-#: xmodule/templates/library-sourced-block-studio-view.html
-msgid "Save and Import"
-msgstr ""
-
#: xmodule/vertical_block.py
msgid "Enable in-context discussions for the Unit"
msgstr ""
@@ -14514,10 +14481,6 @@ msgstr "Atsisiųsti kurso dalyvio įvertinimus"
msgid "Print or share your certificate:"
msgstr "Atsispausdinkite arba paskelbkite savo sertifikatą: "
-#: lms/templates/certificates/_accomplishment-banner.html
-msgid "Click the link to see my certificate."
-msgstr "Spustelėkite nuorodą ir pamatysite mano sertifikatą."
-
#: lms/templates/certificates/_accomplishment-banner.html
msgid "Post on Facebook"
msgstr "Skelbti Facebooke"
diff --git a/conf/locale/lt_LT/LC_MESSAGES/djangojs.po b/conf/locale/lt_LT/LC_MESSAGES/djangojs.po
index dfe1e8f34cc9..4c162463f051 100644
--- a/conf/locale/lt_LT/LC_MESSAGES/djangojs.po
+++ b/conf/locale/lt_LT/LC_MESSAGES/djangojs.po
@@ -50,7 +50,7 @@ msgid ""
msgstr ""
"Project-Id-Version: edx-platform\n"
"Report-Msgid-Bugs-To: openedx-translation@googlegroups.com\n"
-"POT-Creation-Date: 2023-08-27 20:42+0000\n"
+"POT-Creation-Date: 2023-09-17 20:42+0000\n"
"PO-Revision-Date: 2014-06-11 15:18+0000\n"
"Last-Translator: Riina , 2014-2015\n"
"Language-Team: Lithuanian (Lithuania) (http://app.transifex.com/open-edx/edx-platform/language/lt_LT/)\n"
@@ -61,14 +61,6 @@ msgstr ""
"Plural-Forms: nplurals=4; plural=(n % 10 == 1 && (n % 100 > 19 || n % 100 < 11) ? 0 : (n % 10 >= 2 && n % 10 <=9) && (n % 100 > 19 || n % 100 < 11) ? 1 : n % 1 != 0 ? 2: 3);\n"
"Generated-By: Babel 2.8.0\n"
-#: cms/static/cms/js/main.js cms/static/js/views/active_video_upload_list.js
-#: cms/static/js/views/video_transcripts.js
-#: xmodule/assets/library_source_block/public/js/library_source_block.js
-msgid ""
-"This may be happening because of an error with our server or your internet "
-"connection. Try refreshing the page or making sure you are online."
-msgstr ""
-
#: cms/static/cms/js/xblock/cms.runtime.v1.js
#: cms/static/js/certificates/views/signatory_details.js
#: cms/static/js/models/section.js cms/static/js/utils/drag_and_drop.js
@@ -80,7 +72,6 @@ msgstr ""
#: cms/static/js/views/modals/edit_xblock.js cms/static/js/views/tabs.js
#: cms/static/js/views/utils/xblock_utils.js lms/static/js/ccx/schedule.js
#: lms/static/js/views/fields.js
-#: xmodule/assets/library_source_block/public/js/library_source_block.js
msgid "Saving"
msgstr "Įrašoma"
@@ -3806,18 +3797,6 @@ msgstr ""
msgid "Updating with latest library content"
msgstr "Atnaujinama naujausiu bibliotekos turiniu"
-#: xmodule/assets/library_source_block/LibrarySourcedBlockPicker.jsx
-msgid "Loading..."
-msgstr ""
-
-#: xmodule/assets/library_source_block/LibrarySourcedBlockPicker.jsx
-msgid "Selected blocks"
-msgstr ""
-
-#: xmodule/assets/library_source_block/public/js/library_source_block.js
-msgid "Unable to update settings"
-msgstr ""
-
#: xmodule/assets/split_test/public/js/split_test_author_view.js
#: xmodule/js/public/js/split_test_author_view.js
msgid "Creating missing groups"
@@ -5447,6 +5426,13 @@ msgstr ""
msgid "Turn off transcripts"
msgstr ""
+#: cms/static/cms/js/main.js cms/static/js/views/active_video_upload_list.js
+#: cms/static/js/views/video_transcripts.js
+msgid ""
+"This may be happening because of an error with our server or your internet "
+"connection. Try refreshing the page or making sure you are online."
+msgstr ""
+
#: cms/static/cms/js/main.js
msgid "Studio's having trouble saving your work"
msgstr ""
@@ -5997,7 +5983,7 @@ msgstr ""
#: cms/static/js/views/course_outline.js
#: cms/static/js/views/pages/container.js
-msgid "New files were added to this course's Files & Uploads"
+msgid "New file(s) added to Files & Uploads."
msgstr ""
#: cms/static/js/views/course_outline.js
@@ -6005,6 +5991,16 @@ msgstr ""
msgid "The following required files were imported to this course:"
msgstr ""
+#: cms/static/js/views/course_outline.js
+#: cms/static/js/views/pages/container.js
+msgid "View files"
+msgstr ""
+
+#: cms/static/js/views/course_outline.js
+#: cms/static/js/views/pages/container.js
+msgid "Dismiss"
+msgstr ""
+
#: cms/static/js/views/course_rerun.js
msgid "Create Re-run"
msgstr "Sukurti pakartojimą"
diff --git a/conf/locale/lv/LC_MESSAGES/django.mo b/conf/locale/lv/LC_MESSAGES/django.mo
index c5bda7187ce9..fa18b15f2578 100644
Binary files a/conf/locale/lv/LC_MESSAGES/django.mo and b/conf/locale/lv/LC_MESSAGES/django.mo differ
diff --git a/conf/locale/lv/LC_MESSAGES/django.po b/conf/locale/lv/LC_MESSAGES/django.po
index ffae1c9aa428..7975d7c8d159 100644
--- a/conf/locale/lv/LC_MESSAGES/django.po
+++ b/conf/locale/lv/LC_MESSAGES/django.po
@@ -49,7 +49,7 @@ msgid ""
msgstr ""
"Project-Id-Version: 0.1a\n"
"Report-Msgid-Bugs-To: openedx-translation@googlegroups.com\n"
-"POT-Creation-Date: 2023-08-27 20:43+0000\n"
+"POT-Creation-Date: 2023-09-17 20:43+0000\n"
"PO-Revision-Date: 2019-01-20 20:43+0000\n"
"Last-Translator: Waheed Ahmed , 2019\n"
"Language-Team: Latvian (https://app.transifex.com/open-edx/teams/6205/lv/)\n"
@@ -149,8 +149,8 @@ msgid "Video"
msgstr "Video"
#: cms/djangoapps/contentstore/views/component.py xmodule/capa_block.py
-msgid "Blank Advanced Problem"
-msgstr "Tukša padziļinātā problēma"
+msgid "Blank Problem"
+msgstr ""
#: cms/djangoapps/contentstore/views/component.py
#: xmodule/video_block/video_block.py
@@ -255,8 +255,8 @@ msgstr "Profesionālā izglītība"
#: common/djangoapps/course_modes/models.py xmodule/annotatable_block.py
#: xmodule/capa_block.py xmodule/conditional_block.py
#: xmodule/discussion_block.py xmodule/html_block.py
-#: xmodule/library_content_block.py xmodule/library_sourced_block.py
-#: xmodule/lti_block.py xmodule/split_test_block.py xmodule/unit_block.py
+#: xmodule/library_content_block.py xmodule/lti_block.py
+#: xmodule/split_test_block.py xmodule/unit_block.py
#: xmodule/word_cloud_block.py xmodule/x_module.py
#: cms/templates/container.html cms/templates/library.html
msgid "Display Name"
@@ -2907,6 +2907,12 @@ msgstr ""
msgid "Open Response Assessment"
msgstr ""
+#: lms/djangoapps/courseware/courses.py
+msgid ""
+"This Open Response Assessment's due dates are set by your instructor and "
+"can't be shifted."
+msgstr ""
+
#: lms/djangoapps/courseware/courses.py
msgid "Self Assessment"
msgstr ""
@@ -2923,12 +2929,6 @@ msgstr ""
msgid "Submission"
msgstr ""
-#: lms/djangoapps/courseware/courses.py
-msgid ""
-"Open Response Assessment due dates are set by your instructor and can't be "
-"shifted."
-msgstr ""
-
#. Translators: 'absolute' is a date such as "Jan 01,
#. 2020". 'relative' is a fuzzy description of the time until
#. 'absolute'. For example, 'absolute' might be "Jan 01, 2020",
@@ -5541,7 +5541,6 @@ msgstr ""
#: lms/templates/oauth2_provider/authorize.html
#: openedx/core/djangoapps/user_api/admin.py
-#: xmodule/templates/library-sourced-block-studio-view.html
msgid "Cancel"
msgstr "Atcelt"
@@ -5990,10 +5989,10 @@ msgid "Quotes"
msgstr "Pēdiņas"
#: lms/templates/wiki/includes/editor_widget.html
-#, python-format
+#, python-brace-format
msgid ""
-"Markdown syntax is allowed. See the %(start_link)scheatsheet%(end_link)s for"
-" help."
+"Markdown syntax is allowed. See the {start_link}cheatsheet{end_link} for "
+"help."
msgstr ""
#: lms/templates/wiki/plugins/attachments/index.html
@@ -6993,8 +6992,8 @@ msgstr ""
#: openedx/core/djangoapps/discussions/models.py
msgid ""
-"The Posting availabilty in discussions whether it will be enabled, scheduled"
-" or indefinitely disabled."
+"The Posting availability in discussions whether it will be enabled, "
+"scheduled or indefinitely disabled."
msgstr ""
#: openedx/core/djangoapps/discussions/models.py
@@ -8896,8 +8895,7 @@ msgstr "XML dati anotācijai"
#: xmodule/annotatable_block.py xmodule/capa_block.py
#: xmodule/conditional_block.py xmodule/discussion_block.py
#: xmodule/html_block.py xmodule/library_content_block.py
-#: xmodule/library_root_xblock.py xmodule/library_sourced_block.py
-#: xmodule/poll_block.py xmodule/unit_block.py
+#: xmodule/library_root_xblock.py xmodule/poll_block.py xmodule/unit_block.py
#: xmodule/video_block/video_xfields.py xmodule/word_cloud_block.py
#: xmodule/x_module.py
msgid "The display name for this component."
@@ -11088,33 +11086,6 @@ msgid "Enter the names of the advanced components to use in your library."
msgstr ""
"Ievadiet to uzlaboto komponentu nosaukumus, kurus izmantot Jūsu bibliotēkā."
-#: xmodule/library_sourced_block.py
-msgid "Library Blocks List"
-msgstr ""
-
-#: xmodule/library_sourced_block.py
-msgid "Enter the IDs of the library XBlocks that you wish to use."
-msgstr ""
-
-#: xmodule/library_sourced_block.py
-#, python-brace-format
-msgid "A maximum of {0} components may be added."
-msgstr ""
-
-#: xmodule/library_sourced_block.py
-msgid ""
-"No XBlock has been configured for this component. Use the editor to select "
-"the target blocks."
-msgstr ""
-
-#: xmodule/library_sourced_block.py
-msgid "Open Editor"
-msgstr ""
-
-#: xmodule/library_sourced_block.py
-msgid "Importing Library Block failed - are the IDs valid and readable?"
-msgstr ""
-
#: xmodule/lti_block.py
msgid ""
"The display name for this component. Analytics reports may also use the "
@@ -11804,10 +11775,6 @@ msgstr "Šim satura eksperimentam ir problēmas, kas ietekmē satura redzamību.
msgid "External Discussion"
msgstr "Ārējā diskusija"
-#: xmodule/templates/library-sourced-block-studio-view.html
-msgid "Save and Import"
-msgstr ""
-
#: xmodule/vertical_block.py
msgid "Enable in-context discussions for the Unit"
msgstr ""
@@ -15495,10 +15462,6 @@ msgstr "Lejupielādēt studentu atzīmes"
msgid "Print or share your certificate:"
msgstr "Izdrukāt vai kopīgot Jūsu sertifikātu:"
-#: lms/templates/certificates/_accomplishment-banner.html
-msgid "Click the link to see my certificate."
-msgstr "Klikšķini uz saites, lai apskatītu manus sertifikātus."
-
#: lms/templates/certificates/_accomplishment-banner.html
msgid "Post on Facebook"
msgstr "Publicēt Facebook"
diff --git a/conf/locale/lv/LC_MESSAGES/djangojs.po b/conf/locale/lv/LC_MESSAGES/djangojs.po
index a2ac32d4f1bf..4dea7b341695 100644
--- a/conf/locale/lv/LC_MESSAGES/djangojs.po
+++ b/conf/locale/lv/LC_MESSAGES/djangojs.po
@@ -40,7 +40,7 @@ msgid ""
msgstr ""
"Project-Id-Version: edx-platform\n"
"Report-Msgid-Bugs-To: openedx-translation@googlegroups.com\n"
-"POT-Creation-Date: 2023-08-27 20:42+0000\n"
+"POT-Creation-Date: 2023-09-17 20:42+0000\n"
"PO-Revision-Date: 2014-06-11 15:18+0000\n"
"Last-Translator: LTMC Latvijas Tiesnešu mācību centrs , 2019\n"
"Language-Team: Latvian (http://app.transifex.com/open-edx/edx-platform/language/lv/)\n"
@@ -51,14 +51,6 @@ msgstr ""
"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n != 0 ? 1 : 2);\n"
"Generated-By: Babel 2.8.0\n"
-#: cms/static/cms/js/main.js cms/static/js/views/active_video_upload_list.js
-#: cms/static/js/views/video_transcripts.js
-#: xmodule/assets/library_source_block/public/js/library_source_block.js
-msgid ""
-"This may be happening because of an error with our server or your internet "
-"connection. Try refreshing the page or making sure you are online."
-msgstr ""
-
#: cms/static/cms/js/xblock/cms.runtime.v1.js
#: cms/static/js/certificates/views/signatory_details.js
#: cms/static/js/models/section.js cms/static/js/utils/drag_and_drop.js
@@ -70,7 +62,6 @@ msgstr ""
#: cms/static/js/views/modals/edit_xblock.js cms/static/js/views/tabs.js
#: cms/static/js/views/utils/xblock_utils.js lms/static/js/ccx/schedule.js
#: lms/static/js/views/fields.js
-#: xmodule/assets/library_source_block/public/js/library_source_block.js
msgid "Saving"
msgstr "Saglabā"
@@ -3999,18 +3990,6 @@ msgstr "Profils"
msgid "Updating with latest library content"
msgstr "Atjaunina ar jaunāko bibliotēkas saturu"
-#: xmodule/assets/library_source_block/LibrarySourcedBlockPicker.jsx
-msgid "Loading..."
-msgstr ""
-
-#: xmodule/assets/library_source_block/LibrarySourcedBlockPicker.jsx
-msgid "Selected blocks"
-msgstr ""
-
-#: xmodule/assets/library_source_block/public/js/library_source_block.js
-msgid "Unable to update settings"
-msgstr ""
-
#: xmodule/assets/split_test/public/js/split_test_author_view.js
#: xmodule/js/public/js/split_test_author_view.js
msgid "Creating missing groups"
@@ -5668,6 +5647,13 @@ msgstr "Ieslēgt norakstus"
msgid "Turn off transcripts"
msgstr "Izslēgt norakstus"
+#: cms/static/cms/js/main.js cms/static/js/views/active_video_upload_list.js
+#: cms/static/js/views/video_transcripts.js
+msgid ""
+"This may be happening because of an error with our server or your internet "
+"connection. Try refreshing the page or making sure you are online."
+msgstr ""
+
#: cms/static/cms/js/main.js
msgid "Studio's having trouble saving your work"
msgstr ""
@@ -6208,7 +6194,7 @@ msgstr ""
#: cms/static/js/views/course_outline.js
#: cms/static/js/views/pages/container.js
-msgid "New files were added to this course's Files & Uploads"
+msgid "New file(s) added to Files & Uploads."
msgstr ""
#: cms/static/js/views/course_outline.js
@@ -6216,6 +6202,16 @@ msgstr ""
msgid "The following required files were imported to this course:"
msgstr ""
+#: cms/static/js/views/course_outline.js
+#: cms/static/js/views/pages/container.js
+msgid "View files"
+msgstr ""
+
+#: cms/static/js/views/course_outline.js
+#: cms/static/js/views/pages/container.js
+msgid "Dismiss"
+msgstr ""
+
#: cms/static/js/views/course_rerun.js
msgid "Create Re-run"
msgstr ""
diff --git a/conf/locale/mn/LC_MESSAGES/django.mo b/conf/locale/mn/LC_MESSAGES/django.mo
index 905f148164b4..d96551f83c82 100644
Binary files a/conf/locale/mn/LC_MESSAGES/django.mo and b/conf/locale/mn/LC_MESSAGES/django.mo differ
diff --git a/conf/locale/mn/LC_MESSAGES/django.po b/conf/locale/mn/LC_MESSAGES/django.po
index 26dd655a018d..e7ad5f189ee8 100644
--- a/conf/locale/mn/LC_MESSAGES/django.po
+++ b/conf/locale/mn/LC_MESSAGES/django.po
@@ -74,7 +74,7 @@ msgid ""
msgstr ""
"Project-Id-Version: 0.1a\n"
"Report-Msgid-Bugs-To: openedx-translation@googlegroups.com\n"
-"POT-Creation-Date: 2023-08-27 20:43+0000\n"
+"POT-Creation-Date: 2023-09-17 20:43+0000\n"
"PO-Revision-Date: 2019-01-20 20:43+0000\n"
"Last-Translator: Waheed Ahmed , 2019\n"
"Language-Team: Mongolian (https://app.transifex.com/open-edx/teams/6205/mn/)\n"
@@ -173,8 +173,8 @@ msgid "Video"
msgstr "Видео"
#: cms/djangoapps/contentstore/views/component.py xmodule/capa_block.py
-msgid "Blank Advanced Problem"
-msgstr "Ахисан түвшний хоосон даалгавар"
+msgid "Blank Problem"
+msgstr ""
#: cms/djangoapps/contentstore/views/component.py
#: xmodule/video_block/video_block.py
@@ -278,8 +278,8 @@ msgstr "Мэргэжлийн боловсрол"
#: common/djangoapps/course_modes/models.py xmodule/annotatable_block.py
#: xmodule/capa_block.py xmodule/conditional_block.py
#: xmodule/discussion_block.py xmodule/html_block.py
-#: xmodule/library_content_block.py xmodule/library_sourced_block.py
-#: xmodule/lti_block.py xmodule/split_test_block.py xmodule/unit_block.py
+#: xmodule/library_content_block.py xmodule/lti_block.py
+#: xmodule/split_test_block.py xmodule/unit_block.py
#: xmodule/word_cloud_block.py xmodule/x_module.py
#: cms/templates/container.html cms/templates/library.html
msgid "Display Name"
@@ -2806,6 +2806,12 @@ msgstr ""
msgid "Open Response Assessment"
msgstr ""
+#: lms/djangoapps/courseware/courses.py
+msgid ""
+"This Open Response Assessment's due dates are set by your instructor and "
+"can't be shifted."
+msgstr ""
+
#: lms/djangoapps/courseware/courses.py
msgid "Self Assessment"
msgstr ""
@@ -2822,12 +2828,6 @@ msgstr ""
msgid "Submission"
msgstr ""
-#: lms/djangoapps/courseware/courses.py
-msgid ""
-"Open Response Assessment due dates are set by your instructor and can't be "
-"shifted."
-msgstr ""
-
#. Translators: 'absolute' is a date such as "Jan 01,
#. 2020". 'relative' is a fuzzy description of the time until
#. 'absolute'. For example, 'absolute' might be "Jan 01, 2020",
@@ -5272,7 +5272,6 @@ msgstr ""
#: lms/templates/oauth2_provider/authorize.html
#: openedx/core/djangoapps/user_api/admin.py
-#: xmodule/templates/library-sourced-block-studio-view.html
msgid "Cancel"
msgstr "Болих"
@@ -5713,10 +5712,10 @@ msgid "Quotes"
msgstr ""
#: lms/templates/wiki/includes/editor_widget.html
-#, python-format
+#, python-brace-format
msgid ""
-"Markdown syntax is allowed. See the %(start_link)scheatsheet%(end_link)s for"
-" help."
+"Markdown syntax is allowed. See the {start_link}cheatsheet{end_link} for "
+"help."
msgstr ""
#: wiki/plugins/attachments/templates/wiki/plugins/attachments/index.html
@@ -6658,8 +6657,8 @@ msgstr ""
#: openedx/core/djangoapps/discussions/models.py
msgid ""
-"The Posting availabilty in discussions whether it will be enabled, scheduled"
-" or indefinitely disabled."
+"The Posting availability in discussions whether it will be enabled, "
+"scheduled or indefinitely disabled."
msgstr ""
#: openedx/core/djangoapps/discussions/models.py
@@ -8466,8 +8465,7 @@ msgstr "Тэмдэглэгээний XML өгөгдөл"
#: xmodule/annotatable_block.py xmodule/capa_block.py
#: xmodule/conditional_block.py xmodule/discussion_block.py
#: xmodule/html_block.py xmodule/library_content_block.py
-#: xmodule/library_root_xblock.py xmodule/library_sourced_block.py
-#: xmodule/poll_block.py xmodule/unit_block.py
+#: xmodule/library_root_xblock.py xmodule/poll_block.py xmodule/unit_block.py
#: xmodule/video_block/video_xfields.py xmodule/word_cloud_block.py
#: xmodule/x_module.py
msgid "The display name for this component."
@@ -10454,33 +10452,6 @@ msgstr ""
msgid "Enter the names of the advanced components to use in your library."
msgstr ""
-#: xmodule/library_sourced_block.py
-msgid "Library Blocks List"
-msgstr ""
-
-#: xmodule/library_sourced_block.py
-msgid "Enter the IDs of the library XBlocks that you wish to use."
-msgstr ""
-
-#: xmodule/library_sourced_block.py
-#, python-brace-format
-msgid "A maximum of {0} components may be added."
-msgstr ""
-
-#: xmodule/library_sourced_block.py
-msgid ""
-"No XBlock has been configured for this component. Use the editor to select "
-"the target blocks."
-msgstr ""
-
-#: xmodule/library_sourced_block.py
-msgid "Open Editor"
-msgstr ""
-
-#: xmodule/library_sourced_block.py
-msgid "Importing Library Block failed - are the IDs valid and readable?"
-msgstr ""
-
#: xmodule/lti_block.py
msgid ""
"The display name for this component. Analytics reports may also use the "
@@ -11069,10 +11040,6 @@ msgstr ""
msgid "External Discussion"
msgstr ""
-#: xmodule/templates/library-sourced-block-studio-view.html
-msgid "Save and Import"
-msgstr ""
-
#: xmodule/vertical_block.py
msgid "Enable in-context discussions for the Unit"
msgstr ""
@@ -14539,10 +14506,6 @@ msgstr ""
msgid "Print or share your certificate:"
msgstr ""
-#: lms/templates/certificates/_accomplishment-banner.html
-msgid "Click the link to see my certificate."
-msgstr ""
-
#: lms/templates/certificates/_accomplishment-banner.html
msgid "Post on Facebook"
msgstr ""
diff --git a/conf/locale/mn/LC_MESSAGES/djangojs.po b/conf/locale/mn/LC_MESSAGES/djangojs.po
index 127bf8e0612b..a5fbdfbfaa83 100644
--- a/conf/locale/mn/LC_MESSAGES/djangojs.po
+++ b/conf/locale/mn/LC_MESSAGES/djangojs.po
@@ -63,7 +63,7 @@ msgid ""
msgstr ""
"Project-Id-Version: edx-platform\n"
"Report-Msgid-Bugs-To: openedx-translation@googlegroups.com\n"
-"POT-Creation-Date: 2023-08-27 20:42+0000\n"
+"POT-Creation-Date: 2023-09-17 20:42+0000\n"
"PO-Revision-Date: 2014-06-11 15:18+0000\n"
"Last-Translator: Myagmarjav Enkhbileg , 2018\n"
"Language-Team: Mongolian (http://app.transifex.com/open-edx/edx-platform/language/mn/)\n"
@@ -74,14 +74,6 @@ msgstr ""
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
"Generated-By: Babel 2.8.0\n"
-#: cms/static/cms/js/main.js cms/static/js/views/active_video_upload_list.js
-#: cms/static/js/views/video_transcripts.js
-#: xmodule/assets/library_source_block/public/js/library_source_block.js
-msgid ""
-"This may be happening because of an error with our server or your internet "
-"connection. Try refreshing the page or making sure you are online."
-msgstr ""
-
#: cms/static/cms/js/xblock/cms.runtime.v1.js
#: cms/static/js/certificates/views/signatory_details.js
#: cms/static/js/models/section.js cms/static/js/utils/drag_and_drop.js
@@ -93,7 +85,6 @@ msgstr ""
#: cms/static/js/views/modals/edit_xblock.js cms/static/js/views/tabs.js
#: cms/static/js/views/utils/xblock_utils.js lms/static/js/ccx/schedule.js
#: lms/static/js/views/fields.js
-#: xmodule/assets/library_source_block/public/js/library_source_block.js
msgid "Saving"
msgstr "Хадгалж байна"
@@ -3747,18 +3738,6 @@ msgstr "Профайл"
msgid "Updating with latest library content"
msgstr "Сангийн агуулгыг сүүлийн хувилбараар шинэчилж байна. "
-#: xmodule/assets/library_source_block/LibrarySourcedBlockPicker.jsx
-msgid "Loading..."
-msgstr ""
-
-#: xmodule/assets/library_source_block/LibrarySourcedBlockPicker.jsx
-msgid "Selected blocks"
-msgstr ""
-
-#: xmodule/assets/library_source_block/public/js/library_source_block.js
-msgid "Unable to update settings"
-msgstr ""
-
#: xmodule/assets/split_test/public/js/split_test_author_view.js
#: xmodule/js/public/js/split_test_author_view.js
msgid "Creating missing groups"
@@ -5360,6 +5339,13 @@ msgstr ""
msgid "Turn off transcripts"
msgstr ""
+#: cms/static/cms/js/main.js cms/static/js/views/active_video_upload_list.js
+#: cms/static/js/views/video_transcripts.js
+msgid ""
+"This may be happening because of an error with our server or your internet "
+"connection. Try refreshing the page or making sure you are online."
+msgstr ""
+
#: cms/static/cms/js/main.js
msgid "Studio's having trouble saving your work"
msgstr "Хадгалах явцад асуудал үүслээ. "
@@ -5903,7 +5889,7 @@ msgstr ""
#: cms/static/js/views/course_outline.js
#: cms/static/js/views/pages/container.js
-msgid "New files were added to this course's Files & Uploads"
+msgid "New file(s) added to Files & Uploads."
msgstr ""
#: cms/static/js/views/course_outline.js
@@ -5911,6 +5897,16 @@ msgstr ""
msgid "The following required files were imported to this course:"
msgstr ""
+#: cms/static/js/views/course_outline.js
+#: cms/static/js/views/pages/container.js
+msgid "View files"
+msgstr ""
+
+#: cms/static/js/views/course_outline.js
+#: cms/static/js/views/pages/container.js
+msgid "Dismiss"
+msgstr ""
+
#: cms/static/js/views/course_rerun.js
msgid "Create Re-run"
msgstr "Ахиж ажиллуулах горимыг үүсгэх"
diff --git a/conf/locale/pl/LC_MESSAGES/django.mo b/conf/locale/pl/LC_MESSAGES/django.mo
index c686274b61c0..75876fc64879 100644
Binary files a/conf/locale/pl/LC_MESSAGES/django.mo and b/conf/locale/pl/LC_MESSAGES/django.mo differ
diff --git a/conf/locale/pl/LC_MESSAGES/django.po b/conf/locale/pl/LC_MESSAGES/django.po
index 113a52b2a34b..63d7c1340ec5 100644
--- a/conf/locale/pl/LC_MESSAGES/django.po
+++ b/conf/locale/pl/LC_MESSAGES/django.po
@@ -150,7 +150,7 @@ msgid ""
msgstr ""
"Project-Id-Version: 0.1a\n"
"Report-Msgid-Bugs-To: openedx-translation@googlegroups.com\n"
-"POT-Creation-Date: 2023-08-27 20:43+0000\n"
+"POT-Creation-Date: 2023-09-17 20:43+0000\n"
"PO-Revision-Date: 2019-01-20 20:43+0000\n"
"Last-Translator: Marcin Miłek, 2022\n"
"Language-Team: Polish (https://app.transifex.com/open-edx/teams/6205/pl/)\n"
@@ -249,8 +249,8 @@ msgid "Video"
msgstr "Film"
#: cms/djangoapps/contentstore/views/component.py xmodule/capa_block.py
-msgid "Blank Advanced Problem"
-msgstr "Puste ćwiczenie zaawansowane"
+msgid "Blank Problem"
+msgstr ""
#: cms/djangoapps/contentstore/views/component.py
#: xmodule/video_block/video_block.py
@@ -354,8 +354,8 @@ msgstr "Edukacja specjalistyczna"
#: common/djangoapps/course_modes/models.py xmodule/annotatable_block.py
#: xmodule/capa_block.py xmodule/conditional_block.py
#: xmodule/discussion_block.py xmodule/html_block.py
-#: xmodule/library_content_block.py xmodule/library_sourced_block.py
-#: xmodule/lti_block.py xmodule/split_test_block.py xmodule/unit_block.py
+#: xmodule/library_content_block.py xmodule/lti_block.py
+#: xmodule/split_test_block.py xmodule/unit_block.py
#: xmodule/word_cloud_block.py xmodule/x_module.py
#: cms/templates/container.html cms/templates/library.html
msgid "Display Name"
@@ -3028,6 +3028,12 @@ msgstr ""
msgid "Open Response Assessment"
msgstr ""
+#: lms/djangoapps/courseware/courses.py
+msgid ""
+"This Open Response Assessment's due dates are set by your instructor and "
+"can't be shifted."
+msgstr ""
+
#: lms/djangoapps/courseware/courses.py
msgid "Self Assessment"
msgstr ""
@@ -3044,12 +3050,6 @@ msgstr ""
msgid "Submission"
msgstr ""
-#: lms/djangoapps/courseware/courses.py
-msgid ""
-"Open Response Assessment due dates are set by your instructor and can't be "
-"shifted."
-msgstr ""
-
#. Translators: 'absolute' is a date such as "Jan 01,
#. 2020". 'relative' is a fuzzy description of the time until
#. 'absolute'. For example, 'absolute' might be "Jan 01, 2020",
@@ -5674,7 +5674,6 @@ msgstr ""
#: lms/templates/oauth2_provider/authorize.html
#: openedx/core/djangoapps/user_api/admin.py
-#: xmodule/templates/library-sourced-block-studio-view.html
#: cms/templates/course-create-rerun.html cms/templates/index.html
#: cms/templates/manage_users.html cms/templates/manage_users_lib.html
#: cms/templates/videos_index_pagination.html
@@ -6123,10 +6122,10 @@ msgid "Quotes"
msgstr "Cytaty"
#: lms/templates/wiki/includes/editor_widget.html
-#, python-format
+#, python-brace-format
msgid ""
-"Markdown syntax is allowed. See the %(start_link)scheatsheet%(end_link)s for"
-" help."
+"Markdown syntax is allowed. See the {start_link}cheatsheet{end_link} for "
+"help."
msgstr ""
#: lms/templates/wiki/plugins/attachments/index.html
@@ -7118,8 +7117,8 @@ msgstr ""
#: openedx/core/djangoapps/discussions/models.py
msgid ""
-"The Posting availabilty in discussions whether it will be enabled, scheduled"
-" or indefinitely disabled."
+"The Posting availability in discussions whether it will be enabled, "
+"scheduled or indefinitely disabled."
msgstr ""
#: openedx/core/djangoapps/discussions/models.py
@@ -8983,8 +8982,7 @@ msgstr "Dane XML dla przypisu"
#: xmodule/annotatable_block.py xmodule/capa_block.py
#: xmodule/conditional_block.py xmodule/discussion_block.py
#: xmodule/html_block.py xmodule/library_content_block.py
-#: xmodule/library_root_xblock.py xmodule/library_sourced_block.py
-#: xmodule/poll_block.py xmodule/unit_block.py
+#: xmodule/library_root_xblock.py xmodule/poll_block.py xmodule/unit_block.py
#: xmodule/video_block/video_xfields.py xmodule/word_cloud_block.py
#: xmodule/x_module.py
msgid "The display name for this component."
@@ -11205,33 +11203,6 @@ msgstr ""
"Wprowadź nazwy elementów zaawansowanych, których chcesz użyć w swojej "
"bibliotece."
-#: xmodule/library_sourced_block.py
-msgid "Library Blocks List"
-msgstr ""
-
-#: xmodule/library_sourced_block.py
-msgid "Enter the IDs of the library XBlocks that you wish to use."
-msgstr ""
-
-#: xmodule/library_sourced_block.py
-#, python-brace-format
-msgid "A maximum of {0} components may be added."
-msgstr ""
-
-#: xmodule/library_sourced_block.py
-msgid ""
-"No XBlock has been configured for this component. Use the editor to select "
-"the target blocks."
-msgstr ""
-
-#: xmodule/library_sourced_block.py
-msgid "Open Editor"
-msgstr ""
-
-#: xmodule/library_sourced_block.py
-msgid "Importing Library Block failed - are the IDs valid and readable?"
-msgstr ""
-
#: xmodule/lti_block.py
msgid ""
"The display name for this component. Analytics reports may also use the "
@@ -11917,10 +11888,6 @@ msgstr ""
msgid "External Discussion"
msgstr "Zewnętrzna dyskusja"
-#: xmodule/templates/library-sourced-block-studio-view.html
-msgid "Save and Import"
-msgstr ""
-
#: xmodule/vertical_block.py
msgid "Enable in-context discussions for the Unit"
msgstr ""
@@ -15719,10 +15686,6 @@ msgstr "Pobierz oceny studenta"
msgid "Print or share your certificate:"
msgstr "Wydrukuj lub udostępnij swój certyfikat:"
-#: lms/templates/certificates/_accomplishment-banner.html
-msgid "Click the link to see my certificate."
-msgstr "Kliknij w odnośnik, aby wyświetlić mój certyfikat."
-
#: lms/templates/certificates/_accomplishment-banner.html
msgid "Post on Facebook"
msgstr "Opublikuj na Facebook'u"
diff --git a/conf/locale/pl/LC_MESSAGES/djangojs.po b/conf/locale/pl/LC_MESSAGES/djangojs.po
index 237953c5da81..e9a391e6c78d 100644
--- a/conf/locale/pl/LC_MESSAGES/djangojs.po
+++ b/conf/locale/pl/LC_MESSAGES/djangojs.po
@@ -32,6 +32,7 @@
# Ola Kleniewska , 2016
# Piotr Jańczuk , 2015
# Radek , 2015
+# Robert Zieliński, 2023
# Sebastian , 2014
# Jaroslaw Lukawski , 2014
# Dyfeomorfizm , 2014
@@ -115,7 +116,7 @@ msgid ""
msgstr ""
"Project-Id-Version: edx-platform\n"
"Report-Msgid-Bugs-To: openedx-translation@googlegroups.com\n"
-"POT-Creation-Date: 2023-08-27 20:42+0000\n"
+"POT-Creation-Date: 2023-09-17 20:42+0000\n"
"PO-Revision-Date: 2014-06-11 15:18+0000\n"
"Last-Translator: Klara Sielicka-Baryłka, 2022\n"
"Language-Team: Polish (http://app.transifex.com/open-edx/edx-platform/language/pl/)\n"
@@ -126,14 +127,6 @@ msgstr ""
"Plural-Forms: nplurals=4; plural=(n==1 ? 0 : (n%10>=2 && n%10<=4) && (n%100<12 || n%100>14) ? 1 : n!=1 && (n%10>=0 && n%10<=1) || (n%10>=5 && n%10<=9) || (n%100>=12 && n%100<=14) ? 2 : 3);\n"
"Generated-By: Babel 2.8.0\n"
-#: cms/static/cms/js/main.js cms/static/js/views/active_video_upload_list.js
-#: cms/static/js/views/video_transcripts.js
-#: xmodule/assets/library_source_block/public/js/library_source_block.js
-msgid ""
-"This may be happening because of an error with our server or your internet "
-"connection. Try refreshing the page or making sure you are online."
-msgstr ""
-
#: cms/static/cms/js/xblock/cms.runtime.v1.js
#: cms/static/js/certificates/views/signatory_details.js
#: cms/static/js/models/section.js cms/static/js/utils/drag_and_drop.js
@@ -145,7 +138,6 @@ msgstr ""
#: cms/static/js/views/modals/edit_xblock.js cms/static/js/views/tabs.js
#: cms/static/js/views/utils/xblock_utils.js lms/static/js/ccx/schedule.js
#: lms/static/js/views/fields.js
-#: xmodule/assets/library_source_block/public/js/library_source_block.js
msgid "Saving"
msgstr "Zapisywanie"
@@ -4099,18 +4091,6 @@ msgstr "Profil"
msgid "Updating with latest library content"
msgstr "Aktualizacja o najnowszą treść biblioteki"
-#: xmodule/assets/library_source_block/LibrarySourcedBlockPicker.jsx
-msgid "Loading..."
-msgstr ""
-
-#: xmodule/assets/library_source_block/LibrarySourcedBlockPicker.jsx
-msgid "Selected blocks"
-msgstr ""
-
-#: xmodule/assets/library_source_block/public/js/library_source_block.js
-msgid "Unable to update settings"
-msgstr ""
-
#: xmodule/assets/split_test/public/js/split_test_author_view.js
#: xmodule/js/public/js/split_test_author_view.js
msgid "Creating missing groups"
@@ -5725,6 +5705,13 @@ msgstr ""
msgid "Turn off transcripts"
msgstr ""
+#: cms/static/cms/js/main.js cms/static/js/views/active_video_upload_list.js
+#: cms/static/js/views/video_transcripts.js
+msgid ""
+"This may be happening because of an error with our server or your internet "
+"connection. Try refreshing the page or making sure you are online."
+msgstr ""
+
#: cms/static/cms/js/main.js
msgid "Studio's having trouble saving your work"
msgstr ""
@@ -6285,7 +6272,7 @@ msgstr ""
#: cms/static/js/views/course_outline.js
#: cms/static/js/views/pages/container.js
-msgid "New files were added to this course's Files & Uploads"
+msgid "New file(s) added to Files & Uploads."
msgstr ""
#: cms/static/js/views/course_outline.js
@@ -6293,6 +6280,16 @@ msgstr ""
msgid "The following required files were imported to this course:"
msgstr ""
+#: cms/static/js/views/course_outline.js
+#: cms/static/js/views/pages/container.js
+msgid "View files"
+msgstr ""
+
+#: cms/static/js/views/course_outline.js
+#: cms/static/js/views/pages/container.js
+msgid "Dismiss"
+msgstr ""
+
#: cms/static/js/views/course_rerun.js
msgid "Create Re-run"
msgstr "Utwórz wznowienie"
diff --git a/conf/locale/pt_BR/LC_MESSAGES/djangojs.po b/conf/locale/pt_BR/LC_MESSAGES/djangojs.po
index 350d265c594a..80dd53ef4f7f 100644
--- a/conf/locale/pt_BR/LC_MESSAGES/djangojs.po
+++ b/conf/locale/pt_BR/LC_MESSAGES/djangojs.po
@@ -246,7 +246,7 @@ msgid ""
msgstr ""
"Project-Id-Version: edx-platform\n"
"Report-Msgid-Bugs-To: openedx-translation@googlegroups.com\n"
-"POT-Creation-Date: 2023-08-27 20:42+0000\n"
+"POT-Creation-Date: 2023-09-17 20:42+0000\n"
"PO-Revision-Date: 2014-06-11 15:18+0000\n"
"Last-Translator: Rodrigo Rocha , 2020\n"
"Language-Team: Portuguese (Brazil) (http://app.transifex.com/open-edx/edx-platform/language/pt_BR/)\n"
@@ -257,14 +257,6 @@ msgstr ""
"Plural-Forms: nplurals=3; plural=(n == 0 || n == 1) ? 0 : n != 0 && n % 1000000 == 0 ? 1 : 2;\n"
"Generated-By: Babel 2.8.0\n"
-#: cms/static/cms/js/main.js cms/static/js/views/active_video_upload_list.js
-#: cms/static/js/views/video_transcripts.js
-#: xmodule/assets/library_source_block/public/js/library_source_block.js
-msgid ""
-"This may be happening because of an error with our server or your internet "
-"connection. Try refreshing the page or making sure you are online."
-msgstr ""
-
#: cms/static/cms/js/xblock/cms.runtime.v1.js
#: cms/static/js/certificates/views/signatory_details.js
#: cms/static/js/models/section.js cms/static/js/utils/drag_and_drop.js
@@ -276,7 +268,6 @@ msgstr ""
#: cms/static/js/views/modals/edit_xblock.js cms/static/js/views/tabs.js
#: cms/static/js/views/utils/xblock_utils.js lms/static/js/ccx/schedule.js
#: lms/static/js/views/fields.js
-#: xmodule/assets/library_source_block/public/js/library_source_block.js
msgid "Saving"
msgstr "Salvando"
@@ -4009,18 +4000,6 @@ msgstr ""
msgid "Updating with latest library content"
msgstr "Atualizando com o conteúdo mais recente da biblioteca"
-#: xmodule/assets/library_source_block/LibrarySourcedBlockPicker.jsx
-msgid "Loading..."
-msgstr ""
-
-#: xmodule/assets/library_source_block/LibrarySourcedBlockPicker.jsx
-msgid "Selected blocks"
-msgstr ""
-
-#: xmodule/assets/library_source_block/public/js/library_source_block.js
-msgid "Unable to update settings"
-msgstr ""
-
#: xmodule/assets/split_test/public/js/split_test_author_view.js
#: xmodule/js/public/js/split_test_author_view.js
msgid "Creating missing groups"
@@ -5633,6 +5612,13 @@ msgstr ""
msgid "Turn off transcripts"
msgstr ""
+#: cms/static/cms/js/main.js cms/static/js/views/active_video_upload_list.js
+#: cms/static/js/views/video_transcripts.js
+msgid ""
+"This may be happening because of an error with our server or your internet "
+"connection. Try refreshing the page or making sure you are online."
+msgstr ""
+
#: cms/static/cms/js/main.js
msgid "Studio's having trouble saving your work"
msgstr ""
@@ -6188,7 +6174,7 @@ msgstr ""
#: cms/static/js/views/course_outline.js
#: cms/static/js/views/pages/container.js
-msgid "New files were added to this course's Files & Uploads"
+msgid "New file(s) added to Files & Uploads."
msgstr ""
#: cms/static/js/views/course_outline.js
@@ -6196,6 +6182,16 @@ msgstr ""
msgid "The following required files were imported to this course:"
msgstr ""
+#: cms/static/js/views/course_outline.js
+#: cms/static/js/views/pages/container.js
+msgid "View files"
+msgstr ""
+
+#: cms/static/js/views/course_outline.js
+#: cms/static/js/views/pages/container.js
+msgid "Dismiss"
+msgstr ""
+
#: cms/static/js/views/course_rerun.js
msgid "Create Re-run"
msgstr "Criar Reprise"
diff --git a/conf/locale/pt_PT/LC_MESSAGES/django.mo b/conf/locale/pt_PT/LC_MESSAGES/django.mo
index 2bcf6ca20bd0..9315ec0e1cf1 100644
Binary files a/conf/locale/pt_PT/LC_MESSAGES/django.mo and b/conf/locale/pt_PT/LC_MESSAGES/django.mo differ
diff --git a/conf/locale/pt_PT/LC_MESSAGES/django.po b/conf/locale/pt_PT/LC_MESSAGES/django.po
index 9dfa5316e3ef..036bfa2f7027 100644
--- a/conf/locale/pt_PT/LC_MESSAGES/django.po
+++ b/conf/locale/pt_PT/LC_MESSAGES/django.po
@@ -141,7 +141,7 @@ msgid ""
msgstr ""
"Project-Id-Version: 0.1a\n"
"Report-Msgid-Bugs-To: openedx-translation@googlegroups.com\n"
-"POT-Creation-Date: 2023-08-20 20:42+0000\n"
+"POT-Creation-Date: 2023-09-10 20:42+0000\n"
"PO-Revision-Date: 2019-01-20 20:43+0000\n"
"Last-Translator: Cátia Lopes , 2019\n"
"Language-Team: Portuguese (Portugal) (https://app.transifex.com/open-edx/teams/6205/pt_PT/)\n"
@@ -244,8 +244,8 @@ msgid "Video"
msgstr "Vídeo"
#: cms/djangoapps/contentstore/views/component.py xmodule/capa_block.py
-msgid "Blank Advanced Problem"
-msgstr "Problema avançado em branco"
+msgid "Blank Problem"
+msgstr ""
#: cms/djangoapps/contentstore/views/component.py
#: xmodule/video_block/video_block.py
@@ -349,8 +349,8 @@ msgstr "Profissional de Educação"
#: common/djangoapps/course_modes/models.py xmodule/annotatable_block.py
#: xmodule/capa_block.py xmodule/conditional_block.py
#: xmodule/discussion_block.py xmodule/html_block.py
-#: xmodule/library_content_block.py xmodule/library_sourced_block.py
-#: xmodule/lti_block.py xmodule/split_test_block.py xmodule/unit_block.py
+#: xmodule/library_content_block.py xmodule/lti_block.py
+#: xmodule/split_test_block.py xmodule/unit_block.py
#: xmodule/word_cloud_block.py xmodule/x_module.py
#: cms/templates/container.html cms/templates/library.html
msgid "Display Name"
@@ -3226,6 +3226,12 @@ msgstr "Tarefa"
msgid "Open Response Assessment"
msgstr "Questão de Resposta Aberta"
+#: lms/djangoapps/courseware/courses.py
+msgid ""
+"This Open Response Assessment's due dates are set by your instructor and "
+"can't be shifted."
+msgstr ""
+
#: lms/djangoapps/courseware/courses.py
msgid "Self Assessment"
msgstr "Auto-avaliação"
@@ -3242,14 +3248,6 @@ msgstr "Avaliação pela Equipa"
msgid "Submission"
msgstr "Envio"
-#: lms/djangoapps/courseware/courses.py
-msgid ""
-"Open Response Assessment due dates are set by your instructor and can't be "
-"shifted."
-msgstr ""
-"As datas de entrega das questões de resposta aberta são definidas pelo "
-"formador e não podem ser alteradas."
-
#. Translators: 'absolute' is a date such as "Jan 01,
#. 2020". 'relative' is a fuzzy description of the time until
#. 'absolute'. For example, 'absolute' might be "Jan 01, 2020",
@@ -6059,7 +6057,6 @@ msgstr ""
#: lms/templates/oauth2_provider/authorize.html
#: openedx/core/djangoapps/user_api/admin.py
-#: xmodule/templates/library-sourced-block-studio-view.html
#: cms/templates/course-create-rerun.html cms/templates/index.html
#: cms/templates/manage_users.html cms/templates/manage_users_lib.html
#: cms/templates/videos_index_pagination.html
@@ -6525,13 +6522,11 @@ msgid "Quotes"
msgstr "Citações"
#: lms/templates/wiki/includes/editor_widget.html
-#, python-format
+#, python-brace-format
msgid ""
-"Markdown syntax is allowed. See the %(start_link)scheatsheet%(end_link)s for"
-" help."
+"Markdown syntax is allowed. See the {start_link}cheatsheet{end_link} for "
+"help."
msgstr ""
-"Sintaxe de Markdown é permitida. Consulte o %(start_link)s cheatsheet "
-"%(end_link)s para obter ajuda."
#: lms/templates/wiki/plugins/attachments/index.html
#: wiki/plugins/attachments/templates/wiki/plugins/attachments/index.html
@@ -7590,8 +7585,8 @@ msgstr ""
#: openedx/core/djangoapps/discussions/models.py
msgid ""
-"The Posting availabilty in discussions whether it will be enabled, scheduled"
-" or indefinitely disabled."
+"The Posting availability in discussions whether it will be enabled, "
+"scheduled or indefinitely disabled."
msgstr ""
#: openedx/core/djangoapps/discussions/models.py
@@ -9667,8 +9662,7 @@ msgstr "Dados XML para a anotação"
#: xmodule/annotatable_block.py xmodule/capa_block.py
#: xmodule/conditional_block.py xmodule/discussion_block.py
#: xmodule/html_block.py xmodule/library_content_block.py
-#: xmodule/library_root_xblock.py xmodule/library_sourced_block.py
-#: xmodule/poll_block.py xmodule/unit_block.py
+#: xmodule/library_root_xblock.py xmodule/poll_block.py xmodule/unit_block.py
#: xmodule/video_block/video_xfields.py xmodule/word_cloud_block.py
#: xmodule/x_module.py
msgid "The display name for this component."
@@ -11950,37 +11944,6 @@ msgid "Enter the names of the advanced components to use in your library."
msgstr ""
"Insira os nomes dos componentes avançados para utilizar na sua biblioteca."
-#: xmodule/library_sourced_block.py
-msgid "Library Blocks List"
-msgstr "Lista de Blocos da Biblioteca"
-
-#: xmodule/library_sourced_block.py
-msgid "Enter the IDs of the library XBlocks that you wish to use."
-msgstr "Digite os IDs da biblioteca XBlocks que pretende usar."
-
-#: xmodule/library_sourced_block.py
-#, python-brace-format
-msgid "A maximum of {0} components may be added."
-msgstr "Pode-se adicionar um máximo de {0} componentes."
-
-#: xmodule/library_sourced_block.py
-msgid ""
-"No XBlock has been configured for this component. Use the editor to select "
-"the target blocks."
-msgstr ""
-"Nenhum XBlock foi configurado para este componente. Use o editor para "
-"selecionar os blocos de destino."
-
-#: xmodule/library_sourced_block.py
-msgid "Open Editor"
-msgstr "Abrir o Editor"
-
-#: xmodule/library_sourced_block.py
-msgid "Importing Library Block failed - are the IDs valid and readable?"
-msgstr ""
-"A falha na importação do Bloco de Bibliotecas - os IDs são válidos e "
-"legíveis?"
-
#: xmodule/lti_block.py
msgid ""
"The display name for this component. Analytics reports may also use the "
@@ -12695,10 +12658,6 @@ msgstr "Este conteúdo apresenta problemas que afetam a sua visibilidade."
msgid "External Discussion"
msgstr "Debate Externo"
-#: xmodule/templates/library-sourced-block-studio-view.html
-msgid "Save and Import"
-msgstr "Salvar e Importar"
-
#: xmodule/vertical_block.py
msgid "Enable in-context discussions for the Unit"
msgstr "Permitir discussões em contexto para a Unidade"
@@ -16717,10 +16676,6 @@ msgstr "Transferir classificações do estudante"
msgid "Print or share your certificate:"
msgstr "Imprimir ou partilhar o seu certificado:"
-#: lms/templates/certificates/_accomplishment-banner.html
-msgid "Click the link to see my certificate."
-msgstr "Clicar no link para ver o meu certificado."
-
#: lms/templates/certificates/_accomplishment-banner.html
msgid "Post on Facebook"
msgstr "Publicar no Facebook"
diff --git a/conf/locale/pt_PT/LC_MESSAGES/djangojs.mo b/conf/locale/pt_PT/LC_MESSAGES/djangojs.mo
index 0ed9a12ea459..f0c6db6268c6 100644
Binary files a/conf/locale/pt_PT/LC_MESSAGES/djangojs.mo and b/conf/locale/pt_PT/LC_MESSAGES/djangojs.mo differ
diff --git a/conf/locale/pt_PT/LC_MESSAGES/djangojs.po b/conf/locale/pt_PT/LC_MESSAGES/djangojs.po
index 9251955ee79f..a3ef571d2cb1 100644
--- a/conf/locale/pt_PT/LC_MESSAGES/djangojs.po
+++ b/conf/locale/pt_PT/LC_MESSAGES/djangojs.po
@@ -113,7 +113,7 @@ msgid ""
msgstr ""
"Project-Id-Version: edx-platform\n"
"Report-Msgid-Bugs-To: openedx-translation@googlegroups.com\n"
-"POT-Creation-Date: 2023-08-27 20:42+0000\n"
+"POT-Creation-Date: 2023-09-17 20:42+0000\n"
"PO-Revision-Date: 2014-06-11 15:18+0000\n"
"Last-Translator: Ivo Branco , 2021,2023\n"
"Language-Team: Portuguese (Portugal) (http://app.transifex.com/open-edx/edx-platform/language/pt_PT/)\n"
@@ -124,17 +124,6 @@ msgstr ""
"Plural-Forms: nplurals=3; plural=(n == 0 || n == 1) ? 0 : n != 0 && n % 1000000 == 0 ? 1 : 2;\n"
"Generated-By: Babel 2.8.0\n"
-#: cms/static/cms/js/main.js cms/static/js/views/active_video_upload_list.js
-#: cms/static/js/views/video_transcripts.js
-#: xmodule/assets/library_source_block/public/js/library_source_block.js
-msgid ""
-"This may be happening because of an error with our server or your internet "
-"connection. Try refreshing the page or making sure you are online."
-msgstr ""
-"Ocorreu este problema provavelmente devido a um erro com o nosso servidor ou"
-" com a sua ligação à Internet. Atualize a página ou certifique-se que está "
-"online."
-
#: cms/static/cms/js/xblock/cms.runtime.v1.js
#: cms/static/js/certificates/views/signatory_details.js
#: cms/static/js/models/section.js cms/static/js/utils/drag_and_drop.js
@@ -146,7 +135,6 @@ msgstr ""
#: cms/static/js/views/modals/edit_xblock.js cms/static/js/views/tabs.js
#: cms/static/js/views/utils/xblock_utils.js lms/static/js/ccx/schedule.js
#: lms/static/js/views/fields.js
-#: xmodule/assets/library_source_block/public/js/library_source_block.js
msgid "Saving"
msgstr "A guardar"
@@ -4253,18 +4241,6 @@ msgstr "Perfil"
msgid "Updating with latest library content"
msgstr "A atualizar com o conteúdo mais recente"
-#: xmodule/assets/library_source_block/LibrarySourcedBlockPicker.jsx
-msgid "Loading..."
-msgstr "A carregar..."
-
-#: xmodule/assets/library_source_block/LibrarySourcedBlockPicker.jsx
-msgid "Selected blocks"
-msgstr "Blocos selecionados"
-
-#: xmodule/assets/library_source_block/public/js/library_source_block.js
-msgid "Unable to update settings"
-msgstr "Não é possível atualizar configurações"
-
#: xmodule/assets/split_test/public/js/split_test_author_view.js
#: xmodule/js/public/js/split_test_author_view.js
msgid "Creating missing groups"
@@ -5939,6 +5915,13 @@ msgstr "Ativar transcrições"
msgid "Turn off transcripts"
msgstr "Desativar transcrições"
+#: cms/static/cms/js/main.js cms/static/js/views/active_video_upload_list.js
+#: cms/static/js/views/video_transcripts.js
+msgid ""
+"This may be happening because of an error with our server or your internet "
+"connection. Try refreshing the page or making sure you are online."
+msgstr ""
+
#: cms/static/cms/js/main.js
msgid "Studio's having trouble saving your work"
msgstr "O Studio está a ter problemas em gravar o seu trabalho"
@@ -6512,7 +6495,7 @@ msgstr ""
#: cms/static/js/views/course_outline.js
#: cms/static/js/views/pages/container.js
-msgid "New files were added to this course's Files & Uploads"
+msgid "New file(s) added to Files & Uploads."
msgstr ""
#: cms/static/js/views/course_outline.js
@@ -6520,6 +6503,16 @@ msgstr ""
msgid "The following required files were imported to this course:"
msgstr ""
+#: cms/static/js/views/course_outline.js
+#: cms/static/js/views/pages/container.js
+msgid "View files"
+msgstr ""
+
+#: cms/static/js/views/course_outline.js
+#: cms/static/js/views/pages/container.js
+msgid "Dismiss"
+msgstr ""
+
#: cms/static/js/views/course_rerun.js
msgid "Create Re-run"
msgstr "Criar Nova Edição do Curso"
diff --git a/conf/locale/rtl/LC_MESSAGES/django.mo b/conf/locale/rtl/LC_MESSAGES/django.mo
index 27725816c986..3933c6509062 100644
Binary files a/conf/locale/rtl/LC_MESSAGES/django.mo and b/conf/locale/rtl/LC_MESSAGES/django.mo differ
diff --git a/conf/locale/rtl/LC_MESSAGES/django.po b/conf/locale/rtl/LC_MESSAGES/django.po
index 975b6367e7f1..1a218f7dc4fe 100644
--- a/conf/locale/rtl/LC_MESSAGES/django.po
+++ b/conf/locale/rtl/LC_MESSAGES/django.po
@@ -38,8 +38,8 @@ msgid ""
msgstr ""
"Project-Id-Version: 0.1a\n"
"Report-Msgid-Bugs-To: openedx-translation@googlegroups.com\n"
-"POT-Creation-Date: 2023-09-05 15:59+0000\n"
-"PO-Revision-Date: 2023-09-05 15:59:41.440074\n"
+"POT-Creation-Date: 2023-09-24 20:36+0000\n"
+"PO-Revision-Date: 2023-09-24 20:36:20.303017\n"
"Last-Translator: \n"
"Language-Team: openedx-translation \n"
"Language: rtl\n"
@@ -141,8 +141,8 @@ msgid "Video"
msgstr "Vᴉdǝø"
#: cms/djangoapps/contentstore/views/component.py xmodule/capa_block.py
-msgid "Blank Advanced Problem"
-msgstr "Ƀlɐnʞ Ⱥdʌɐnɔǝd Ᵽɹøblǝɯ"
+msgid "Blank Problem"
+msgstr "Ƀlɐnʞ Ᵽɹøblǝɯ"
#: cms/djangoapps/contentstore/views/component.py
#: xmodule/video_block/video_block.py
@@ -247,8 +247,8 @@ msgstr "Ᵽɹøɟǝssᴉønɐl Ɇd"
#: common/djangoapps/course_modes/models.py xmodule/annotatable_block.py
#: xmodule/capa_block.py xmodule/conditional_block.py
#: xmodule/discussion_block.py xmodule/html_block.py
-#: xmodule/library_content_block.py xmodule/library_sourced_block.py
-#: xmodule/lti_block.py xmodule/split_test_block.py xmodule/unit_block.py
+#: xmodule/library_content_block.py xmodule/lti_block.py
+#: xmodule/split_test_block.py xmodule/unit_block.py
#: xmodule/word_cloud_block.py xmodule/x_module.py
#: cms/templates/container.html cms/templates/library.html
msgid "Display Name"
@@ -3045,6 +3045,14 @@ msgstr "Ⱥssᴉƃnɯǝnʇ"
msgid "Open Response Assessment"
msgstr "Ødǝn Ɍǝsdønsǝ Ⱥssǝssɯǝnʇ"
+#: lms/djangoapps/courseware/courses.py
+msgid ""
+"This Open Response Assessment's due dates are set by your instructor and "
+"can't be shifted."
+msgstr ""
+"Ŧɥᴉs Ødǝn Ɍǝsdønsǝ Ⱥssǝssɯǝnʇ's dnǝ dɐʇǝs ɐɹǝ sǝʇ bʎ ʎønɹ ᴉnsʇɹnɔʇøɹ ɐnd "
+"ɔɐn'ʇ bǝ sɥᴉɟʇǝd."
+
#: lms/djangoapps/courseware/courses.py
msgid "Self Assessment"
msgstr "Sǝlɟ Ⱥssǝssɯǝnʇ"
@@ -3061,14 +3069,6 @@ msgstr "Sʇɐɟɟ Ⱥssǝssɯǝnʇ"
msgid "Submission"
msgstr "Snbɯᴉssᴉøn"
-#: lms/djangoapps/courseware/courses.py
-msgid ""
-"Open Response Assessment due dates are set by your instructor and can't be "
-"shifted."
-msgstr ""
-"Ødǝn Ɍǝsdønsǝ Ⱥssǝssɯǝnʇ dnǝ dɐʇǝs ɐɹǝ sǝʇ bʎ ʎønɹ ᴉnsʇɹnɔʇøɹ ɐnd ɔɐn'ʇ bǝ "
-"sɥᴉɟʇǝd."
-
#. Translators: 'absolute' is a date such as "Jan 01,
#. 2020". 'relative' is a fuzzy description of the time until
#. 'absolute'. For example, 'absolute' might be "Jan 01, 2020",
@@ -5799,7 +5799,6 @@ msgstr ""
#: lms/templates/oauth2_provider/authorize.html
#: openedx/core/djangoapps/user_api/admin.py
-#: xmodule/templates/library-sourced-block-studio-view.html
#: cms/templates/course-create-rerun.html cms/templates/index.html
#: cms/templates/manage_users.html cms/templates/manage_users_lib.html
#: cms/templates/videos_index_pagination.html
@@ -7008,6 +7007,19 @@ msgstr ""
msgid "Original usage key/ID of the thing that is in the clipboard."
msgstr "Øɹᴉƃᴉnɐl nsɐƃǝ ʞǝʎ/ƗĐ øɟ ʇɥǝ ʇɥᴉnƃ ʇɥɐʇ ᴉs ᴉn ʇɥǝ ɔlᴉdbøɐɹd."
+#: openedx/core/djangoapps/content_tagging/models/base.py
+#: wiki/models/article.py
+msgid "owner"
+msgstr "øʍnǝɹ"
+
+#: openedx/core/djangoapps/content_tagging/models/base.py
+msgid ""
+"Organization that is related to this taxonomy.If None, then this taxonomy is"
+" related to all organizations."
+msgstr ""
+"Øɹƃɐnᴉzɐʇᴉøn ʇɥɐʇ ᴉs ɹǝlɐʇǝd ʇø ʇɥᴉs ʇɐxønøɯʎ.Ɨɟ Nønǝ, ʇɥǝn ʇɥᴉs ʇɐxønøɯʎ ᴉs"
+" ɹǝlɐʇǝd ʇø ɐll øɹƃɐnᴉzɐʇᴉøns."
+
#: openedx/core/djangoapps/cors_csrf/models.py
msgid ""
"List of domains that are allowed to make cross-domain requests to this site."
@@ -9019,18 +9031,6 @@ msgstr ""
"Ɏøn ɥɐʌǝ snɔɔǝssɟnllʎ sɥᴉɟʇǝd ʎønɹ ɔønɹsǝ sɔɥǝdnlǝ ɐnd ʎønɹ ɔɐlǝndɐɹ ᴉs nd "
"ʇø dɐʇǝ."
-#: openedx/features/content_tagging/models/base.py wiki/models/article.py
-msgid "owner"
-msgstr "øʍnǝɹ"
-
-#: openedx/features/content_tagging/models/base.py
-msgid ""
-"Organization that is related to this taxonomy.If None, then this taxonomy is"
-" related to all organizations."
-msgstr ""
-"Øɹƃɐnᴉzɐʇᴉøn ʇɥɐʇ ᴉs ɹǝlɐʇǝd ʇø ʇɥᴉs ʇɐxønøɯʎ.Ɨɟ Nønǝ, ʇɥǝn ʇɥᴉs ʇɐxønøɯʎ ᴉs"
-" ɹǝlɐʇǝd ʇø ɐll øɹƃɐnᴉzɐʇᴉøns."
-
#: openedx/features/content_type_gating/models.py
#: openedx/features/course_duration_limits/models.py
#: lms/templates/support/feature_based_enrollments.html
@@ -9356,8 +9356,7 @@ msgstr "XMŁ dɐʇɐ ɟøɹ ʇɥǝ ɐnnøʇɐʇᴉøn"
#: xmodule/annotatable_block.py xmodule/capa_block.py
#: xmodule/conditional_block.py xmodule/discussion_block.py
#: xmodule/html_block.py xmodule/library_content_block.py
-#: xmodule/library_root_xblock.py xmodule/library_sourced_block.py
-#: xmodule/poll_block.py xmodule/unit_block.py
+#: xmodule/library_root_xblock.py xmodule/poll_block.py xmodule/unit_block.py
#: xmodule/video_block/video_xfields.py xmodule/word_cloud_block.py
#: xmodule/x_module.py
msgid "The display name for this component."
@@ -11569,35 +11568,6 @@ msgstr "Łᴉbɹɐɹʎ Đᴉsdlɐʎ Nɐɯǝ"
msgid "Enter the names of the advanced components to use in your library."
msgstr "Ɇnʇǝɹ ʇɥǝ nɐɯǝs øɟ ʇɥǝ ɐdʌɐnɔǝd ɔøɯdønǝnʇs ʇø nsǝ ᴉn ʎønɹ lᴉbɹɐɹʎ."
-#: xmodule/library_sourced_block.py
-msgid "Library Blocks List"
-msgstr "Łᴉbɹɐɹʎ Ƀløɔʞs Łᴉsʇ"
-
-#: xmodule/library_sourced_block.py
-msgid "Enter the IDs of the library XBlocks that you wish to use."
-msgstr "Ɇnʇǝɹ ʇɥǝ ƗĐs øɟ ʇɥǝ lᴉbɹɐɹʎ XɃløɔʞs ʇɥɐʇ ʎøn ʍᴉsɥ ʇø nsǝ."
-
-#: xmodule/library_sourced_block.py
-#, python-brace-format
-msgid "A maximum of {0} components may be added."
-msgstr "Ⱥ ɯɐxᴉɯnɯ øɟ {0} ɔøɯdønǝnʇs ɯɐʎ bǝ ɐddǝd."
-
-#: xmodule/library_sourced_block.py
-msgid ""
-"No XBlock has been configured for this component. Use the editor to select "
-"the target blocks."
-msgstr ""
-"Nø XɃløɔʞ ɥɐs bǝǝn ɔønɟᴉƃnɹǝd ɟøɹ ʇɥᴉs ɔøɯdønǝnʇ. Ʉsǝ ʇɥǝ ǝdᴉʇøɹ ʇø sǝlǝɔʇ "
-"ʇɥǝ ʇɐɹƃǝʇ bløɔʞs."
-
-#: xmodule/library_sourced_block.py
-msgid "Open Editor"
-msgstr "Ødǝn Ɇdᴉʇøɹ"
-
-#: xmodule/library_sourced_block.py
-msgid "Importing Library Block failed - are the IDs valid and readable?"
-msgstr "Ɨɯdøɹʇᴉnƃ Łᴉbɹɐɹʎ Ƀløɔʞ ɟɐᴉlǝd - ɐɹǝ ʇɥǝ ƗĐs ʌɐlᴉd ɐnd ɹǝɐdɐblǝ?"
-
#: xmodule/lti_block.py
msgid ""
"The display name for this component. Analytics reports may also use the "
@@ -12301,10 +12271,6 @@ msgstr "Ŧɥᴉs ɔønʇǝnʇ ǝxdǝɹᴉɯǝnʇ ɥɐs ᴉssnǝs ʇɥɐʇ ɐɟɟ
msgid "External Discussion"
msgstr "Ɇxʇǝɹnɐl Đᴉsɔnssᴉøn"
-#: xmodule/templates/library-sourced-block-studio-view.html
-msgid "Save and Import"
-msgstr "Sɐʌǝ ɐnd Ɨɯdøɹʇ"
-
#: xmodule/vertical_block.py
msgid "Enable in-context discussions for the Unit"
msgstr "Ɇnɐblǝ ᴉn-ɔønʇǝxʇ dᴉsɔnssᴉøns ɟøɹ ʇɥǝ Ʉnᴉʇ"
@@ -16249,10 +16215,6 @@ msgstr "Đøʍnløɐd sʇndǝnʇ ƃɹɐdǝs"
msgid "Print or share your certificate:"
msgstr "Ᵽɹᴉnʇ øɹ sɥɐɹǝ ʎønɹ ɔǝɹʇᴉɟᴉɔɐʇǝ:"
-#: lms/templates/certificates/_accomplishment-banner.html
-msgid "Click the link to see my certificate."
-msgstr "Ȼlᴉɔʞ ʇɥǝ lᴉnʞ ʇø sǝǝ ɯʎ ɔǝɹʇᴉɟᴉɔɐʇǝ."
-
#: lms/templates/certificates/_accomplishment-banner.html
msgid "Post on Facebook"
msgstr "Ᵽøsʇ øn Fɐɔǝbøøʞ"
diff --git a/conf/locale/rtl/LC_MESSAGES/djangojs.mo b/conf/locale/rtl/LC_MESSAGES/djangojs.mo
index f06520bf0e93..d85f0d6e3600 100644
Binary files a/conf/locale/rtl/LC_MESSAGES/djangojs.mo and b/conf/locale/rtl/LC_MESSAGES/djangojs.mo differ
diff --git a/conf/locale/rtl/LC_MESSAGES/djangojs.po b/conf/locale/rtl/LC_MESSAGES/djangojs.po
index 81321709ae26..76d9de1c11e8 100644
--- a/conf/locale/rtl/LC_MESSAGES/djangojs.po
+++ b/conf/locale/rtl/LC_MESSAGES/djangojs.po
@@ -32,8 +32,8 @@ msgid ""
msgstr ""
"Project-Id-Version: 0.1a\n"
"Report-Msgid-Bugs-To: openedx-translation@googlegroups.com\n"
-"POT-Creation-Date: 2023-09-05 15:59+0000\n"
-"PO-Revision-Date: 2023-09-05 15:59:41.261194\n"
+"POT-Creation-Date: 2023-09-24 20:36+0000\n"
+"PO-Revision-Date: 2023-09-24 20:36:20.294880\n"
"Last-Translator: \n"
"Language-Team: openedx-translation \n"
"Language: rtl\n"
@@ -43,16 +43,6 @@ msgstr ""
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
"Generated-By: Babel 2.8.0\n"
-#: cms/static/cms/js/main.js cms/static/js/views/active_video_upload_list.js
-#: cms/static/js/views/video_transcripts.js
-#: xmodule/assets/library_source_block/public/js/library_source_block.js
-msgid ""
-"This may be happening because of an error with our server or your internet "
-"connection. Try refreshing the page or making sure you are online."
-msgstr ""
-"Ŧɥᴉs ɯɐʎ bǝ ɥɐddǝnᴉnƃ bǝɔɐnsǝ øɟ ɐn ǝɹɹøɹ ʍᴉʇɥ ønɹ sǝɹʌǝɹ øɹ ʎønɹ ᴉnʇǝɹnǝʇ "
-"ɔønnǝɔʇᴉøn. Ŧɹʎ ɹǝɟɹǝsɥᴉnƃ ʇɥǝ dɐƃǝ øɹ ɯɐʞᴉnƃ snɹǝ ʎøn ɐɹǝ ønlᴉnǝ."
-
#: cms/static/cms/js/xblock/cms.runtime.v1.js
#: cms/static/js/certificates/views/signatory_details.js
#: cms/static/js/models/section.js cms/static/js/utils/drag_and_drop.js
@@ -64,7 +54,6 @@ msgstr ""
#: cms/static/js/views/modals/edit_xblock.js cms/static/js/views/tabs.js
#: cms/static/js/views/utils/xblock_utils.js lms/static/js/ccx/schedule.js
#: lms/static/js/views/fields.js
-#: xmodule/assets/library_source_block/public/js/library_source_block.js
msgid "Saving"
msgstr "Sɐʌᴉnƃ"
@@ -4070,18 +4059,6 @@ msgstr "Ᵽɹøɟᴉlǝ"
msgid "Updating with latest library content"
msgstr "Ʉddɐʇᴉnƃ ʍᴉʇɥ lɐʇǝsʇ lᴉbɹɐɹʎ ɔønʇǝnʇ"
-#: xmodule/assets/library_source_block/LibrarySourcedBlockPicker.jsx
-msgid "Loading..."
-msgstr "Łøɐdᴉnƃ..."
-
-#: xmodule/assets/library_source_block/LibrarySourcedBlockPicker.jsx
-msgid "Selected blocks"
-msgstr "Sǝlǝɔʇǝd bløɔʞs"
-
-#: xmodule/assets/library_source_block/public/js/library_source_block.js
-msgid "Unable to update settings"
-msgstr "Ʉnɐblǝ ʇø nddɐʇǝ sǝʇʇᴉnƃs"
-
#: xmodule/assets/split_test/public/js/split_test_author_view.js
#: xmodule/js/public/js/split_test_author_view.js
msgid "Creating missing groups"
@@ -5741,6 +5718,15 @@ msgstr "Ŧnɹn øn ʇɹɐnsɔɹᴉdʇs"
msgid "Turn off transcripts"
msgstr "Ŧnɹn øɟɟ ʇɹɐnsɔɹᴉdʇs"
+#: cms/static/cms/js/main.js cms/static/js/views/active_video_upload_list.js
+#: cms/static/js/views/video_transcripts.js
+msgid ""
+"This may be happening because of an error with our server or your internet "
+"connection. Try refreshing the page or making sure you are online."
+msgstr ""
+"Ŧɥᴉs ɯɐʎ bǝ ɥɐddǝnᴉnƃ bǝɔɐnsǝ øɟ ɐn ǝɹɹøɹ ʍᴉʇɥ ønɹ sǝɹʌǝɹ øɹ ʎønɹ ᴉnʇǝɹnǝʇ "
+"ɔønnǝɔʇᴉøn. Ŧɹʎ ɹǝɟɹǝsɥᴉnƃ ʇɥǝ dɐƃǝ øɹ ɯɐʞᴉnƃ snɹǝ ʎøn ɐɹǝ ønlᴉnǝ."
+
#: cms/static/cms/js/main.js
msgid "Studio's having trouble saving your work"
msgstr "Sʇndᴉø's ɥɐʌᴉnƃ ʇɹønblǝ sɐʌᴉnƃ ʎønɹ ʍøɹʞ"
@@ -6302,14 +6288,24 @@ msgstr ""
#: cms/static/js/views/course_outline.js
#: cms/static/js/views/pages/container.js
-msgid "New files were added to this course's Files & Uploads"
-msgstr "Nǝʍ ɟᴉlǝs ʍǝɹǝ ɐddǝd ʇø ʇɥᴉs ɔønɹsǝ's Fᴉlǝs & Ʉdløɐds"
+msgid "New file(s) added to Files & Uploads."
+msgstr "Nǝʍ ɟᴉlǝ(s) ɐddǝd ʇø Fᴉlǝs & Ʉdløɐds."
#: cms/static/js/views/course_outline.js
#: cms/static/js/views/pages/container.js
msgid "The following required files were imported to this course:"
msgstr "Ŧɥǝ ɟølløʍᴉnƃ ɹǝbnᴉɹǝd ɟᴉlǝs ʍǝɹǝ ᴉɯdøɹʇǝd ʇø ʇɥᴉs ɔønɹsǝ:"
+#: cms/static/js/views/course_outline.js
+#: cms/static/js/views/pages/container.js
+msgid "View files"
+msgstr "Vᴉǝʍ ɟᴉlǝs"
+
+#: cms/static/js/views/course_outline.js
+#: cms/static/js/views/pages/container.js
+msgid "Dismiss"
+msgstr "Đᴉsɯᴉss"
+
#: cms/static/js/views/course_rerun.js
msgid "Create Re-run"
msgstr "Ȼɹǝɐʇǝ Ɍǝ-ɹnn"
diff --git a/conf/locale/ru/LC_MESSAGES/djangojs.po b/conf/locale/ru/LC_MESSAGES/djangojs.po
index a68466184f0e..57e9096fc573 100644
--- a/conf/locale/ru/LC_MESSAGES/djangojs.po
+++ b/conf/locale/ru/LC_MESSAGES/djangojs.po
@@ -193,7 +193,7 @@ msgid ""
msgstr ""
"Project-Id-Version: edx-platform\n"
"Report-Msgid-Bugs-To: openedx-translation@googlegroups.com\n"
-"POT-Creation-Date: 2023-08-27 20:42+0000\n"
+"POT-Creation-Date: 2023-09-17 20:42+0000\n"
"PO-Revision-Date: 2014-06-11 15:18+0000\n"
"Last-Translator: ashed , 2022-2023\n"
"Language-Team: Russian (http://app.transifex.com/open-edx/edx-platform/language/ru/)\n"
@@ -204,14 +204,6 @@ msgstr ""
"Plural-Forms: nplurals=4; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<12 || n%100>14) ? 1 : n%10==0 || (n%10>=5 && n%10<=9) || (n%100>=11 && n%100<=14)? 2 : 3);\n"
"Generated-By: Babel 2.8.0\n"
-#: cms/static/cms/js/main.js cms/static/js/views/active_video_upload_list.js
-#: cms/static/js/views/video_transcripts.js
-#: xmodule/assets/library_source_block/public/js/library_source_block.js
-msgid ""
-"This may be happening because of an error with our server or your internet "
-"connection. Try refreshing the page or making sure you are online."
-msgstr ""
-
#: cms/static/cms/js/xblock/cms.runtime.v1.js
#: cms/static/js/certificates/views/signatory_details.js
#: cms/static/js/models/section.js cms/static/js/utils/drag_and_drop.js
@@ -223,7 +215,6 @@ msgstr ""
#: cms/static/js/views/modals/edit_xblock.js cms/static/js/views/tabs.js
#: cms/static/js/views/utils/xblock_utils.js lms/static/js/ccx/schedule.js
#: lms/static/js/views/fields.js
-#: xmodule/assets/library_source_block/public/js/library_source_block.js
msgid "Saving"
msgstr "Сохранение"
@@ -4134,18 +4125,6 @@ msgstr "Профиль"
msgid "Updating with latest library content"
msgstr "Обновление содержимого из актуальной версии библиотеки"
-#: xmodule/assets/library_source_block/LibrarySourcedBlockPicker.jsx
-msgid "Loading..."
-msgstr ""
-
-#: xmodule/assets/library_source_block/LibrarySourcedBlockPicker.jsx
-msgid "Selected blocks"
-msgstr ""
-
-#: xmodule/assets/library_source_block/public/js/library_source_block.js
-msgid "Unable to update settings"
-msgstr ""
-
#: xmodule/assets/split_test/public/js/split_test_author_view.js
#: xmodule/js/public/js/split_test_author_view.js
msgid "Creating missing groups"
@@ -5813,6 +5792,13 @@ msgstr "Включить встроенные субтитры"
msgid "Turn off transcripts"
msgstr "Отключить встроенные субтитры"
+#: cms/static/cms/js/main.js cms/static/js/views/active_video_upload_list.js
+#: cms/static/js/views/video_transcripts.js
+msgid ""
+"This may be happening because of an error with our server or your internet "
+"connection. Try refreshing the page or making sure you are online."
+msgstr ""
+
#: cms/static/cms/js/main.js
msgid "Studio's having trouble saving your work"
msgstr ""
@@ -6370,7 +6356,7 @@ msgstr ""
#: cms/static/js/views/course_outline.js
#: cms/static/js/views/pages/container.js
-msgid "New files were added to this course's Files & Uploads"
+msgid "New file(s) added to Files & Uploads."
msgstr ""
#: cms/static/js/views/course_outline.js
@@ -6378,6 +6364,16 @@ msgstr ""
msgid "The following required files were imported to this course:"
msgstr ""
+#: cms/static/js/views/course_outline.js
+#: cms/static/js/views/pages/container.js
+msgid "View files"
+msgstr ""
+
+#: cms/static/js/views/course_outline.js
+#: cms/static/js/views/pages/container.js
+msgid "Dismiss"
+msgstr ""
+
#: cms/static/js/views/course_rerun.js
msgid "Create Re-run"
msgstr "Создать перезапуск"
diff --git a/conf/locale/sk/LC_MESSAGES/django.po b/conf/locale/sk/LC_MESSAGES/django.po
index 69bf0c5708b7..b161a5287849 100644
--- a/conf/locale/sk/LC_MESSAGES/django.po
+++ b/conf/locale/sk/LC_MESSAGES/django.po
@@ -55,7 +55,7 @@ msgid ""
msgstr ""
"Project-Id-Version: 0.1a\n"
"Report-Msgid-Bugs-To: openedx-translation@googlegroups.com\n"
-"POT-Creation-Date: 2023-08-27 20:43+0000\n"
+"POT-Creation-Date: 2023-09-17 20:43+0000\n"
"PO-Revision-Date: 2019-01-20 20:43+0000\n"
"Last-Translator: Waheed Ahmed , 2019\n"
"Language-Team: Slovak (https://app.transifex.com/open-edx/teams/6205/sk/)\n"
@@ -154,7 +154,7 @@ msgid "Video"
msgstr "Video"
#: cms/djangoapps/contentstore/views/component.py xmodule/capa_block.py
-msgid "Blank Advanced Problem"
+msgid "Blank Problem"
msgstr ""
#: cms/djangoapps/contentstore/views/component.py
@@ -257,8 +257,8 @@ msgstr ""
#: common/djangoapps/course_modes/models.py xmodule/annotatable_block.py
#: xmodule/capa_block.py xmodule/conditional_block.py
#: xmodule/discussion_block.py xmodule/html_block.py
-#: xmodule/library_content_block.py xmodule/library_sourced_block.py
-#: xmodule/lti_block.py xmodule/split_test_block.py xmodule/unit_block.py
+#: xmodule/library_content_block.py xmodule/lti_block.py
+#: xmodule/split_test_block.py xmodule/unit_block.py
#: xmodule/word_cloud_block.py xmodule/x_module.py
#: cms/templates/container.html cms/templates/library.html
msgid "Display Name"
@@ -2806,6 +2806,12 @@ msgstr ""
msgid "Open Response Assessment"
msgstr ""
+#: lms/djangoapps/courseware/courses.py
+msgid ""
+"This Open Response Assessment's due dates are set by your instructor and "
+"can't be shifted."
+msgstr ""
+
#: lms/djangoapps/courseware/courses.py
msgid "Self Assessment"
msgstr ""
@@ -2822,12 +2828,6 @@ msgstr ""
msgid "Submission"
msgstr ""
-#: lms/djangoapps/courseware/courses.py
-msgid ""
-"Open Response Assessment due dates are set by your instructor and can't be "
-"shifted."
-msgstr ""
-
#. Translators: 'absolute' is a date such as "Jan 01,
#. 2020". 'relative' is a fuzzy description of the time until
#. 'absolute'. For example, 'absolute' might be "Jan 01, 2020",
@@ -5319,7 +5319,6 @@ msgstr ""
#: lms/templates/oauth2_provider/authorize.html
#: openedx/core/djangoapps/user_api/admin.py
-#: xmodule/templates/library-sourced-block-studio-view.html
msgid "Cancel"
msgstr "Zrušiť"
@@ -5739,10 +5738,10 @@ msgid "Quotes"
msgstr ""
#: lms/templates/wiki/includes/editor_widget.html
-#, python-format
+#, python-brace-format
msgid ""
-"Markdown syntax is allowed. See the %(start_link)scheatsheet%(end_link)s for"
-" help."
+"Markdown syntax is allowed. See the {start_link}cheatsheet{end_link} for "
+"help."
msgstr ""
#: lms/templates/wiki/plugins/attachments/index.html
@@ -6679,8 +6678,8 @@ msgstr ""
#: openedx/core/djangoapps/discussions/models.py
msgid ""
-"The Posting availabilty in discussions whether it will be enabled, scheduled"
-" or indefinitely disabled."
+"The Posting availability in discussions whether it will be enabled, "
+"scheduled or indefinitely disabled."
msgstr ""
#: openedx/core/djangoapps/discussions/models.py
@@ -8494,8 +8493,7 @@ msgstr ""
#: xmodule/annotatable_block.py xmodule/capa_block.py
#: xmodule/conditional_block.py xmodule/discussion_block.py
#: xmodule/html_block.py xmodule/library_content_block.py
-#: xmodule/library_root_xblock.py xmodule/library_sourced_block.py
-#: xmodule/poll_block.py xmodule/unit_block.py
+#: xmodule/library_root_xblock.py xmodule/poll_block.py xmodule/unit_block.py
#: xmodule/video_block/video_xfields.py xmodule/word_cloud_block.py
#: xmodule/x_module.py
msgid "The display name for this component."
@@ -10476,33 +10474,6 @@ msgstr ""
msgid "Enter the names of the advanced components to use in your library."
msgstr ""
-#: xmodule/library_sourced_block.py
-msgid "Library Blocks List"
-msgstr ""
-
-#: xmodule/library_sourced_block.py
-msgid "Enter the IDs of the library XBlocks that you wish to use."
-msgstr ""
-
-#: xmodule/library_sourced_block.py
-#, python-brace-format
-msgid "A maximum of {0} components may be added."
-msgstr ""
-
-#: xmodule/library_sourced_block.py
-msgid ""
-"No XBlock has been configured for this component. Use the editor to select "
-"the target blocks."
-msgstr ""
-
-#: xmodule/library_sourced_block.py
-msgid "Open Editor"
-msgstr ""
-
-#: xmodule/library_sourced_block.py
-msgid "Importing Library Block failed - are the IDs valid and readable?"
-msgstr ""
-
#: xmodule/lti_block.py
msgid ""
"The display name for this component. Analytics reports may also use the "
@@ -11092,10 +11063,6 @@ msgstr ""
msgid "External Discussion"
msgstr ""
-#: xmodule/templates/library-sourced-block-studio-view.html
-msgid "Save and Import"
-msgstr ""
-
#: xmodule/vertical_block.py
msgid "Enable in-context discussions for the Unit"
msgstr ""
@@ -14592,10 +14559,6 @@ msgstr ""
msgid "Print or share your certificate:"
msgstr ""
-#: lms/templates/certificates/_accomplishment-banner.html
-msgid "Click the link to see my certificate."
-msgstr ""
-
#: lms/templates/certificates/_accomplishment-banner.html
msgid "Post on Facebook"
msgstr ""
diff --git a/conf/locale/sk/LC_MESSAGES/djangojs.po b/conf/locale/sk/LC_MESSAGES/djangojs.po
index 196bbe18d503..1e707b179ada 100644
--- a/conf/locale/sk/LC_MESSAGES/djangojs.po
+++ b/conf/locale/sk/LC_MESSAGES/djangojs.po
@@ -46,7 +46,7 @@ msgid ""
msgstr ""
"Project-Id-Version: edx-platform\n"
"Report-Msgid-Bugs-To: openedx-translation@googlegroups.com\n"
-"POT-Creation-Date: 2023-08-27 20:42+0000\n"
+"POT-Creation-Date: 2023-09-17 20:42+0000\n"
"PO-Revision-Date: 2014-06-11 15:18+0000\n"
"Last-Translator: \n"
"Language-Team: Slovak (http://app.transifex.com/open-edx/edx-platform/language/sk/)\n"
@@ -57,14 +57,6 @@ msgstr ""
"Plural-Forms: nplurals=4; plural=(n % 1 == 0 && n == 1 ? 0 : n % 1 == 0 && n >= 2 && n <= 4 ? 1 : n % 1 != 0 ? 2: 3);\n"
"Generated-By: Babel 2.8.0\n"
-#: cms/static/cms/js/main.js cms/static/js/views/active_video_upload_list.js
-#: cms/static/js/views/video_transcripts.js
-#: xmodule/assets/library_source_block/public/js/library_source_block.js
-msgid ""
-"This may be happening because of an error with our server or your internet "
-"connection. Try refreshing the page or making sure you are online."
-msgstr ""
-
#: cms/static/cms/js/xblock/cms.runtime.v1.js
#: cms/static/js/certificates/views/signatory_details.js
#: cms/static/js/models/section.js cms/static/js/utils/drag_and_drop.js
@@ -76,7 +68,6 @@ msgstr ""
#: cms/static/js/views/modals/edit_xblock.js cms/static/js/views/tabs.js
#: cms/static/js/views/utils/xblock_utils.js lms/static/js/ccx/schedule.js
#: lms/static/js/views/fields.js
-#: xmodule/assets/library_source_block/public/js/library_source_block.js
msgid "Saving"
msgstr "Ukladá sa"
@@ -3745,18 +3736,6 @@ msgstr ""
msgid "Updating with latest library content"
msgstr "Aktualizujem s najnovším obsahom knižnice"
-#: xmodule/assets/library_source_block/LibrarySourcedBlockPicker.jsx
-msgid "Loading..."
-msgstr ""
-
-#: xmodule/assets/library_source_block/LibrarySourcedBlockPicker.jsx
-msgid "Selected blocks"
-msgstr ""
-
-#: xmodule/assets/library_source_block/public/js/library_source_block.js
-msgid "Unable to update settings"
-msgstr ""
-
#: xmodule/assets/split_test/public/js/split_test_author_view.js
#: xmodule/js/public/js/split_test_author_view.js
msgid "Creating missing groups"
@@ -5379,6 +5358,13 @@ msgstr "Zapnúť prepisy"
msgid "Turn off transcripts"
msgstr "Vypnúť prepisy"
+#: cms/static/cms/js/main.js cms/static/js/views/active_video_upload_list.js
+#: cms/static/js/views/video_transcripts.js
+msgid ""
+"This may be happening because of an error with our server or your internet "
+"connection. Try refreshing the page or making sure you are online."
+msgstr ""
+
#: cms/static/cms/js/main.js
msgid "Studio's having trouble saving your work"
msgstr ""
@@ -5927,7 +5913,7 @@ msgstr ""
#: cms/static/js/views/course_outline.js
#: cms/static/js/views/pages/container.js
-msgid "New files were added to this course's Files & Uploads"
+msgid "New file(s) added to Files & Uploads."
msgstr ""
#: cms/static/js/views/course_outline.js
@@ -5935,6 +5921,16 @@ msgstr ""
msgid "The following required files were imported to this course:"
msgstr ""
+#: cms/static/js/views/course_outline.js
+#: cms/static/js/views/pages/container.js
+msgid "View files"
+msgstr ""
+
+#: cms/static/js/views/course_outline.js
+#: cms/static/js/views/pages/container.js
+msgid "Dismiss"
+msgstr ""
+
#: cms/static/js/views/course_rerun.js
msgid "Create Re-run"
msgstr "Vytvoriť reprízu"
diff --git a/conf/locale/sw_KE/LC_MESSAGES/django.mo b/conf/locale/sw_KE/LC_MESSAGES/django.mo
index 7f7d046783cc..9c42f8def880 100644
Binary files a/conf/locale/sw_KE/LC_MESSAGES/django.mo and b/conf/locale/sw_KE/LC_MESSAGES/django.mo differ
diff --git a/conf/locale/sw_KE/LC_MESSAGES/django.po b/conf/locale/sw_KE/LC_MESSAGES/django.po
index 461a420644f2..e3ca02f5c666 100644
--- a/conf/locale/sw_KE/LC_MESSAGES/django.po
+++ b/conf/locale/sw_KE/LC_MESSAGES/django.po
@@ -85,7 +85,7 @@ msgid ""
msgstr ""
"Project-Id-Version: 0.1a\n"
"Report-Msgid-Bugs-To: openedx-translation@googlegroups.com\n"
-"POT-Creation-Date: 2023-08-27 20:43+0000\n"
+"POT-Creation-Date: 2023-09-17 20:43+0000\n"
"PO-Revision-Date: 2019-01-20 20:43+0000\n"
"Last-Translator: Waheed Ahmed , 2019\n"
"Language-Team: Swahili (Kenya) (https://app.transifex.com/open-edx/teams/6205/sw_KE/)\n"
@@ -184,7 +184,7 @@ msgid "Video"
msgstr "Video"
#: cms/djangoapps/contentstore/views/component.py xmodule/capa_block.py
-msgid "Blank Advanced Problem"
+msgid "Blank Problem"
msgstr ""
#: cms/djangoapps/contentstore/views/component.py
@@ -290,8 +290,8 @@ msgstr "Mtaalamu wa Elimu"
#: common/djangoapps/course_modes/models.py xmodule/annotatable_block.py
#: xmodule/capa_block.py xmodule/conditional_block.py
#: xmodule/discussion_block.py xmodule/html_block.py
-#: xmodule/library_content_block.py xmodule/library_sourced_block.py
-#: xmodule/lti_block.py xmodule/split_test_block.py xmodule/unit_block.py
+#: xmodule/library_content_block.py xmodule/lti_block.py
+#: xmodule/split_test_block.py xmodule/unit_block.py
#: xmodule/word_cloud_block.py xmodule/x_module.py
#: cms/templates/container.html cms/templates/library.html
msgid "Display Name"
@@ -2827,6 +2827,12 @@ msgstr ""
msgid "Open Response Assessment"
msgstr ""
+#: lms/djangoapps/courseware/courses.py
+msgid ""
+"This Open Response Assessment's due dates are set by your instructor and "
+"can't be shifted."
+msgstr ""
+
#: lms/djangoapps/courseware/courses.py
msgid "Self Assessment"
msgstr ""
@@ -2843,12 +2849,6 @@ msgstr ""
msgid "Submission"
msgstr ""
-#: lms/djangoapps/courseware/courses.py
-msgid ""
-"Open Response Assessment due dates are set by your instructor and can't be "
-"shifted."
-msgstr ""
-
#. Translators: 'absolute' is a date such as "Jan 01,
#. 2020". 'relative' is a fuzzy description of the time until
#. 'absolute'. For example, 'absolute' might be "Jan 01, 2020",
@@ -5354,7 +5354,6 @@ msgstr ""
#: lms/templates/oauth2_provider/authorize.html
#: openedx/core/djangoapps/user_api/admin.py
-#: xmodule/templates/library-sourced-block-studio-view.html
msgid "Cancel"
msgstr "Batilisha "
@@ -5774,10 +5773,10 @@ msgid "Quotes"
msgstr "Dondoo"
#: lms/templates/wiki/includes/editor_widget.html
-#, python-format
+#, python-brace-format
msgid ""
-"Markdown syntax is allowed. See the %(start_link)scheatsheet%(end_link)s for"
-" help."
+"Markdown syntax is allowed. See the {start_link}cheatsheet{end_link} for "
+"help."
msgstr ""
#: lms/templates/wiki/plugins/attachments/index.html
@@ -6715,8 +6714,8 @@ msgstr ""
#: openedx/core/djangoapps/discussions/models.py
msgid ""
-"The Posting availabilty in discussions whether it will be enabled, scheduled"
-" or indefinitely disabled."
+"The Posting availability in discussions whether it will be enabled, "
+"scheduled or indefinitely disabled."
msgstr ""
#: openedx/core/djangoapps/discussions/models.py
@@ -8557,8 +8556,7 @@ msgstr ""
#: xmodule/annotatable_block.py xmodule/capa_block.py
#: xmodule/conditional_block.py xmodule/discussion_block.py
#: xmodule/html_block.py xmodule/library_content_block.py
-#: xmodule/library_root_xblock.py xmodule/library_sourced_block.py
-#: xmodule/poll_block.py xmodule/unit_block.py
+#: xmodule/library_root_xblock.py xmodule/poll_block.py xmodule/unit_block.py
#: xmodule/video_block/video_xfields.py xmodule/word_cloud_block.py
#: xmodule/x_module.py
msgid "The display name for this component."
@@ -10588,33 +10586,6 @@ msgstr ""
msgid "Enter the names of the advanced components to use in your library."
msgstr ""
-#: xmodule/library_sourced_block.py
-msgid "Library Blocks List"
-msgstr ""
-
-#: xmodule/library_sourced_block.py
-msgid "Enter the IDs of the library XBlocks that you wish to use."
-msgstr ""
-
-#: xmodule/library_sourced_block.py
-#, python-brace-format
-msgid "A maximum of {0} components may be added."
-msgstr ""
-
-#: xmodule/library_sourced_block.py
-msgid ""
-"No XBlock has been configured for this component. Use the editor to select "
-"the target blocks."
-msgstr ""
-
-#: xmodule/library_sourced_block.py
-msgid "Open Editor"
-msgstr ""
-
-#: xmodule/library_sourced_block.py
-msgid "Importing Library Block failed - are the IDs valid and readable?"
-msgstr ""
-
#: xmodule/lti_block.py
msgid ""
"The display name for this component. Analytics reports may also use the "
@@ -11213,10 +11184,6 @@ msgstr ""
msgid "External Discussion"
msgstr "Majadiliano ya Nje"
-#: xmodule/templates/library-sourced-block-studio-view.html
-msgid "Save and Import"
-msgstr ""
-
#: xmodule/vertical_block.py
msgid "Enable in-context discussions for the Unit"
msgstr ""
@@ -14866,10 +14833,6 @@ msgstr "'Pakua mtandaoni' madaraja ya mwanafunzi"
msgid "Print or share your certificate:"
msgstr "Chapisha au tuma cheti chako:"
-#: lms/templates/certificates/_accomplishment-banner.html
-msgid "Click the link to see my certificate."
-msgstr "Bofya kiungo-wavuti uone cheti changu."
-
#: lms/templates/certificates/_accomplishment-banner.html
msgid "Post on Facebook"
msgstr "Bandika kwenye Facebook"
diff --git a/conf/locale/sw_KE/LC_MESSAGES/djangojs.po b/conf/locale/sw_KE/LC_MESSAGES/djangojs.po
index 7db8742c8757..52e1dcbeea93 100644
--- a/conf/locale/sw_KE/LC_MESSAGES/djangojs.po
+++ b/conf/locale/sw_KE/LC_MESSAGES/djangojs.po
@@ -71,7 +71,7 @@ msgid ""
msgstr ""
"Project-Id-Version: edx-platform\n"
"Report-Msgid-Bugs-To: openedx-translation@googlegroups.com\n"
-"POT-Creation-Date: 2023-08-27 20:42+0000\n"
+"POT-Creation-Date: 2023-09-17 20:42+0000\n"
"PO-Revision-Date: 2014-06-11 15:18+0000\n"
"Last-Translator: YAHAYA MWAVURIZI , 2017\n"
"Language-Team: Swahili (Kenya) (http://app.transifex.com/open-edx/edx-platform/language/sw_KE/)\n"
@@ -82,14 +82,6 @@ msgstr ""
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
"Generated-By: Babel 2.8.0\n"
-#: cms/static/cms/js/main.js cms/static/js/views/active_video_upload_list.js
-#: cms/static/js/views/video_transcripts.js
-#: xmodule/assets/library_source_block/public/js/library_source_block.js
-msgid ""
-"This may be happening because of an error with our server or your internet "
-"connection. Try refreshing the page or making sure you are online."
-msgstr ""
-
#: cms/static/cms/js/xblock/cms.runtime.v1.js
#: cms/static/js/certificates/views/signatory_details.js
#: cms/static/js/models/section.js cms/static/js/utils/drag_and_drop.js
@@ -101,7 +93,6 @@ msgstr ""
#: cms/static/js/views/modals/edit_xblock.js cms/static/js/views/tabs.js
#: cms/static/js/views/utils/xblock_utils.js lms/static/js/ccx/schedule.js
#: lms/static/js/views/fields.js
-#: xmodule/assets/library_source_block/public/js/library_source_block.js
msgid "Saving"
msgstr "Kuhifadhi"
@@ -3868,18 +3859,6 @@ msgstr ""
msgid "Updating with latest library content"
msgstr "Sasisha kwa kutumia taarifa mpya za maktaba"
-#: xmodule/assets/library_source_block/LibrarySourcedBlockPicker.jsx
-msgid "Loading..."
-msgstr ""
-
-#: xmodule/assets/library_source_block/LibrarySourcedBlockPicker.jsx
-msgid "Selected blocks"
-msgstr ""
-
-#: xmodule/assets/library_source_block/public/js/library_source_block.js
-msgid "Unable to update settings"
-msgstr ""
-
#: xmodule/assets/split_test/public/js/split_test_author_view.js
#: xmodule/js/public/js/split_test_author_view.js
msgid "Creating missing groups"
@@ -5483,6 +5462,13 @@ msgstr ""
msgid "Turn off transcripts"
msgstr ""
+#: cms/static/cms/js/main.js cms/static/js/views/active_video_upload_list.js
+#: cms/static/js/views/video_transcripts.js
+msgid ""
+"This may be happening because of an error with our server or your internet "
+"connection. Try refreshing the page or making sure you are online."
+msgstr ""
+
#: cms/static/cms/js/main.js
msgid "Studio's having trouble saving your work"
msgstr ""
@@ -6030,7 +6016,7 @@ msgstr ""
#: cms/static/js/views/course_outline.js
#: cms/static/js/views/pages/container.js
-msgid "New files were added to this course's Files & Uploads"
+msgid "New file(s) added to Files & Uploads."
msgstr ""
#: cms/static/js/views/course_outline.js
@@ -6038,6 +6024,16 @@ msgstr ""
msgid "The following required files were imported to this course:"
msgstr ""
+#: cms/static/js/views/course_outline.js
+#: cms/static/js/views/pages/container.js
+msgid "View files"
+msgstr ""
+
+#: cms/static/js/views/course_outline.js
+#: cms/static/js/views/pages/container.js
+msgid "Dismiss"
+msgstr ""
+
#: cms/static/js/views/course_rerun.js
msgid "Create Re-run"
msgstr ""
diff --git a/conf/locale/th/LC_MESSAGES/django.mo b/conf/locale/th/LC_MESSAGES/django.mo
index 2f0e170ec2a3..d038cec3bbb7 100644
Binary files a/conf/locale/th/LC_MESSAGES/django.mo and b/conf/locale/th/LC_MESSAGES/django.mo differ
diff --git a/conf/locale/th/LC_MESSAGES/django.po b/conf/locale/th/LC_MESSAGES/django.po
index fdb8a3fda3e4..b33b18ec2286 100644
--- a/conf/locale/th/LC_MESSAGES/django.po
+++ b/conf/locale/th/LC_MESSAGES/django.po
@@ -116,7 +116,7 @@ msgid ""
msgstr ""
"Project-Id-Version: 0.1a\n"
"Report-Msgid-Bugs-To: openedx-translation@googlegroups.com\n"
-"POT-Creation-Date: 2023-08-27 20:43+0000\n"
+"POT-Creation-Date: 2023-09-17 20:43+0000\n"
"PO-Revision-Date: 2019-01-20 20:43+0000\n"
"Last-Translator: Waheed Ahmed , 2019\n"
"Language-Team: Thai (https://app.transifex.com/open-edx/teams/6205/th/)\n"
@@ -211,7 +211,7 @@ msgid "Video"
msgstr "วีดีโอ"
#: cms/djangoapps/contentstore/views/component.py xmodule/capa_block.py
-msgid "Blank Advanced Problem"
+msgid "Blank Problem"
msgstr ""
#: cms/djangoapps/contentstore/views/component.py
@@ -2742,6 +2742,12 @@ msgstr ""
msgid "Open Response Assessment"
msgstr ""
+#: lms/djangoapps/courseware/courses.py
+msgid ""
+"This Open Response Assessment's due dates are set by your instructor and "
+"can't be shifted."
+msgstr ""
+
#: lms/djangoapps/courseware/courses.py
msgid "Self Assessment"
msgstr ""
@@ -2758,12 +2764,6 @@ msgstr ""
msgid "Submission"
msgstr ""
-#: lms/djangoapps/courseware/courses.py
-msgid ""
-"Open Response Assessment due dates are set by your instructor and can't be "
-"shifted."
-msgstr ""
-
#. Translators: 'absolute' is a date such as "Jan 01,
#. 2020". 'relative' is a fuzzy description of the time until
#. 'absolute'. For example, 'absolute' might be "Jan 01, 2020",
@@ -5190,7 +5190,6 @@ msgstr ""
#: lms/templates/oauth2_provider/authorize.html
#: openedx/core/djangoapps/user_api/admin.py
-#: xmodule/templates/library-sourced-block-studio-view.html
#: cms/templates/course-create-rerun.html cms/templates/index.html
#: cms/templates/manage_users.html cms/templates/manage_users_lib.html
#: cms/templates/videos_index_pagination.html
@@ -5617,10 +5616,10 @@ msgid "Quotes"
msgstr "คำพูด"
#: lms/templates/wiki/includes/editor_widget.html
-#, python-format
+#, python-brace-format
msgid ""
-"Markdown syntax is allowed. See the %(start_link)scheatsheet%(end_link)s for"
-" help."
+"Markdown syntax is allowed. See the {start_link}cheatsheet{end_link} for "
+"help."
msgstr ""
#: lms/templates/wiki/plugins/attachments/index.html
@@ -6538,8 +6537,8 @@ msgstr ""
#: openedx/core/djangoapps/discussions/models.py
msgid ""
-"The Posting availabilty in discussions whether it will be enabled, scheduled"
-" or indefinitely disabled."
+"The Posting availability in discussions whether it will be enabled, "
+"scheduled or indefinitely disabled."
msgstr ""
#: openedx/core/djangoapps/discussions/models.py
@@ -8314,8 +8313,7 @@ msgstr ""
#: xmodule/annotatable_block.py xmodule/capa_block.py
#: xmodule/conditional_block.py xmodule/discussion_block.py
#: xmodule/html_block.py xmodule/library_content_block.py
-#: xmodule/library_root_xblock.py xmodule/library_sourced_block.py
-#: xmodule/poll_block.py xmodule/unit_block.py
+#: xmodule/library_root_xblock.py xmodule/poll_block.py xmodule/unit_block.py
#: xmodule/video_block/video_xfields.py xmodule/word_cloud_block.py
#: xmodule/x_module.py
msgid "The display name for this component."
@@ -10266,33 +10264,6 @@ msgstr ""
msgid "Enter the names of the advanced components to use in your library."
msgstr ""
-#: xmodule/library_sourced_block.py
-msgid "Library Blocks List"
-msgstr ""
-
-#: xmodule/library_sourced_block.py
-msgid "Enter the IDs of the library XBlocks that you wish to use."
-msgstr ""
-
-#: xmodule/library_sourced_block.py
-#, python-brace-format
-msgid "A maximum of {0} components may be added."
-msgstr ""
-
-#: xmodule/library_sourced_block.py
-msgid ""
-"No XBlock has been configured for this component. Use the editor to select "
-"the target blocks."
-msgstr ""
-
-#: xmodule/library_sourced_block.py
-msgid "Open Editor"
-msgstr ""
-
-#: xmodule/library_sourced_block.py
-msgid "Importing Library Block failed - are the IDs valid and readable?"
-msgstr ""
-
#: xmodule/lti_block.py
msgid ""
"The display name for this component. Analytics reports may also use the "
@@ -10880,10 +10851,6 @@ msgstr ""
msgid "External Discussion"
msgstr ""
-#: xmodule/templates/library-sourced-block-studio-view.html
-msgid "Save and Import"
-msgstr ""
-
#: xmodule/vertical_block.py
msgid "Enable in-context discussions for the Unit"
msgstr ""
@@ -14390,10 +14357,6 @@ msgstr "ดาวน์โหลดเกรดของผู้เรียน
msgid "Print or share your certificate:"
msgstr "ปริ้นท์หรือแบ่งปันประกาศนียบัตร"
-#: lms/templates/certificates/_accomplishment-banner.html
-msgid "Click the link to see my certificate."
-msgstr "คลิกที่ลิ้งค์เพื่อดูประกาศนียบัตร"
-
#: lms/templates/certificates/_accomplishment-banner.html
msgid "Post on Facebook"
msgstr "โพสต์บน Facebook"
diff --git a/conf/locale/th/LC_MESSAGES/djangojs.po b/conf/locale/th/LC_MESSAGES/djangojs.po
index 07138edab4ae..727ea417a2bb 100644
--- a/conf/locale/th/LC_MESSAGES/djangojs.po
+++ b/conf/locale/th/LC_MESSAGES/djangojs.po
@@ -73,7 +73,7 @@ msgid ""
msgstr ""
"Project-Id-Version: edx-platform\n"
"Report-Msgid-Bugs-To: openedx-translation@googlegroups.com\n"
-"POT-Creation-Date: 2023-08-27 20:42+0000\n"
+"POT-Creation-Date: 2023-09-17 20:42+0000\n"
"PO-Revision-Date: 2014-06-11 15:18+0000\n"
"Last-Translator: edx demo , 2019\n"
"Language-Team: Thai (http://app.transifex.com/open-edx/edx-platform/language/th/)\n"
@@ -84,14 +84,6 @@ msgstr ""
"Plural-Forms: nplurals=1; plural=0;\n"
"Generated-By: Babel 2.8.0\n"
-#: cms/static/cms/js/main.js cms/static/js/views/active_video_upload_list.js
-#: cms/static/js/views/video_transcripts.js
-#: xmodule/assets/library_source_block/public/js/library_source_block.js
-msgid ""
-"This may be happening because of an error with our server or your internet "
-"connection. Try refreshing the page or making sure you are online."
-msgstr ""
-
#: cms/static/cms/js/xblock/cms.runtime.v1.js
#: cms/static/js/certificates/views/signatory_details.js
#: cms/static/js/models/section.js cms/static/js/utils/drag_and_drop.js
@@ -103,7 +95,6 @@ msgstr ""
#: cms/static/js/views/modals/edit_xblock.js cms/static/js/views/tabs.js
#: cms/static/js/views/utils/xblock_utils.js lms/static/js/ccx/schedule.js
#: lms/static/js/views/fields.js
-#: xmodule/assets/library_source_block/public/js/library_source_block.js
msgid "Saving"
msgstr "กำลังบันทึก"
@@ -3752,18 +3743,6 @@ msgstr ""
msgid "Updating with latest library content"
msgstr "อัพเดทส่วนเนื้อหาจากห้องสมุดล่าสุด"
-#: xmodule/assets/library_source_block/LibrarySourcedBlockPicker.jsx
-msgid "Loading..."
-msgstr ""
-
-#: xmodule/assets/library_source_block/LibrarySourcedBlockPicker.jsx
-msgid "Selected blocks"
-msgstr ""
-
-#: xmodule/assets/library_source_block/public/js/library_source_block.js
-msgid "Unable to update settings"
-msgstr ""
-
#: xmodule/assets/split_test/public/js/split_test_author_view.js
#: xmodule/js/public/js/split_test_author_view.js
msgid "Creating missing groups"
@@ -5362,6 +5341,13 @@ msgstr ""
msgid "Turn off transcripts"
msgstr ""
+#: cms/static/cms/js/main.js cms/static/js/views/active_video_upload_list.js
+#: cms/static/js/views/video_transcripts.js
+msgid ""
+"This may be happening because of an error with our server or your internet "
+"connection. Try refreshing the page or making sure you are online."
+msgstr ""
+
#: cms/static/cms/js/main.js
msgid "Studio's having trouble saving your work"
msgstr ""
@@ -5906,7 +5892,7 @@ msgstr ""
#: cms/static/js/views/course_outline.js
#: cms/static/js/views/pages/container.js
-msgid "New files were added to this course's Files & Uploads"
+msgid "New file(s) added to Files & Uploads."
msgstr ""
#: cms/static/js/views/course_outline.js
@@ -5914,6 +5900,16 @@ msgstr ""
msgid "The following required files were imported to this course:"
msgstr ""
+#: cms/static/js/views/course_outline.js
+#: cms/static/js/views/pages/container.js
+msgid "View files"
+msgstr ""
+
+#: cms/static/js/views/course_outline.js
+#: cms/static/js/views/pages/container.js
+msgid "Dismiss"
+msgstr ""
+
#: cms/static/js/views/course_rerun.js
msgid "Create Re-run"
msgstr "สร้างการทำซ้ำ"
diff --git a/conf/locale/tr_TR/LC_MESSAGES/django.mo b/conf/locale/tr_TR/LC_MESSAGES/django.mo
index bc03b95071f8..7214d36a28c1 100644
Binary files a/conf/locale/tr_TR/LC_MESSAGES/django.mo and b/conf/locale/tr_TR/LC_MESSAGES/django.mo differ
diff --git a/conf/locale/tr_TR/LC_MESSAGES/django.po b/conf/locale/tr_TR/LC_MESSAGES/django.po
index 9d1823fc0f15..2c437e3dec2d 100644
--- a/conf/locale/tr_TR/LC_MESSAGES/django.po
+++ b/conf/locale/tr_TR/LC_MESSAGES/django.po
@@ -132,7 +132,7 @@ msgid ""
msgstr ""
"Project-Id-Version: 0.1a\n"
"Report-Msgid-Bugs-To: openedx-translation@googlegroups.com\n"
-"POT-Creation-Date: 2023-08-20 20:42+0000\n"
+"POT-Creation-Date: 2023-09-10 20:42+0000\n"
"PO-Revision-Date: 2019-01-20 20:43+0000\n"
"Last-Translator: Ali Işıngör , 2021\n"
"Language-Team: Turkish (Turkey) (https://app.transifex.com/open-edx/teams/6205/tr_TR/)\n"
@@ -234,8 +234,8 @@ msgid "Video"
msgstr "Video"
#: cms/djangoapps/contentstore/views/component.py xmodule/capa_block.py
-msgid "Blank Advanced Problem"
-msgstr "Boş Gelişmiş Problem"
+msgid "Blank Problem"
+msgstr "Boş Problem"
#: cms/djangoapps/contentstore/views/component.py
#: xmodule/video_block/video_block.py
@@ -340,8 +340,8 @@ msgstr "Profesyonel Eğitim"
#: common/djangoapps/course_modes/models.py xmodule/annotatable_block.py
#: xmodule/capa_block.py xmodule/conditional_block.py
#: xmodule/discussion_block.py xmodule/html_block.py
-#: xmodule/library_content_block.py xmodule/library_sourced_block.py
-#: xmodule/lti_block.py xmodule/split_test_block.py xmodule/unit_block.py
+#: xmodule/library_content_block.py xmodule/lti_block.py
+#: xmodule/split_test_block.py xmodule/unit_block.py
#: xmodule/word_cloud_block.py xmodule/x_module.py
#: cms/templates/container.html cms/templates/library.html
msgid "Display Name"
@@ -3152,6 +3152,14 @@ msgstr "Görev"
msgid "Open Response Assessment"
msgstr "Açık Yanıt Değerlendirmesi"
+#: lms/djangoapps/courseware/courses.py
+msgid ""
+"This Open Response Assessment's due dates are set by your instructor and "
+"can't be shifted."
+msgstr ""
+"Bu ORA - Açık Cevap Değerlendirmesinin son tarihleri eğitmeniniz tarafından "
+"belirlenir ve değiştirilemez. "
+
#: lms/djangoapps/courseware/courses.py
msgid "Self Assessment"
msgstr "Öz Değerlendirme"
@@ -3168,14 +3176,6 @@ msgstr "Personel Değerlendirmesi"
msgid "Submission"
msgstr "Gönderim"
-#: lms/djangoapps/courseware/courses.py
-msgid ""
-"Open Response Assessment due dates are set by your instructor and can't be "
-"shifted."
-msgstr ""
-"Açık Cevap Değerlendirmesi - ORA son tarihleri eğitmeniniz tarafından "
-"belirlenir ve değiştirilemez. "
-
#. Translators: 'absolute' is a date such as "Jan 01,
#. 2020". 'relative' is a fuzzy description of the time until
#. 'absolute'. For example, 'absolute' might be "Jan 01, 2020",
@@ -3431,7 +3431,7 @@ msgstr "Açık Yanıt Değerlendirmesi Ayarları"
#: lms/djangoapps/courseware/plugins.py
msgid "Course level settings for Open Response Assessment."
-msgstr ""
+msgstr "Açık Cevap Değerlendirmesi için ders seviyesi ayarları."
#: lms/djangoapps/courseware/tabs.py lms/djangoapps/courseware/views/views.py
#: openedx/features/course_experience/__init__.py xmodule/tabs.py
@@ -3710,12 +3710,12 @@ msgstr "İyi"
#. Translators: Replier commented on "your" response to your post
#: lms/djangoapps/discussion/rest_api/utils.py
msgid "your"
-msgstr ""
+msgstr "size"
#. Translators: Replier commented on "their" response to your post
#: lms/djangoapps/discussion/rest_api/utils.py
msgid "their"
-msgstr ""
+msgstr "onlara"
#: lms/djangoapps/discussion/templates/discussion/edx_ace/reportedcontentnotification/email/body.html
#, python-format
@@ -5943,7 +5943,6 @@ msgstr ""
#: lms/templates/oauth2_provider/authorize.html
#: openedx/core/djangoapps/user_api/admin.py
-#: xmodule/templates/library-sourced-block-studio-view.html
#: cms/templates/course-create-rerun.html cms/templates/index.html
#: cms/templates/manage_users.html cms/templates/manage_users_lib.html
#: cms/templates/videos_index_pagination.html
@@ -6409,13 +6408,11 @@ msgid "Quotes"
msgstr "Alıntılar"
#: lms/templates/wiki/includes/editor_widget.html
-#, python-format
+#, python-brace-format
msgid ""
-"Markdown syntax is allowed. See the %(start_link)scheatsheet%(end_link)s for"
-" help."
+"Markdown syntax is allowed. See the {start_link}cheatsheet{end_link} for "
+"help."
msgstr ""
-"Markdown yazımına izin verilmektedir. Yardım için "
-"%(start_link)sipuçları%(end_link)ssayfasına bakın."
#: lms/templates/wiki/plugins/attachments/index.html
#: wiki/plugins/attachments/templates/wiki/plugins/attachments/index.html
@@ -7455,8 +7452,8 @@ msgstr ""
#: openedx/core/djangoapps/discussions/models.py
msgid ""
-"The Posting availabilty in discussions whether it will be enabled, scheduled"
-" or indefinitely disabled."
+"The Posting availability in discussions whether it will be enabled, "
+"scheduled or indefinitely disabled."
msgstr ""
#: openedx/core/djangoapps/discussions/models.py
@@ -7652,6 +7649,8 @@ msgid ""
"<{p}><{strong}>{replier_name}{strong}> responded to your post "
"<{strong}>{post_title}{strong}>{p}>"
msgstr ""
+"<{p}><{strong}>{replier_name}{strong}> gönderinize cevap yazdı "
+"<{strong}>{post_title}{strong}>{p}>"
#: openedx/core/djangoapps/notifications/base_notification.py
#, python-brace-format
@@ -7659,6 +7658,8 @@ msgid ""
"<{p}><{strong}>{username}{strong}> posted "
"<{strong}>{post_title}{strong}>{p}>"
msgstr ""
+"<{p}><{strong}>{username}{strong}> gönderdi "
+"<{strong}>{post_title}{strong}>{p}>"
#: openedx/core/djangoapps/notifications/base_notification.py
#, python-brace-format
@@ -7666,6 +7667,8 @@ msgid ""
"<{p}><{strong}>{username}{strong}> asked "
"<{strong}>{post_title}{strong}>{p}>"
msgstr ""
+"<{p}><{strong}>{username}{strong}> sordu "
+"<{strong}>{post_title}{strong}>{p}>"
#: openedx/core/djangoapps/notifications/base_notification.py
msgid ""
@@ -7679,23 +7682,23 @@ msgstr ""
#: openedx/core/djangoapps/notifications/views.py
msgid "Invalid app name."
-msgstr ""
+msgstr "Geçersiz uygulama adı."
#: openedx/core/djangoapps/notifications/views.py
msgid "Notifications marked as seen."
-msgstr ""
+msgstr "Bildirimler görüldü olarak işaretlendi."
#: openedx/core/djangoapps/notifications/views.py
msgid "Notification marked read."
-msgstr ""
+msgstr "Bildirim okundu olarak işaretlendi."
#: openedx/core/djangoapps/notifications/views.py
msgid "Notifications marked read."
-msgstr ""
+msgstr "Bildirimler okundu olarak işaretlendi."
#: openedx/core/djangoapps/notifications/views.py
msgid "Invalid app_name or notification_id."
-msgstr ""
+msgstr "Geçersiz uyg_adı ya da bildirim_id."
#: openedx/core/djangoapps/oauth_dispatch/models.py
msgid ""
@@ -9516,8 +9519,7 @@ msgstr "Bilgi notu için XML verisi"
#: xmodule/annotatable_block.py xmodule/capa_block.py
#: xmodule/conditional_block.py xmodule/discussion_block.py
#: xmodule/html_block.py xmodule/library_content_block.py
-#: xmodule/library_root_xblock.py xmodule/library_sourced_block.py
-#: xmodule/poll_block.py xmodule/unit_block.py
+#: xmodule/library_root_xblock.py xmodule/poll_block.py xmodule/unit_block.py
#: xmodule/video_block/video_xfields.py xmodule/word_cloud_block.py
#: xmodule/x_module.py
msgid "The display name for this component."
@@ -11768,36 +11770,6 @@ msgstr "Kütüphane Görünen Adı"
msgid "Enter the names of the advanced components to use in your library."
msgstr "Kütüphanenizde kullanmak için gelişmiş bileşenlerin adlarını girin."
-#: xmodule/library_sourced_block.py
-msgid "Library Blocks List"
-msgstr "Kütüphane XBlock Listesi"
-
-#: xmodule/library_sourced_block.py
-msgid "Enter the IDs of the library XBlocks that you wish to use."
-msgstr "Kullanmak istediğiniz kütüphane XBlock'ının kimliğini girin."
-
-#: xmodule/library_sourced_block.py
-#, python-brace-format
-msgid "A maximum of {0} components may be added."
-msgstr "En fazla {0} bileşen eklenebilir."
-
-#: xmodule/library_sourced_block.py
-msgid ""
-"No XBlock has been configured for this component. Use the editor to select "
-"the target blocks."
-msgstr ""
-"Bu bileşen için herhangi bir XBlock yapılandırılmamış. Hedef block seçmek "
-"için editörü kullanın."
-
-#: xmodule/library_sourced_block.py
-msgid "Open Editor"
-msgstr "Açık Düzenleyici"
-
-#: xmodule/library_sourced_block.py
-msgid "Importing Library Block failed - are the IDs valid and readable?"
-msgstr ""
-"Kütüphane Block içe aktarımı başarısız - ID'ler geçerli ve okunabilir mi?"
-
#: xmodule/lti_block.py
msgid ""
"The display name for this component. Analytics reports may also use the "
@@ -12509,10 +12481,6 @@ msgstr "Bu içerik deneyinin içerik görünürlüğünü etkileyen sorunları v
msgid "External Discussion"
msgstr "Harici Tartışma"
-#: xmodule/templates/library-sourced-block-studio-view.html
-msgid "Save and Import"
-msgstr "Kaydet ve İçe Aktar"
-
#: xmodule/vertical_block.py
msgid "Enable in-context discussions for the Unit"
msgstr "Ünite için bağlam içi tartışmaları etkinleştirin"
@@ -16396,10 +16364,6 @@ msgstr "Öğrenci notlarını indir"
msgid "Print or share your certificate:"
msgstr "Sertifikanı yazdır veya paylaş:"
-#: lms/templates/certificates/_accomplishment-banner.html
-msgid "Click the link to see my certificate."
-msgstr "Sertifikanızı görmek için bağlantıya tıklayın."
-
#: lms/templates/certificates/_accomplishment-banner.html
msgid "Post on Facebook"
msgstr "Facebook'ta paylaş"
@@ -19433,7 +19397,7 @@ msgstr "Personel Ekle"
#: lms/templates/instructor/instructor_dashboard_2/membership.html
msgid "Limited Staff"
-msgstr ""
+msgstr "Sınırlı Personel"
#: lms/templates/instructor/instructor_dashboard_2/membership.html
msgid ""
@@ -19442,10 +19406,15 @@ msgid ""
"grades and access all course data. Limited Staff don't have access to your "
"course in Studio. You can only give course team roles to enrolled users."
msgstr ""
+"Sınırlı Personel rolüne sahip ders ekibi üyeleri dersiniz, yönetmenize "
+"yardımcı olur. Sınırlı Personel, öğrencilerin kaydını yapabilir ve "
+"kayıtlarını kaldırabilir, ayrıca notlarını değiştirebilir ve tüm ders "
+"verilerine erişebilir. Sınırlı Personelin Studio'daki dersinize erişimi "
+"yoktur. Ders ekibi rollerini yalnızca kayıtlı kullanıcılara verebilirsiniz."
#: lms/templates/instructor/instructor_dashboard_2/membership.html
msgid "Add Limited Staff"
-msgstr ""
+msgstr "Sınırlı Personel Ekle"
#: lms/templates/instructor/instructor_dashboard_2/membership.html
msgid "Admin"
diff --git a/conf/locale/tr_TR/LC_MESSAGES/djangojs.mo b/conf/locale/tr_TR/LC_MESSAGES/djangojs.mo
index 27b00b941db4..4bbbcaf56a05 100644
Binary files a/conf/locale/tr_TR/LC_MESSAGES/djangojs.mo and b/conf/locale/tr_TR/LC_MESSAGES/djangojs.mo differ
diff --git a/conf/locale/tr_TR/LC_MESSAGES/djangojs.po b/conf/locale/tr_TR/LC_MESSAGES/djangojs.po
index 2fbb569c82a5..b8e157cc2b4f 100644
--- a/conf/locale/tr_TR/LC_MESSAGES/djangojs.po
+++ b/conf/locale/tr_TR/LC_MESSAGES/djangojs.po
@@ -110,7 +110,7 @@ msgid ""
msgstr ""
"Project-Id-Version: edx-platform\n"
"Report-Msgid-Bugs-To: openedx-translation@googlegroups.com\n"
-"POT-Creation-Date: 2023-08-27 20:42+0000\n"
+"POT-Creation-Date: 2023-09-17 20:42+0000\n"
"PO-Revision-Date: 2014-06-11 15:18+0000\n"
"Last-Translator: Ali Işıngör , 2018,2020-2021,2023\n"
"Language-Team: Turkish (Turkey) (http://app.transifex.com/open-edx/edx-platform/language/tr_TR/)\n"
@@ -121,17 +121,6 @@ msgstr ""
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
"Generated-By: Babel 2.8.0\n"
-#: cms/static/cms/js/main.js cms/static/js/views/active_video_upload_list.js
-#: cms/static/js/views/video_transcripts.js
-#: xmodule/assets/library_source_block/public/js/library_source_block.js
-msgid ""
-"This may be happening because of an error with our server or your internet "
-"connection. Try refreshing the page or making sure you are online."
-msgstr ""
-"Bu durum sunucudaki bir hatadan veya İnternet bağlantınızdan kaynaklanmış "
-"olabilir. Sayfayı yeniden yüklemeyi deneyin veya çevrimiçi olduğunuza emin "
-"olun."
-
#: cms/static/cms/js/xblock/cms.runtime.v1.js
#: cms/static/js/certificates/views/signatory_details.js
#: cms/static/js/models/section.js cms/static/js/utils/drag_and_drop.js
@@ -143,7 +132,6 @@ msgstr ""
#: cms/static/js/views/modals/edit_xblock.js cms/static/js/views/tabs.js
#: cms/static/js/views/utils/xblock_utils.js lms/static/js/ccx/schedule.js
#: lms/static/js/views/fields.js
-#: xmodule/assets/library_source_block/public/js/library_source_block.js
msgid "Saving"
msgstr "Kaydediliyor"
@@ -4179,18 +4167,6 @@ msgstr "Profil"
msgid "Updating with latest library content"
msgstr "Son kütüphane içeriğiyle güncelleniyor"
-#: xmodule/assets/library_source_block/LibrarySourcedBlockPicker.jsx
-msgid "Loading..."
-msgstr "Yüklüyor..."
-
-#: xmodule/assets/library_source_block/LibrarySourcedBlockPicker.jsx
-msgid "Selected blocks"
-msgstr "Seçili blocklar"
-
-#: xmodule/assets/library_source_block/public/js/library_source_block.js
-msgid "Unable to update settings"
-msgstr "Ayarlar güncellenemedi"
-
#: xmodule/assets/split_test/public/js/split_test_author_view.js
#: xmodule/js/public/js/split_test_author_view.js
msgid "Creating missing groups"
@@ -5856,6 +5832,13 @@ msgstr "Altyazıyı aç"
msgid "Turn off transcripts"
msgstr "Altyazıları kapat"
+#: cms/static/cms/js/main.js cms/static/js/views/active_video_upload_list.js
+#: cms/static/js/views/video_transcripts.js
+msgid ""
+"This may be happening because of an error with our server or your internet "
+"connection. Try refreshing the page or making sure you are online."
+msgstr ""
+
#: cms/static/cms/js/main.js
msgid "Studio's having trouble saving your work"
msgstr "Studio yaptığınız işi kaydetme konusunda zorluk yaşıyor"
@@ -6422,7 +6405,7 @@ msgstr ""
#: cms/static/js/views/course_outline.js
#: cms/static/js/views/pages/container.js
-msgid "New files were added to this course's Files & Uploads"
+msgid "New file(s) added to Files & Uploads."
msgstr ""
#: cms/static/js/views/course_outline.js
@@ -6430,6 +6413,16 @@ msgstr ""
msgid "The following required files were imported to this course:"
msgstr ""
+#: cms/static/js/views/course_outline.js
+#: cms/static/js/views/pages/container.js
+msgid "View files"
+msgstr ""
+
+#: cms/static/js/views/course_outline.js
+#: cms/static/js/views/pages/container.js
+msgid "Dismiss"
+msgstr ""
+
#: cms/static/js/views/course_rerun.js
msgid "Create Re-run"
msgstr "Yeniden Çalıştırma Oluştur"
diff --git a/conf/locale/uk/LC_MESSAGES/django.mo b/conf/locale/uk/LC_MESSAGES/django.mo
index 4ce7208e219d..892b71fcee3a 100644
Binary files a/conf/locale/uk/LC_MESSAGES/django.mo and b/conf/locale/uk/LC_MESSAGES/django.mo differ
diff --git a/conf/locale/uk/LC_MESSAGES/django.po b/conf/locale/uk/LC_MESSAGES/django.po
index 4def912ff1b3..2c79148d22fb 100644
--- a/conf/locale/uk/LC_MESSAGES/django.po
+++ b/conf/locale/uk/LC_MESSAGES/django.po
@@ -125,7 +125,7 @@ msgid ""
msgstr ""
"Project-Id-Version: 0.1a\n"
"Report-Msgid-Bugs-To: openedx-translation@googlegroups.com\n"
-"POT-Creation-Date: 2023-08-27 20:43+0000\n"
+"POT-Creation-Date: 2023-09-17 20:43+0000\n"
"PO-Revision-Date: 2019-01-20 20:43+0000\n"
"Last-Translator: Danylo Shcherbak , 2020\n"
"Language-Team: Ukrainian (https://app.transifex.com/open-edx/teams/6205/uk/)\n"
@@ -224,8 +224,8 @@ msgid "Video"
msgstr "Відео"
#: cms/djangoapps/contentstore/views/component.py xmodule/capa_block.py
-msgid "Blank Advanced Problem"
-msgstr "Звичайне завдання"
+msgid "Blank Problem"
+msgstr ""
#: cms/djangoapps/contentstore/views/component.py
#: xmodule/video_block/video_block.py
@@ -330,8 +330,8 @@ msgstr "Професійна освіта"
#: common/djangoapps/course_modes/models.py xmodule/annotatable_block.py
#: xmodule/capa_block.py xmodule/conditional_block.py
#: xmodule/discussion_block.py xmodule/html_block.py
-#: xmodule/library_content_block.py xmodule/library_sourced_block.py
-#: xmodule/lti_block.py xmodule/split_test_block.py xmodule/unit_block.py
+#: xmodule/library_content_block.py xmodule/lti_block.py
+#: xmodule/split_test_block.py xmodule/unit_block.py
#: xmodule/word_cloud_block.py xmodule/x_module.py
msgid "Display Name"
msgstr "Назва, що відображається"
@@ -3045,6 +3045,12 @@ msgstr ""
msgid "Open Response Assessment"
msgstr ""
+#: lms/djangoapps/courseware/courses.py
+msgid ""
+"This Open Response Assessment's due dates are set by your instructor and "
+"can't be shifted."
+msgstr ""
+
#: lms/djangoapps/courseware/courses.py
msgid "Self Assessment"
msgstr ""
@@ -3061,12 +3067,6 @@ msgstr ""
msgid "Submission"
msgstr ""
-#: lms/djangoapps/courseware/courses.py
-msgid ""
-"Open Response Assessment due dates are set by your instructor and can't be "
-"shifted."
-msgstr ""
-
#. Translators: 'absolute' is a date such as "Jan 01,
#. 2020". 'relative' is a fuzzy description of the time until
#. 'absolute'. For example, 'absolute' might be "Jan 01, 2020",
@@ -5723,7 +5723,6 @@ msgstr ""
#: lms/templates/oauth2_provider/authorize.html
#: openedx/core/djangoapps/user_api/admin.py
-#: xmodule/templates/library-sourced-block-studio-view.html
msgid "Cancel"
msgstr "Відмінити"
@@ -6168,13 +6167,11 @@ msgid "Quotes"
msgstr "Цитати"
#: lms/templates/wiki/includes/editor_widget.html
-#, python-format
+#, python-brace-format
msgid ""
-"Markdown syntax is allowed. See the %(start_link)scheatsheet%(end_link)s for"
-" help."
+"Markdown syntax is allowed. See the {start_link}cheatsheet{end_link} for "
+"help."
msgstr ""
-" Синтаксис Markdown дозволений. Дивіться "
-"%(start_link)scheatsheet%(end_link)sдля допомоги."
#: lms/templates/wiki/plugins/attachments/index.html
#: wiki/plugins/attachments/templates/wiki/plugins/attachments/index.html
@@ -7167,8 +7164,8 @@ msgstr ""
#: openedx/core/djangoapps/discussions/models.py
msgid ""
-"The Posting availabilty in discussions whether it will be enabled, scheduled"
-" or indefinitely disabled."
+"The Posting availability in discussions whether it will be enabled, "
+"scheduled or indefinitely disabled."
msgstr ""
#: openedx/core/djangoapps/discussions/models.py
@@ -9090,8 +9087,7 @@ msgstr "XML-дані для анотації"
#: xmodule/annotatable_block.py xmodule/capa_block.py
#: xmodule/conditional_block.py xmodule/discussion_block.py
#: xmodule/html_block.py xmodule/library_content_block.py
-#: xmodule/library_root_xblock.py xmodule/library_sourced_block.py
-#: xmodule/poll_block.py xmodule/unit_block.py
+#: xmodule/library_root_xblock.py xmodule/poll_block.py xmodule/unit_block.py
#: xmodule/video_block/video_xfields.py xmodule/word_cloud_block.py
#: xmodule/x_module.py
msgid "The display name for this component."
@@ -11309,33 +11305,6 @@ msgid "Enter the names of the advanced components to use in your library."
msgstr ""
"Введіть назви додаткових компонентів для використання у вашій бібліотеці."
-#: xmodule/library_sourced_block.py
-msgid "Library Blocks List"
-msgstr ""
-
-#: xmodule/library_sourced_block.py
-msgid "Enter the IDs of the library XBlocks that you wish to use."
-msgstr ""
-
-#: xmodule/library_sourced_block.py
-#, python-brace-format
-msgid "A maximum of {0} components may be added."
-msgstr ""
-
-#: xmodule/library_sourced_block.py
-msgid ""
-"No XBlock has been configured for this component. Use the editor to select "
-"the target blocks."
-msgstr ""
-
-#: xmodule/library_sourced_block.py
-msgid "Open Editor"
-msgstr ""
-
-#: xmodule/library_sourced_block.py
-msgid "Importing Library Block failed - are the IDs valid and readable?"
-msgstr ""
-
#: xmodule/lti_block.py
msgid ""
"The display name for this component. Analytics reports may also use the "
@@ -12029,10 +11998,6 @@ msgstr ""
msgid "External Discussion"
msgstr "Зовнішнє обговорення"
-#: xmodule/templates/library-sourced-block-studio-view.html
-msgid "Save and Import"
-msgstr ""
-
#: xmodule/vertical_block.py
msgid "Enable in-context discussions for the Unit"
msgstr ""
@@ -15656,10 +15621,6 @@ msgstr ""
msgid "Print or share your certificate:"
msgstr ""
-#: lms/templates/certificates/_accomplishment-banner.html
-msgid "Click the link to see my certificate."
-msgstr ""
-
#: lms/templates/certificates/_accomplishment-banner.html
msgid "Post on Facebook"
msgstr "Опублікувати у Facebook"
@@ -19952,15 +19913,15 @@ msgstr ""
#: themes/stanford-style/lms/templates/static_templates/tos.html
msgid "Put your Honor Code here!"
-msgstr "Додати свій Кодекс честі сюди!"
+msgstr "Додайте текст Політики Доброчесності сюди!"
#: themes/stanford-style/lms/templates/static_templates/tos.html
msgid "Put your Copyright Text here!"
-msgstr ""
+msgstr "Додайте текст Авторського Права сюди!"
#: xmodule/capa/templates/codeinput.html
msgid "Code Editor"
-msgstr ""
+msgstr "Редактор коду"
#: cms/templates/404.html
msgid "The page that you were looking for was not found."
diff --git a/conf/locale/uk/LC_MESSAGES/djangojs.po b/conf/locale/uk/LC_MESSAGES/djangojs.po
index 656f5e774669..de9cd2e85d9a 100644
--- a/conf/locale/uk/LC_MESSAGES/djangojs.po
+++ b/conf/locale/uk/LC_MESSAGES/djangojs.po
@@ -102,7 +102,7 @@ msgid ""
msgstr ""
"Project-Id-Version: edx-platform\n"
"Report-Msgid-Bugs-To: openedx-translation@googlegroups.com\n"
-"POT-Creation-Date: 2023-08-27 20:42+0000\n"
+"POT-Creation-Date: 2023-09-17 20:42+0000\n"
"PO-Revision-Date: 2014-06-11 15:18+0000\n"
"Last-Translator: Andrey Kryachko, 2018\n"
"Language-Team: Ukrainian (http://app.transifex.com/open-edx/edx-platform/language/uk/)\n"
@@ -113,14 +113,6 @@ msgstr ""
"Plural-Forms: nplurals=4; plural=(n % 1 == 0 && n % 10 == 1 && n % 100 != 11 ? 0 : n % 1 == 0 && n % 10 >= 2 && n % 10 <= 4 && (n % 100 < 12 || n % 100 > 14) ? 1 : n % 1 == 0 && (n % 10 ==0 || (n % 10 >=5 && n % 10 <=9) || (n % 100 >=11 && n % 100 <=14 )) ? 2: 3);\n"
"Generated-By: Babel 2.8.0\n"
-#: cms/static/cms/js/main.js cms/static/js/views/active_video_upload_list.js
-#: cms/static/js/views/video_transcripts.js
-#: xmodule/assets/library_source_block/public/js/library_source_block.js
-msgid ""
-"This may be happening because of an error with our server or your internet "
-"connection. Try refreshing the page or making sure you are online."
-msgstr ""
-
#: cms/static/cms/js/xblock/cms.runtime.v1.js
#: cms/static/js/certificates/views/signatory_details.js
#: cms/static/js/models/section.js cms/static/js/utils/drag_and_drop.js
@@ -132,7 +124,6 @@ msgstr ""
#: cms/static/js/views/modals/edit_xblock.js cms/static/js/views/tabs.js
#: cms/static/js/views/utils/xblock_utils.js lms/static/js/ccx/schedule.js
#: lms/static/js/views/fields.js
-#: xmodule/assets/library_source_block/public/js/library_source_block.js
msgid "Saving"
msgstr "Збереження"
@@ -4073,18 +4064,6 @@ msgstr "Профіль"
msgid "Updating with latest library content"
msgstr "Оновлення за допомогою найновішого вмісту бібліотеки"
-#: xmodule/assets/library_source_block/LibrarySourcedBlockPicker.jsx
-msgid "Loading..."
-msgstr ""
-
-#: xmodule/assets/library_source_block/LibrarySourcedBlockPicker.jsx
-msgid "Selected blocks"
-msgstr ""
-
-#: xmodule/assets/library_source_block/public/js/library_source_block.js
-msgid "Unable to update settings"
-msgstr ""
-
#: xmodule/assets/split_test/public/js/split_test_author_view.js
#: xmodule/js/public/js/split_test_author_view.js
msgid "Creating missing groups"
@@ -5734,6 +5713,13 @@ msgstr "Включити переклад"
msgid "Turn off transcripts"
msgstr "Вимкнути переклад"
+#: cms/static/cms/js/main.js cms/static/js/views/active_video_upload_list.js
+#: cms/static/js/views/video_transcripts.js
+msgid ""
+"This may be happening because of an error with our server or your internet "
+"connection. Try refreshing the page or making sure you are online."
+msgstr ""
+
#: cms/static/cms/js/main.js
msgid "Studio's having trouble saving your work"
msgstr "Studio не вдається зберегти вашу роботу"
@@ -6287,7 +6273,7 @@ msgstr ""
#: cms/static/js/views/course_outline.js
#: cms/static/js/views/pages/container.js
-msgid "New files were added to this course's Files & Uploads"
+msgid "New file(s) added to Files & Uploads."
msgstr ""
#: cms/static/js/views/course_outline.js
@@ -6295,6 +6281,16 @@ msgstr ""
msgid "The following required files were imported to this course:"
msgstr ""
+#: cms/static/js/views/course_outline.js
+#: cms/static/js/views/pages/container.js
+msgid "View files"
+msgstr ""
+
+#: cms/static/js/views/course_outline.js
+#: cms/static/js/views/pages/container.js
+msgid "Dismiss"
+msgstr ""
+
#: cms/static/js/views/course_rerun.js
msgid "Create Re-run"
msgstr "Створити повторну операцію"
diff --git a/conf/locale/vi/LC_MESSAGES/django.mo b/conf/locale/vi/LC_MESSAGES/django.mo
index f6c4a6686151..4bf4ff388701 100644
Binary files a/conf/locale/vi/LC_MESSAGES/django.mo and b/conf/locale/vi/LC_MESSAGES/django.mo differ
diff --git a/conf/locale/vi/LC_MESSAGES/django.po b/conf/locale/vi/LC_MESSAGES/django.po
index e4ac2c3a739b..891d04238c8c 100644
--- a/conf/locale/vi/LC_MESSAGES/django.po
+++ b/conf/locale/vi/LC_MESSAGES/django.po
@@ -198,7 +198,7 @@ msgid ""
msgstr ""
"Project-Id-Version: 0.1a\n"
"Report-Msgid-Bugs-To: openedx-translation@googlegroups.com\n"
-"POT-Creation-Date: 2023-08-27 20:43+0000\n"
+"POT-Creation-Date: 2023-09-17 20:43+0000\n"
"PO-Revision-Date: 2019-01-20 20:43+0000\n"
"Last-Translator: Le Minh Tri , 2020\n"
"Language-Team: Vietnamese (https://app.transifex.com/open-edx/teams/6205/vi/)\n"
@@ -281,7 +281,7 @@ msgid "Video"
msgstr "Video"
#: cms/djangoapps/contentstore/views/component.py xmodule/capa_block.py
-msgid "Blank Advanced Problem"
+msgid "Blank Problem"
msgstr ""
#: cms/djangoapps/contentstore/views/component.py
@@ -2816,6 +2816,12 @@ msgstr ""
msgid "Open Response Assessment"
msgstr ""
+#: lms/djangoapps/courseware/courses.py
+msgid ""
+"This Open Response Assessment's due dates are set by your instructor and "
+"can't be shifted."
+msgstr ""
+
#: lms/djangoapps/courseware/courses.py
msgid "Self Assessment"
msgstr ""
@@ -2832,12 +2838,6 @@ msgstr ""
msgid "Submission"
msgstr ""
-#: lms/djangoapps/courseware/courses.py
-msgid ""
-"Open Response Assessment due dates are set by your instructor and can't be "
-"shifted."
-msgstr ""
-
#. Translators: 'absolute' is a date such as "Jan 01,
#. 2020". 'relative' is a fuzzy description of the time until
#. 'absolute'. For example, 'absolute' might be "Jan 01, 2020",
@@ -5264,7 +5264,6 @@ msgstr ""
#: lms/templates/oauth2_provider/authorize.html
#: openedx/core/djangoapps/user_api/admin.py
-#: xmodule/templates/library-sourced-block-studio-view.html
#: cms/templates/course-create-rerun.html cms/templates/index.html
#: cms/templates/manage_users.html cms/templates/manage_users_lib.html
#: cms/templates/videos_index_pagination.html
@@ -5692,10 +5691,10 @@ msgid "Quotes"
msgstr "Trích dẫn"
#: lms/templates/wiki/includes/editor_widget.html
-#, python-format
+#, python-brace-format
msgid ""
-"Markdown syntax is allowed. See the %(start_link)scheatsheet%(end_link)s for"
-" help."
+"Markdown syntax is allowed. See the {start_link}cheatsheet{end_link} for "
+"help."
msgstr ""
#: lms/templates/wiki/plugins/attachments/index.html
@@ -6617,8 +6616,8 @@ msgstr ""
#: openedx/core/djangoapps/discussions/models.py
msgid ""
-"The Posting availabilty in discussions whether it will be enabled, scheduled"
-" or indefinitely disabled."
+"The Posting availability in discussions whether it will be enabled, "
+"scheduled or indefinitely disabled."
msgstr ""
#: openedx/core/djangoapps/discussions/models.py
@@ -8391,8 +8390,7 @@ msgstr ""
#: xmodule/annotatable_block.py xmodule/capa_block.py
#: xmodule/conditional_block.py xmodule/discussion_block.py
#: xmodule/html_block.py xmodule/library_content_block.py
-#: xmodule/library_root_xblock.py xmodule/library_sourced_block.py
-#: xmodule/poll_block.py xmodule/unit_block.py
+#: xmodule/library_root_xblock.py xmodule/poll_block.py xmodule/unit_block.py
#: xmodule/video_block/video_xfields.py xmodule/word_cloud_block.py
#: xmodule/x_module.py
msgid "The display name for this component."
@@ -10343,33 +10341,6 @@ msgstr ""
msgid "Enter the names of the advanced components to use in your library."
msgstr ""
-#: xmodule/library_sourced_block.py
-msgid "Library Blocks List"
-msgstr ""
-
-#: xmodule/library_sourced_block.py
-msgid "Enter the IDs of the library XBlocks that you wish to use."
-msgstr ""
-
-#: xmodule/library_sourced_block.py
-#, python-brace-format
-msgid "A maximum of {0} components may be added."
-msgstr ""
-
-#: xmodule/library_sourced_block.py
-msgid ""
-"No XBlock has been configured for this component. Use the editor to select "
-"the target blocks."
-msgstr ""
-
-#: xmodule/library_sourced_block.py
-msgid "Open Editor"
-msgstr ""
-
-#: xmodule/library_sourced_block.py
-msgid "Importing Library Block failed - are the IDs valid and readable?"
-msgstr ""
-
#: xmodule/lti_block.py
msgid ""
"The display name for this component. Analytics reports may also use the "
@@ -10956,10 +10927,6 @@ msgstr ""
msgid "External Discussion"
msgstr ""
-#: xmodule/templates/library-sourced-block-studio-view.html
-msgid "Save and Import"
-msgstr ""
-
#: xmodule/vertical_block.py
msgid "Enable in-context discussions for the Unit"
msgstr ""
@@ -14678,10 +14645,6 @@ msgstr "Tải bảng điểm học viên"
msgid "Print or share your certificate:"
msgstr "In hoặc chia sẻ giấy chứng nhận của bạn:"
-#: lms/templates/certificates/_accomplishment-banner.html
-msgid "Click the link to see my certificate."
-msgstr "Nhấn vào link để xem chứng chỉ."
-
#: lms/templates/certificates/_accomplishment-banner.html
msgid "Post on Facebook"
msgstr "Post lên Facebook"
diff --git a/conf/locale/vi/LC_MESSAGES/djangojs.po b/conf/locale/vi/LC_MESSAGES/djangojs.po
index e0e26b8975f9..468215f6fdca 100644
--- a/conf/locale/vi/LC_MESSAGES/djangojs.po
+++ b/conf/locale/vi/LC_MESSAGES/djangojs.po
@@ -113,7 +113,7 @@ msgid ""
msgstr ""
"Project-Id-Version: edx-platform\n"
"Report-Msgid-Bugs-To: openedx-translation@googlegroups.com\n"
-"POT-Creation-Date: 2023-08-27 20:42+0000\n"
+"POT-Creation-Date: 2023-09-17 20:42+0000\n"
"PO-Revision-Date: 2014-06-11 15:18+0000\n"
"Last-Translator: Le Minh Tri , 2020\n"
"Language-Team: Vietnamese (http://app.transifex.com/open-edx/edx-platform/language/vi/)\n"
@@ -124,14 +124,6 @@ msgstr ""
"Plural-Forms: nplurals=1; plural=0;\n"
"Generated-By: Babel 2.8.0\n"
-#: cms/static/cms/js/main.js cms/static/js/views/active_video_upload_list.js
-#: cms/static/js/views/video_transcripts.js
-#: xmodule/assets/library_source_block/public/js/library_source_block.js
-msgid ""
-"This may be happening because of an error with our server or your internet "
-"connection. Try refreshing the page or making sure you are online."
-msgstr ""
-
#: cms/static/cms/js/xblock/cms.runtime.v1.js
#: cms/static/js/certificates/views/signatory_details.js
#: cms/static/js/models/section.js cms/static/js/utils/drag_and_drop.js
@@ -143,7 +135,6 @@ msgstr ""
#: cms/static/js/views/modals/edit_xblock.js cms/static/js/views/tabs.js
#: cms/static/js/views/utils/xblock_utils.js lms/static/js/ccx/schedule.js
#: lms/static/js/views/fields.js
-#: xmodule/assets/library_source_block/public/js/library_source_block.js
msgid "Saving"
msgstr "Đang lưu"
@@ -3963,18 +3954,6 @@ msgstr "Hồ sơ"
msgid "Updating with latest library content"
msgstr "Đang cập nhật nội dung thư viện mới nhất"
-#: xmodule/assets/library_source_block/LibrarySourcedBlockPicker.jsx
-msgid "Loading..."
-msgstr ""
-
-#: xmodule/assets/library_source_block/LibrarySourcedBlockPicker.jsx
-msgid "Selected blocks"
-msgstr ""
-
-#: xmodule/assets/library_source_block/public/js/library_source_block.js
-msgid "Unable to update settings"
-msgstr ""
-
#: xmodule/assets/split_test/public/js/split_test_author_view.js
#: xmodule/js/public/js/split_test_author_view.js
msgid "Creating missing groups"
@@ -5607,6 +5586,13 @@ msgstr "Bật bản dịch"
msgid "Turn off transcripts"
msgstr "Tắt bản dịch"
+#: cms/static/cms/js/main.js cms/static/js/views/active_video_upload_list.js
+#: cms/static/js/views/video_transcripts.js
+msgid ""
+"This may be happening because of an error with our server or your internet "
+"connection. Try refreshing the page or making sure you are online."
+msgstr ""
+
#: cms/static/cms/js/main.js
msgid "Studio's having trouble saving your work"
msgstr "Studio xảy ra sự cố khi lưu lại công việc của bạn"
@@ -6161,7 +6147,7 @@ msgstr ""
#: cms/static/js/views/course_outline.js
#: cms/static/js/views/pages/container.js
-msgid "New files were added to this course's Files & Uploads"
+msgid "New file(s) added to Files & Uploads."
msgstr ""
#: cms/static/js/views/course_outline.js
@@ -6169,6 +6155,16 @@ msgstr ""
msgid "The following required files were imported to this course:"
msgstr ""
+#: cms/static/js/views/course_outline.js
+#: cms/static/js/views/pages/container.js
+msgid "View files"
+msgstr ""
+
+#: cms/static/js/views/course_outline.js
+#: cms/static/js/views/pages/container.js
+msgid "Dismiss"
+msgstr ""
+
#: cms/static/js/views/course_rerun.js
msgid "Create Re-run"
msgstr "Tạo Re-run"
diff --git a/conf/locale/zh_CN/LC_MESSAGES/django.mo b/conf/locale/zh_CN/LC_MESSAGES/django.mo
index 01a1d020aee0..52436b2f380a 100644
Binary files a/conf/locale/zh_CN/LC_MESSAGES/django.mo and b/conf/locale/zh_CN/LC_MESSAGES/django.mo differ
diff --git a/conf/locale/zh_CN/LC_MESSAGES/django.po b/conf/locale/zh_CN/LC_MESSAGES/django.po
index 59e315b51002..b13d26e1379f 100644
--- a/conf/locale/zh_CN/LC_MESSAGES/django.po
+++ b/conf/locale/zh_CN/LC_MESSAGES/django.po
@@ -403,7 +403,7 @@ msgid ""
msgstr ""
"Project-Id-Version: 0.1a\n"
"Report-Msgid-Bugs-To: openedx-translation@googlegroups.com\n"
-"POT-Creation-Date: 2023-08-27 20:43+0000\n"
+"POT-Creation-Date: 2023-09-17 20:43+0000\n"
"PO-Revision-Date: 2019-01-20 20:43+0000\n"
"Last-Translator: ifLab , 2019\n"
"Language-Team: Chinese (China) (https://app.transifex.com/open-edx/teams/6205/zh_CN/)\n"
@@ -504,8 +504,8 @@ msgid "Video"
msgstr "视频"
#: cms/djangoapps/contentstore/views/component.py xmodule/capa_block.py
-msgid "Blank Advanced Problem"
-msgstr "空白进阶问题"
+msgid "Blank Problem"
+msgstr ""
#: cms/djangoapps/contentstore/views/component.py
#: xmodule/video_block/video_block.py
@@ -607,8 +607,8 @@ msgstr "专业教育"
#: common/djangoapps/course_modes/models.py xmodule/annotatable_block.py
#: xmodule/capa_block.py xmodule/conditional_block.py
#: xmodule/discussion_block.py xmodule/html_block.py
-#: xmodule/library_content_block.py xmodule/library_sourced_block.py
-#: xmodule/lti_block.py xmodule/split_test_block.py xmodule/unit_block.py
+#: xmodule/library_content_block.py xmodule/lti_block.py
+#: xmodule/split_test_block.py xmodule/unit_block.py
#: xmodule/word_cloud_block.py xmodule/x_module.py
#: cms/templates/container.html cms/templates/library.html
msgid "Display Name"
@@ -3132,6 +3132,12 @@ msgstr "作业"
msgid "Open Response Assessment"
msgstr "开放式答题评分"
+#: lms/djangoapps/courseware/courses.py
+msgid ""
+"This Open Response Assessment's due dates are set by your instructor and "
+"can't be shifted."
+msgstr ""
+
#: lms/djangoapps/courseware/courses.py
msgid "Self Assessment"
msgstr "自我评分"
@@ -3148,12 +3154,6 @@ msgstr "工作人员评分"
msgid "Submission"
msgstr "提交"
-#: lms/djangoapps/courseware/courses.py
-msgid ""
-"Open Response Assessment due dates are set by your instructor and can't be "
-"shifted."
-msgstr "开放式题目测试评估截止日期由您的讲师设置,不能更改。"
-
#. Translators: 'absolute' is a date such as "Jan 01,
#. 2020". 'relative' is a fuzzy description of the time until
#. 'absolute'. For example, 'absolute' might be "Jan 01, 2020",
@@ -5668,7 +5668,6 @@ msgstr "请点击“允许”按钮为以上应用进行授权。若您不希望
#: lms/templates/oauth2_provider/authorize.html
#: openedx/core/djangoapps/user_api/admin.py
-#: xmodule/templates/library-sourced-block-studio-view.html
msgid "Cancel"
msgstr "取消"
@@ -6105,11 +6104,11 @@ msgid "Quotes"
msgstr "引言"
#: lms/templates/wiki/includes/editor_widget.html
-#, python-format
+#, python-brace-format
msgid ""
-"Markdown syntax is allowed. See the %(start_link)scheatsheet%(end_link)s for"
-" help."
-msgstr "此处允许使用MarkDown语法。请参阅%(start_link)s快捷键管理%(end_link)s并寻求帮助。"
+"Markdown syntax is allowed. See the {start_link}cheatsheet{end_link} for "
+"help."
+msgstr ""
#: lms/templates/wiki/plugins/attachments/index.html
#: wiki/plugins/attachments/templates/wiki/plugins/attachments/index.html
@@ -7067,8 +7066,8 @@ msgstr "如果禁用,相关学习环境/课程中的讨论将被禁用。"
#: openedx/core/djangoapps/discussions/models.py
msgid ""
-"The Posting availabilty in discussions whether it will be enabled, scheduled"
-" or indefinitely disabled."
+"The Posting availability in discussions whether it will be enabled, "
+"scheduled or indefinitely disabled."
msgstr ""
#: openedx/core/djangoapps/discussions/models.py
@@ -8929,8 +8928,7 @@ msgstr "用于批注的XML数据"
#: xmodule/annotatable_block.py xmodule/capa_block.py
#: xmodule/conditional_block.py xmodule/discussion_block.py
#: xmodule/html_block.py xmodule/library_content_block.py
-#: xmodule/library_root_xblock.py xmodule/library_sourced_block.py
-#: xmodule/poll_block.py xmodule/unit_block.py
+#: xmodule/library_root_xblock.py xmodule/poll_block.py xmodule/unit_block.py
#: xmodule/video_block/video_xfields.py xmodule/word_cloud_block.py
#: xmodule/x_module.py
msgid "The display name for this component."
@@ -10931,33 +10929,6 @@ msgstr "知识库显示名称"
msgid "Enter the names of the advanced components to use in your library."
msgstr "输入在您的知识库中使用的高级组件的名字。"
-#: xmodule/library_sourced_block.py
-msgid "Library Blocks List"
-msgstr "库块列表"
-
-#: xmodule/library_sourced_block.py
-msgid "Enter the IDs of the library XBlocks that you wish to use."
-msgstr "输入您要使用的库 XBlock 的 ID。"
-
-#: xmodule/library_sourced_block.py
-#, python-brace-format
-msgid "A maximum of {0} components may be added."
-msgstr "最多可以添加 {0} 个组件。"
-
-#: xmodule/library_sourced_block.py
-msgid ""
-"No XBlock has been configured for this component. Use the editor to select "
-"the target blocks."
-msgstr "尚未为此组件配置 XBlock。使用编辑器选择目标块。"
-
-#: xmodule/library_sourced_block.py
-msgid "Open Editor"
-msgstr "打开编辑器"
-
-#: xmodule/library_sourced_block.py
-msgid "Importing Library Block failed - are the IDs valid and readable?"
-msgstr "导入库块失败 - ID 是否有效且可读?"
-
#: xmodule/lti_block.py
msgid ""
"The display name for this component. Analytics reports may also use the "
@@ -11567,10 +11538,6 @@ msgstr "该内容实验可能影响内容可见性。"
msgid "External Discussion"
msgstr "外部讨论"
-#: xmodule/templates/library-sourced-block-studio-view.html
-msgid "Save and Import"
-msgstr "保存并导入"
-
#: xmodule/vertical_block.py
msgid "Enable in-context discussions for the Unit"
msgstr "为该单元启用上下文讨论"
@@ -15122,10 +15089,6 @@ msgstr "下载学生评分"
msgid "Print or share your certificate:"
msgstr "打印或分享您的证书:"
-#: lms/templates/certificates/_accomplishment-banner.html
-msgid "Click the link to see my certificate."
-msgstr "点击链接查看我的证书。"
-
#: lms/templates/certificates/_accomplishment-banner.html
msgid "Post on Facebook"
msgstr "发布到Facebook"
diff --git a/conf/locale/zh_CN/LC_MESSAGES/djangojs.mo b/conf/locale/zh_CN/LC_MESSAGES/djangojs.mo
index 2593cb94a110..333aeeb69f07 100644
Binary files a/conf/locale/zh_CN/LC_MESSAGES/djangojs.mo and b/conf/locale/zh_CN/LC_MESSAGES/djangojs.mo differ
diff --git a/conf/locale/zh_CN/LC_MESSAGES/djangojs.po b/conf/locale/zh_CN/LC_MESSAGES/djangojs.po
index 4d27092a933c..88327c771fef 100644
--- a/conf/locale/zh_CN/LC_MESSAGES/djangojs.po
+++ b/conf/locale/zh_CN/LC_MESSAGES/djangojs.po
@@ -230,7 +230,7 @@ msgid ""
msgstr ""
"Project-Id-Version: edx-platform\n"
"Report-Msgid-Bugs-To: openedx-translation@googlegroups.com\n"
-"POT-Creation-Date: 2023-08-27 20:42+0000\n"
+"POT-Creation-Date: 2023-09-17 20:42+0000\n"
"PO-Revision-Date: 2014-06-11 15:18+0000\n"
"Last-Translator: jsgang , 2015-2017,2020\n"
"Language-Team: Chinese (China) (http://app.transifex.com/open-edx/edx-platform/language/zh_CN/)\n"
@@ -241,14 +241,6 @@ msgstr ""
"Plural-Forms: nplurals=1; plural=0;\n"
"Generated-By: Babel 2.8.0\n"
-#: cms/static/cms/js/main.js cms/static/js/views/active_video_upload_list.js
-#: cms/static/js/views/video_transcripts.js
-#: xmodule/assets/library_source_block/public/js/library_source_block.js
-msgid ""
-"This may be happening because of an error with our server or your internet "
-"connection. Try refreshing the page or making sure you are online."
-msgstr "此情况可能由于服务器错误或者您的网络连接错误导致。尝试刷新页面或者确保网络畅通。"
-
#: cms/static/cms/js/xblock/cms.runtime.v1.js
#: cms/static/js/certificates/views/signatory_details.js
#: cms/static/js/models/section.js cms/static/js/utils/drag_and_drop.js
@@ -260,7 +252,6 @@ msgstr "此情况可能由于服务器错误或者您的网络连接错误导致
#: cms/static/js/views/modals/edit_xblock.js cms/static/js/views/tabs.js
#: cms/static/js/views/utils/xblock_utils.js lms/static/js/ccx/schedule.js
#: lms/static/js/views/fields.js
-#: xmodule/assets/library_source_block/public/js/library_source_block.js
msgid "Saving"
msgstr "正在保存"
@@ -3912,18 +3903,6 @@ msgstr "个人主页"
msgid "Updating with latest library content"
msgstr "更新最新的库内容"
-#: xmodule/assets/library_source_block/LibrarySourcedBlockPicker.jsx
-msgid "Loading..."
-msgstr "载入中..."
-
-#: xmodule/assets/library_source_block/LibrarySourcedBlockPicker.jsx
-msgid "Selected blocks"
-msgstr "选中的块"
-
-#: xmodule/assets/library_source_block/public/js/library_source_block.js
-msgid "Unable to update settings"
-msgstr "无法更新设置"
-
#: xmodule/assets/split_test/public/js/split_test_author_view.js
#: xmodule/js/public/js/split_test_author_view.js
msgid "Creating missing groups"
@@ -5532,6 +5511,13 @@ msgstr "打开字幕"
msgid "Turn off transcripts"
msgstr "关闭字幕"
+#: cms/static/cms/js/main.js cms/static/js/views/active_video_upload_list.js
+#: cms/static/js/views/video_transcripts.js
+msgid ""
+"This may be happening because of an error with our server or your internet "
+"connection. Try refreshing the page or making sure you are online."
+msgstr ""
+
#: cms/static/cms/js/main.js
msgid "Studio's having trouble saving your work"
msgstr "保存时遇到问题"
@@ -6076,7 +6062,7 @@ msgstr ""
#: cms/static/js/views/course_outline.js
#: cms/static/js/views/pages/container.js
-msgid "New files were added to this course's Files & Uploads"
+msgid "New file(s) added to Files & Uploads."
msgstr ""
#: cms/static/js/views/course_outline.js
@@ -6084,6 +6070,16 @@ msgstr ""
msgid "The following required files were imported to this course:"
msgstr ""
+#: cms/static/js/views/course_outline.js
+#: cms/static/js/views/pages/container.js
+msgid "View files"
+msgstr ""
+
+#: cms/static/js/views/course_outline.js
+#: cms/static/js/views/pages/container.js
+msgid "Dismiss"
+msgstr ""
+
#: cms/static/js/views/course_rerun.js
msgid "Create Re-run"
msgstr "创建重启"
diff --git a/conf/locale/zh_HANS/LC_MESSAGES/django.mo b/conf/locale/zh_HANS/LC_MESSAGES/django.mo
index 01a1d020aee0..52436b2f380a 100644
Binary files a/conf/locale/zh_HANS/LC_MESSAGES/django.mo and b/conf/locale/zh_HANS/LC_MESSAGES/django.mo differ
diff --git a/conf/locale/zh_HANS/LC_MESSAGES/django.po b/conf/locale/zh_HANS/LC_MESSAGES/django.po
index 59e315b51002..b13d26e1379f 100644
--- a/conf/locale/zh_HANS/LC_MESSAGES/django.po
+++ b/conf/locale/zh_HANS/LC_MESSAGES/django.po
@@ -403,7 +403,7 @@ msgid ""
msgstr ""
"Project-Id-Version: 0.1a\n"
"Report-Msgid-Bugs-To: openedx-translation@googlegroups.com\n"
-"POT-Creation-Date: 2023-08-27 20:43+0000\n"
+"POT-Creation-Date: 2023-09-17 20:43+0000\n"
"PO-Revision-Date: 2019-01-20 20:43+0000\n"
"Last-Translator: ifLab , 2019\n"
"Language-Team: Chinese (China) (https://app.transifex.com/open-edx/teams/6205/zh_CN/)\n"
@@ -504,8 +504,8 @@ msgid "Video"
msgstr "视频"
#: cms/djangoapps/contentstore/views/component.py xmodule/capa_block.py
-msgid "Blank Advanced Problem"
-msgstr "空白进阶问题"
+msgid "Blank Problem"
+msgstr ""
#: cms/djangoapps/contentstore/views/component.py
#: xmodule/video_block/video_block.py
@@ -607,8 +607,8 @@ msgstr "专业教育"
#: common/djangoapps/course_modes/models.py xmodule/annotatable_block.py
#: xmodule/capa_block.py xmodule/conditional_block.py
#: xmodule/discussion_block.py xmodule/html_block.py
-#: xmodule/library_content_block.py xmodule/library_sourced_block.py
-#: xmodule/lti_block.py xmodule/split_test_block.py xmodule/unit_block.py
+#: xmodule/library_content_block.py xmodule/lti_block.py
+#: xmodule/split_test_block.py xmodule/unit_block.py
#: xmodule/word_cloud_block.py xmodule/x_module.py
#: cms/templates/container.html cms/templates/library.html
msgid "Display Name"
@@ -3132,6 +3132,12 @@ msgstr "作业"
msgid "Open Response Assessment"
msgstr "开放式答题评分"
+#: lms/djangoapps/courseware/courses.py
+msgid ""
+"This Open Response Assessment's due dates are set by your instructor and "
+"can't be shifted."
+msgstr ""
+
#: lms/djangoapps/courseware/courses.py
msgid "Self Assessment"
msgstr "自我评分"
@@ -3148,12 +3154,6 @@ msgstr "工作人员评分"
msgid "Submission"
msgstr "提交"
-#: lms/djangoapps/courseware/courses.py
-msgid ""
-"Open Response Assessment due dates are set by your instructor and can't be "
-"shifted."
-msgstr "开放式题目测试评估截止日期由您的讲师设置,不能更改。"
-
#. Translators: 'absolute' is a date such as "Jan 01,
#. 2020". 'relative' is a fuzzy description of the time until
#. 'absolute'. For example, 'absolute' might be "Jan 01, 2020",
@@ -5668,7 +5668,6 @@ msgstr "请点击“允许”按钮为以上应用进行授权。若您不希望
#: lms/templates/oauth2_provider/authorize.html
#: openedx/core/djangoapps/user_api/admin.py
-#: xmodule/templates/library-sourced-block-studio-view.html
msgid "Cancel"
msgstr "取消"
@@ -6105,11 +6104,11 @@ msgid "Quotes"
msgstr "引言"
#: lms/templates/wiki/includes/editor_widget.html
-#, python-format
+#, python-brace-format
msgid ""
-"Markdown syntax is allowed. See the %(start_link)scheatsheet%(end_link)s for"
-" help."
-msgstr "此处允许使用MarkDown语法。请参阅%(start_link)s快捷键管理%(end_link)s并寻求帮助。"
+"Markdown syntax is allowed. See the {start_link}cheatsheet{end_link} for "
+"help."
+msgstr ""
#: lms/templates/wiki/plugins/attachments/index.html
#: wiki/plugins/attachments/templates/wiki/plugins/attachments/index.html
@@ -7067,8 +7066,8 @@ msgstr "如果禁用,相关学习环境/课程中的讨论将被禁用。"
#: openedx/core/djangoapps/discussions/models.py
msgid ""
-"The Posting availabilty in discussions whether it will be enabled, scheduled"
-" or indefinitely disabled."
+"The Posting availability in discussions whether it will be enabled, "
+"scheduled or indefinitely disabled."
msgstr ""
#: openedx/core/djangoapps/discussions/models.py
@@ -8929,8 +8928,7 @@ msgstr "用于批注的XML数据"
#: xmodule/annotatable_block.py xmodule/capa_block.py
#: xmodule/conditional_block.py xmodule/discussion_block.py
#: xmodule/html_block.py xmodule/library_content_block.py
-#: xmodule/library_root_xblock.py xmodule/library_sourced_block.py
-#: xmodule/poll_block.py xmodule/unit_block.py
+#: xmodule/library_root_xblock.py xmodule/poll_block.py xmodule/unit_block.py
#: xmodule/video_block/video_xfields.py xmodule/word_cloud_block.py
#: xmodule/x_module.py
msgid "The display name for this component."
@@ -10931,33 +10929,6 @@ msgstr "知识库显示名称"
msgid "Enter the names of the advanced components to use in your library."
msgstr "输入在您的知识库中使用的高级组件的名字。"
-#: xmodule/library_sourced_block.py
-msgid "Library Blocks List"
-msgstr "库块列表"
-
-#: xmodule/library_sourced_block.py
-msgid "Enter the IDs of the library XBlocks that you wish to use."
-msgstr "输入您要使用的库 XBlock 的 ID。"
-
-#: xmodule/library_sourced_block.py
-#, python-brace-format
-msgid "A maximum of {0} components may be added."
-msgstr "最多可以添加 {0} 个组件。"
-
-#: xmodule/library_sourced_block.py
-msgid ""
-"No XBlock has been configured for this component. Use the editor to select "
-"the target blocks."
-msgstr "尚未为此组件配置 XBlock。使用编辑器选择目标块。"
-
-#: xmodule/library_sourced_block.py
-msgid "Open Editor"
-msgstr "打开编辑器"
-
-#: xmodule/library_sourced_block.py
-msgid "Importing Library Block failed - are the IDs valid and readable?"
-msgstr "导入库块失败 - ID 是否有效且可读?"
-
#: xmodule/lti_block.py
msgid ""
"The display name for this component. Analytics reports may also use the "
@@ -11567,10 +11538,6 @@ msgstr "该内容实验可能影响内容可见性。"
msgid "External Discussion"
msgstr "外部讨论"
-#: xmodule/templates/library-sourced-block-studio-view.html
-msgid "Save and Import"
-msgstr "保存并导入"
-
#: xmodule/vertical_block.py
msgid "Enable in-context discussions for the Unit"
msgstr "为该单元启用上下文讨论"
@@ -15122,10 +15089,6 @@ msgstr "下载学生评分"
msgid "Print or share your certificate:"
msgstr "打印或分享您的证书:"
-#: lms/templates/certificates/_accomplishment-banner.html
-msgid "Click the link to see my certificate."
-msgstr "点击链接查看我的证书。"
-
#: lms/templates/certificates/_accomplishment-banner.html
msgid "Post on Facebook"
msgstr "发布到Facebook"
diff --git a/conf/locale/zh_HANS/LC_MESSAGES/djangojs.mo b/conf/locale/zh_HANS/LC_MESSAGES/djangojs.mo
index 2593cb94a110..333aeeb69f07 100644
Binary files a/conf/locale/zh_HANS/LC_MESSAGES/djangojs.mo and b/conf/locale/zh_HANS/LC_MESSAGES/djangojs.mo differ
diff --git a/conf/locale/zh_HANS/LC_MESSAGES/djangojs.po b/conf/locale/zh_HANS/LC_MESSAGES/djangojs.po
index 4d27092a933c..88327c771fef 100644
--- a/conf/locale/zh_HANS/LC_MESSAGES/djangojs.po
+++ b/conf/locale/zh_HANS/LC_MESSAGES/djangojs.po
@@ -230,7 +230,7 @@ msgid ""
msgstr ""
"Project-Id-Version: edx-platform\n"
"Report-Msgid-Bugs-To: openedx-translation@googlegroups.com\n"
-"POT-Creation-Date: 2023-08-27 20:42+0000\n"
+"POT-Creation-Date: 2023-09-17 20:42+0000\n"
"PO-Revision-Date: 2014-06-11 15:18+0000\n"
"Last-Translator: jsgang , 2015-2017,2020\n"
"Language-Team: Chinese (China) (http://app.transifex.com/open-edx/edx-platform/language/zh_CN/)\n"
@@ -241,14 +241,6 @@ msgstr ""
"Plural-Forms: nplurals=1; plural=0;\n"
"Generated-By: Babel 2.8.0\n"
-#: cms/static/cms/js/main.js cms/static/js/views/active_video_upload_list.js
-#: cms/static/js/views/video_transcripts.js
-#: xmodule/assets/library_source_block/public/js/library_source_block.js
-msgid ""
-"This may be happening because of an error with our server or your internet "
-"connection. Try refreshing the page or making sure you are online."
-msgstr "此情况可能由于服务器错误或者您的网络连接错误导致。尝试刷新页面或者确保网络畅通。"
-
#: cms/static/cms/js/xblock/cms.runtime.v1.js
#: cms/static/js/certificates/views/signatory_details.js
#: cms/static/js/models/section.js cms/static/js/utils/drag_and_drop.js
@@ -260,7 +252,6 @@ msgstr "此情况可能由于服务器错误或者您的网络连接错误导致
#: cms/static/js/views/modals/edit_xblock.js cms/static/js/views/tabs.js
#: cms/static/js/views/utils/xblock_utils.js lms/static/js/ccx/schedule.js
#: lms/static/js/views/fields.js
-#: xmodule/assets/library_source_block/public/js/library_source_block.js
msgid "Saving"
msgstr "正在保存"
@@ -3912,18 +3903,6 @@ msgstr "个人主页"
msgid "Updating with latest library content"
msgstr "更新最新的库内容"
-#: xmodule/assets/library_source_block/LibrarySourcedBlockPicker.jsx
-msgid "Loading..."
-msgstr "载入中..."
-
-#: xmodule/assets/library_source_block/LibrarySourcedBlockPicker.jsx
-msgid "Selected blocks"
-msgstr "选中的块"
-
-#: xmodule/assets/library_source_block/public/js/library_source_block.js
-msgid "Unable to update settings"
-msgstr "无法更新设置"
-
#: xmodule/assets/split_test/public/js/split_test_author_view.js
#: xmodule/js/public/js/split_test_author_view.js
msgid "Creating missing groups"
@@ -5532,6 +5511,13 @@ msgstr "打开字幕"
msgid "Turn off transcripts"
msgstr "关闭字幕"
+#: cms/static/cms/js/main.js cms/static/js/views/active_video_upload_list.js
+#: cms/static/js/views/video_transcripts.js
+msgid ""
+"This may be happening because of an error with our server or your internet "
+"connection. Try refreshing the page or making sure you are online."
+msgstr ""
+
#: cms/static/cms/js/main.js
msgid "Studio's having trouble saving your work"
msgstr "保存时遇到问题"
@@ -6076,7 +6062,7 @@ msgstr ""
#: cms/static/js/views/course_outline.js
#: cms/static/js/views/pages/container.js
-msgid "New files were added to this course's Files & Uploads"
+msgid "New file(s) added to Files & Uploads."
msgstr ""
#: cms/static/js/views/course_outline.js
@@ -6084,6 +6070,16 @@ msgstr ""
msgid "The following required files were imported to this course:"
msgstr ""
+#: cms/static/js/views/course_outline.js
+#: cms/static/js/views/pages/container.js
+msgid "View files"
+msgstr ""
+
+#: cms/static/js/views/course_outline.js
+#: cms/static/js/views/pages/container.js
+msgid "Dismiss"
+msgstr ""
+
#: cms/static/js/views/course_rerun.js
msgid "Create Re-run"
msgstr "创建重启"
diff --git a/conf/locale/zh_TW/LC_MESSAGES/django.mo b/conf/locale/zh_TW/LC_MESSAGES/django.mo
index b33ccfcfb694..f6edcc6632ad 100644
Binary files a/conf/locale/zh_TW/LC_MESSAGES/django.mo and b/conf/locale/zh_TW/LC_MESSAGES/django.mo differ
diff --git a/conf/locale/zh_TW/LC_MESSAGES/django.po b/conf/locale/zh_TW/LC_MESSAGES/django.po
index 73539fffb213..d2bee32b4996 100644
--- a/conf/locale/zh_TW/LC_MESSAGES/django.po
+++ b/conf/locale/zh_TW/LC_MESSAGES/django.po
@@ -177,7 +177,7 @@ msgid ""
msgstr ""
"Project-Id-Version: 0.1a\n"
"Report-Msgid-Bugs-To: openedx-translation@googlegroups.com\n"
-"POT-Creation-Date: 2023-08-27 20:43+0000\n"
+"POT-Creation-Date: 2023-09-17 20:43+0000\n"
"PO-Revision-Date: 2019-01-20 20:43+0000\n"
"Last-Translator: Waheed Ahmed , 2019\n"
"Language-Team: Chinese (Taiwan) (https://app.transifex.com/open-edx/teams/6205/zh_TW/)\n"
@@ -272,8 +272,8 @@ msgid "Video"
msgstr "影片"
#: cms/djangoapps/contentstore/views/component.py xmodule/capa_block.py
-msgid "Blank Advanced Problem"
-msgstr "空白進階問題"
+msgid "Blank Problem"
+msgstr ""
#: cms/djangoapps/contentstore/views/component.py
#: xmodule/video_block/video_block.py
@@ -374,8 +374,8 @@ msgstr "專業的 Ed"
#: common/djangoapps/course_modes/models.py xmodule/annotatable_block.py
#: xmodule/capa_block.py xmodule/conditional_block.py
#: xmodule/discussion_block.py xmodule/html_block.py
-#: xmodule/library_content_block.py xmodule/library_sourced_block.py
-#: xmodule/lti_block.py xmodule/split_test_block.py xmodule/unit_block.py
+#: xmodule/library_content_block.py xmodule/lti_block.py
+#: xmodule/split_test_block.py xmodule/unit_block.py
#: xmodule/word_cloud_block.py xmodule/x_module.py
msgid "Display Name"
msgstr "顯示名稱"
@@ -2848,6 +2848,12 @@ msgstr ""
msgid "Open Response Assessment"
msgstr ""
+#: lms/djangoapps/courseware/courses.py
+msgid ""
+"This Open Response Assessment's due dates are set by your instructor and "
+"can't be shifted."
+msgstr ""
+
#: lms/djangoapps/courseware/courses.py
msgid "Self Assessment"
msgstr ""
@@ -2864,12 +2870,6 @@ msgstr ""
msgid "Submission"
msgstr ""
-#: lms/djangoapps/courseware/courses.py
-msgid ""
-"Open Response Assessment due dates are set by your instructor and can't be "
-"shifted."
-msgstr ""
-
#. Translators: 'absolute' is a date such as "Jan 01,
#. 2020". 'relative' is a fuzzy description of the time until
#. 'absolute'. For example, 'absolute' might be "Jan 01, 2020",
@@ -5366,7 +5366,6 @@ msgstr ""
#: lms/templates/oauth2_provider/authorize.html
#: openedx/core/djangoapps/user_api/admin.py
-#: xmodule/templates/library-sourced-block-studio-view.html
#: cms/templates/course-create-rerun.html cms/templates/index.html
#: cms/templates/manage_users.html cms/templates/manage_users_lib.html
#: cms/templates/videos_index_pagination.html
@@ -5783,10 +5782,10 @@ msgid "Quotes"
msgstr "引言"
#: lms/templates/wiki/includes/editor_widget.html
-#, python-format
+#, python-brace-format
msgid ""
-"Markdown syntax is allowed. See the %(start_link)scheatsheet%(end_link)s for"
-" help."
+"Markdown syntax is allowed. See the {start_link}cheatsheet{end_link} for "
+"help."
msgstr ""
#: lms/templates/wiki/plugins/attachments/index.html
@@ -6704,8 +6703,8 @@ msgstr ""
#: openedx/core/djangoapps/discussions/models.py
msgid ""
-"The Posting availabilty in discussions whether it will be enabled, scheduled"
-" or indefinitely disabled."
+"The Posting availability in discussions whether it will be enabled, "
+"scheduled or indefinitely disabled."
msgstr ""
#: openedx/core/djangoapps/discussions/models.py
@@ -8509,8 +8508,7 @@ msgstr "XML 數據註解"
#: xmodule/annotatable_block.py xmodule/capa_block.py
#: xmodule/conditional_block.py xmodule/discussion_block.py
#: xmodule/html_block.py xmodule/library_content_block.py
-#: xmodule/library_root_xblock.py xmodule/library_sourced_block.py
-#: xmodule/poll_block.py xmodule/unit_block.py
+#: xmodule/library_root_xblock.py xmodule/poll_block.py xmodule/unit_block.py
#: xmodule/video_block/video_xfields.py xmodule/word_cloud_block.py
#: xmodule/x_module.py
msgid "The display name for this component."
@@ -10490,33 +10488,6 @@ msgstr "課程組件庫顯示名稱"
msgid "Enter the names of the advanced components to use in your library."
msgstr "輸入在課程組件庫中使用的進階組件名稱。"
-#: xmodule/library_sourced_block.py
-msgid "Library Blocks List"
-msgstr ""
-
-#: xmodule/library_sourced_block.py
-msgid "Enter the IDs of the library XBlocks that you wish to use."
-msgstr ""
-
-#: xmodule/library_sourced_block.py
-#, python-brace-format
-msgid "A maximum of {0} components may be added."
-msgstr ""
-
-#: xmodule/library_sourced_block.py
-msgid ""
-"No XBlock has been configured for this component. Use the editor to select "
-"the target blocks."
-msgstr ""
-
-#: xmodule/library_sourced_block.py
-msgid "Open Editor"
-msgstr ""
-
-#: xmodule/library_sourced_block.py
-msgid "Importing Library Block failed - are the IDs valid and readable?"
-msgstr ""
-
#: xmodule/lti_block.py
msgid ""
"The display name for this component. Analytics reports may also use the "
@@ -11113,10 +11084,6 @@ msgstr "這個內容實驗已經被標記為影響內容可見度。"
msgid "External Discussion"
msgstr "外部討論"
-#: xmodule/templates/library-sourced-block-studio-view.html
-msgid "Save and Import"
-msgstr ""
-
#: xmodule/vertical_block.py
msgid "Enable in-context discussions for the Unit"
msgstr ""
@@ -14597,10 +14564,6 @@ msgstr "下載學生成績"
msgid "Print or share your certificate:"
msgstr "顯示或共享您的證書:"
-#: lms/templates/certificates/_accomplishment-banner.html
-msgid "Click the link to see my certificate."
-msgstr "點擊鏈接可查看我的證書。"
-
#: lms/templates/certificates/_accomplishment-banner.html
msgid "Post on Facebook"
msgstr "發表在Facebook"
diff --git a/conf/locale/zh_TW/LC_MESSAGES/djangojs.po b/conf/locale/zh_TW/LC_MESSAGES/djangojs.po
index b9c44927aecc..15d153824aef 100644
--- a/conf/locale/zh_TW/LC_MESSAGES/djangojs.po
+++ b/conf/locale/zh_TW/LC_MESSAGES/djangojs.po
@@ -132,7 +132,7 @@ msgid ""
msgstr ""
"Project-Id-Version: edx-platform\n"
"Report-Msgid-Bugs-To: openedx-translation@googlegroups.com\n"
-"POT-Creation-Date: 2023-08-27 20:42+0000\n"
+"POT-Creation-Date: 2023-09-17 20:42+0000\n"
"PO-Revision-Date: 2014-06-11 15:18+0000\n"
"Last-Translator: Andrew Lau , 2017\n"
"Language-Team: Chinese (Taiwan) (http://app.transifex.com/open-edx/edx-platform/language/zh_TW/)\n"
@@ -143,14 +143,6 @@ msgstr ""
"Plural-Forms: nplurals=1; plural=0;\n"
"Generated-By: Babel 2.8.0\n"
-#: cms/static/cms/js/main.js cms/static/js/views/active_video_upload_list.js
-#: cms/static/js/views/video_transcripts.js
-#: xmodule/assets/library_source_block/public/js/library_source_block.js
-msgid ""
-"This may be happening because of an error with our server or your internet "
-"connection. Try refreshing the page or making sure you are online."
-msgstr ""
-
#: cms/static/cms/js/xblock/cms.runtime.v1.js
#: cms/static/js/certificates/views/signatory_details.js
#: cms/static/js/models/section.js cms/static/js/utils/drag_and_drop.js
@@ -162,7 +154,6 @@ msgstr ""
#: cms/static/js/views/modals/edit_xblock.js cms/static/js/views/tabs.js
#: cms/static/js/views/utils/xblock_utils.js lms/static/js/ccx/schedule.js
#: lms/static/js/views/fields.js
-#: xmodule/assets/library_source_block/public/js/library_source_block.js
msgid "Saving"
msgstr "儲存中"
@@ -3772,18 +3763,6 @@ msgstr ""
msgid "Updating with latest library content"
msgstr "以最新的課程組件庫內容更新中"
-#: xmodule/assets/library_source_block/LibrarySourcedBlockPicker.jsx
-msgid "Loading..."
-msgstr ""
-
-#: xmodule/assets/library_source_block/LibrarySourcedBlockPicker.jsx
-msgid "Selected blocks"
-msgstr ""
-
-#: xmodule/assets/library_source_block/public/js/library_source_block.js
-msgid "Unable to update settings"
-msgstr ""
-
#: xmodule/assets/split_test/public/js/split_test_author_view.js
#: xmodule/js/public/js/split_test_author_view.js
msgid "Creating missing groups"
@@ -5382,6 +5361,13 @@ msgstr ""
msgid "Turn off transcripts"
msgstr ""
+#: cms/static/cms/js/main.js cms/static/js/views/active_video_upload_list.js
+#: cms/static/js/views/video_transcripts.js
+msgid ""
+"This may be happening because of an error with our server or your internet "
+"connection. Try refreshing the page or making sure you are online."
+msgstr ""
+
#: cms/static/cms/js/main.js
msgid "Studio's having trouble saving your work"
msgstr ""
@@ -5922,7 +5908,7 @@ msgstr ""
#: cms/static/js/views/course_outline.js
#: cms/static/js/views/pages/container.js
-msgid "New files were added to this course's Files & Uploads"
+msgid "New file(s) added to Files & Uploads."
msgstr ""
#: cms/static/js/views/course_outline.js
@@ -5930,6 +5916,16 @@ msgstr ""
msgid "The following required files were imported to this course:"
msgstr ""
+#: cms/static/js/views/course_outline.js
+#: cms/static/js/views/pages/container.js
+msgid "View files"
+msgstr ""
+
+#: cms/static/js/views/course_outline.js
+#: cms/static/js/views/pages/container.js
+msgid "Dismiss"
+msgstr ""
+
#: cms/static/js/views/course_rerun.js
msgid "Create Re-run"
msgstr "建立再次執行"
diff --git a/docs/decisions/0013-library-reference-content-block.rst b/docs/decisions/0013-library-reference-content-block.rst
index cd842d8b0f79..3d8dcb2153a2 100644
--- a/docs/decisions/0013-library-reference-content-block.rst
+++ b/docs/decisions/0013-library-reference-content-block.rst
@@ -3,7 +3,13 @@ Referencing Content Blocks in Library V2
Status
=======
-Pending
+
+**Deferred** as of September 2023.
+
+The goals described in the ADR are still relevant to future development,
+but for the intial launch of Blockstore-backed content libraries,
+the existing ``library_content`` block will be used instead,
+and it will continue to copy blocks from Blockstore into Modulestore as necessary.
Context
=======
diff --git a/lms/celery.py b/lms/celery.py
index 4eff388c5084..eca05a64e192 100644
--- a/lms/celery.py
+++ b/lms/celery.py
@@ -7,10 +7,6 @@
import os
-from celery.signals import task_prerun
-from django.dispatch import receiver
-from edx_django_utils.monitoring import set_custom_attribute
-
# Patch the xml libs before anything else.
from openedx.core.lib.safe_lxml import defuse_xml_libs
@@ -21,20 +17,3 @@
# and then instantiate the Celery singleton.
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'lms.envs.production')
from openedx.core.lib.celery import APP # pylint: disable=wrong-import-position,unused-import
-
-
-@receiver(task_prerun)
-def set_code_owner_on_celery_tasks(*, task, **kwargs):
- """
- Sets the `code_owner` custom attribute on all Celery tasks, obviating the
- need for the set_code_owner_attribute task decorator.
-
- ...or rather, we're not yet sure whether this works, so we're setting a
- different custom attribute first.
-
- See https://github.com/openedx/edx-platform/issues/33179 for details.
- """
- try:
- set_custom_attribute("auto_celery_code_owner_module", task.__module__)
- except Exception as e: # pylint: disable=broad-except
- set_custom_attribute("auto_celery_code_owner_error", repr(e))
diff --git a/lms/djangoapps/bulk_email/models.py b/lms/djangoapps/bulk_email/models.py
index 37d9a6276f4c..f6e232232a29 100644
--- a/lms/djangoapps/bulk_email/models.py
+++ b/lms/djangoapps/bulk_email/models.py
@@ -164,7 +164,8 @@ class Meta:
app_label = "bulk_email"
def __init__(self, *args, **kwargs):
- kwargs['target_type'] = SEND_TO_COHORT
+ if not args:
+ kwargs['target_type'] = SEND_TO_COHORT
super().__init__(*args, **kwargs)
def __str__(self):
@@ -209,7 +210,8 @@ class Meta:
app_label = "bulk_email"
def __init__(self, *args, **kwargs):
- kwargs['target_type'] = SEND_TO_TRACK
+ if not args:
+ kwargs['target_type'] = SEND_TO_TRACK
super().__init__(*args, **kwargs)
def __str__(self):
diff --git a/lms/djangoapps/certificates/config.py b/lms/djangoapps/certificates/config.py
index fa9b3f2f824e..6df62ae563b1 100644
--- a/lms/djangoapps/certificates/config.py
+++ b/lms/djangoapps/certificates/config.py
@@ -28,3 +28,16 @@
# .. toggle_target_removal_date: 2023-07-31
# .. toggle_tickets: TODO
SEND_CERTIFICATE_CREATED_SIGNAL = SettingToggle('SEND_CERTIFICATE_CREATED_SIGNAL', default=False, module_name=__name__)
+
+
+# .. toggle_name: SEND_CERTIFICATE_REVOKED_SIGNAL
+# .. toggle_implementation: SettingToggle
+# .. toggle_default: False
+# .. toggle_description: When True, the system will publish `CERTIFICATE_REVOKED` signals to the event bus. The
+# `CERTIFICATE_REVOKED` signal is emit when a certificate has been revoked from a learner and the revocation process
+# has completed.
+# .. toggle_use_cases: temporary
+# .. toggle_creation_date: 2023-09-15
+# .. toggle_target_removal_date: 2024-01-01
+# .. toggle_tickets: TODO
+SEND_CERTIFICATE_REVOKED_SIGNAL = SettingToggle('SEND_CERTIFICATE_REVOKED_SIGNAL', default=False, module_name=__name__)
diff --git a/lms/djangoapps/certificates/models.py b/lms/djangoapps/certificates/models.py
index feb387cb6a99..7b5677a6909c 100644
--- a/lms/djangoapps/certificates/models.py
+++ b/lms/djangoapps/certificates/models.py
@@ -378,6 +378,10 @@ def _revoke_certificate(self, status, mode=None, grade=None, source=None):
if not grade:
grade = ''
+ # the grade can come through revocation as a float, so we must convert it to a string to be compatible with the
+ # `CERTIFICATE_REVOKED` event definition
+ elif isinstance(grade, float):
+ grade = str(grade)
if not mode:
mode = self.mode
diff --git a/lms/djangoapps/certificates/signals.py b/lms/djangoapps/certificates/signals.py
index 676c10fb9c8f..4d43f0ed4983 100644
--- a/lms/djangoapps/certificates/signals.py
+++ b/lms/djangoapps/certificates/signals.py
@@ -11,7 +11,7 @@
from common.djangoapps.course_modes import api as modes_api
from common.djangoapps.student.models import CourseEnrollment
from common.djangoapps.student.signals import ENROLLMENT_TRACK_UPDATED
-from lms.djangoapps.certificates.config import SEND_CERTIFICATE_CREATED_SIGNAL
+from lms.djangoapps.certificates.config import SEND_CERTIFICATE_CREATED_SIGNAL, SEND_CERTIFICATE_REVOKED_SIGNAL
from lms.djangoapps.certificates.generation_handler import (
CertificateGenerationNotAllowed,
generate_allowlist_certificate_task,
@@ -32,7 +32,7 @@
COURSE_GRADE_NOW_PASSED,
LEARNER_NOW_VERIFIED
)
-from openedx_events.learning.signals import CERTIFICATE_CREATED
+from openedx_events.learning.signals import CERTIFICATE_CREATED, CERTIFICATE_REVOKED
log = logging.getLogger(__name__)
@@ -162,7 +162,7 @@ def _listen_for_enrollment_mode_change(sender, user, course_key, mode, **kwargs)
@receiver(CERTIFICATE_CREATED)
-def listen_for_certificate_created_event(sender, signal, **kwargs):
+def listen_for_certificate_created_event(sender, signal, **kwargs): # pylint: disable=unused-argument
"""
Publish `CERTIFICATE_CREATED` events to the event bus.
"""
@@ -174,3 +174,18 @@ def listen_for_certificate_created_event(sender, signal, **kwargs):
event_data={'certificate': kwargs['certificate']},
event_metadata=kwargs['metadata']
)
+
+
+@receiver(CERTIFICATE_REVOKED)
+def listen_for_certificate_revoked_event(sender, signal, **kwargs): # pylint: disable=unused-argument
+ """
+ Publish `CERTIFICATE_REVOKED` events to the event bus.
+ """
+ if SEND_CERTIFICATE_REVOKED_SIGNAL.is_enabled():
+ get_producer().send(
+ signal=CERTIFICATE_REVOKED,
+ topic='learning-certificate-lifecycle',
+ event_key_field='certificate.course.course_key',
+ event_data={'certificate': kwargs['certificate']},
+ event_metadata=kwargs['metadata']
+ )
diff --git a/lms/djangoapps/certificates/tests/test_signals.py b/lms/djangoapps/certificates/tests/test_signals.py
index b5993eb623c3..4eb8cf27f48e 100644
--- a/lms/djangoapps/certificates/tests/test_signals.py
+++ b/lms/djangoapps/certificates/tests/test_signals.py
@@ -21,13 +21,16 @@
CertificateGenerationConfiguration,
GeneratedCertificate
)
-from lms.djangoapps.certificates.signals import listen_for_certificate_created_event
+from lms.djangoapps.certificates.signals import (
+ listen_for_certificate_created_event,
+ listen_for_certificate_revoked_event
+)
from lms.djangoapps.certificates.tests.factories import CertificateAllowlistFactory, GeneratedCertificateFactory
from lms.djangoapps.grades.course_grade_factory import CourseGradeFactory
from lms.djangoapps.grades.tests.utils import mock_passing_grade
from lms.djangoapps.verify_student.models import SoftwareSecurePhotoVerification
from openedx_events.data import EventsMetadata
-from openedx_events.learning.signals import CERTIFICATE_CREATED
+from openedx_events.learning.signals import CERTIFICATE_CREATED, CERTIFICATE_REVOKED
from openedx_events.learning.data import CourseData, UserData, UserPersonalData, CertificateData
@@ -458,22 +461,9 @@ def setUp(self):
mode='verified',
)
- @override_settings(SEND_CERTIFICATE_CREATED_SIGNAL=False)
- @mock.patch('lms.djangoapps.certificates.signals.get_producer', autospec=True)
- def test_event_disabled(self, mock_producer):
- """
- Test to verify that we do not push `CERTIFICATE_CREATED` events to the event bus if the
- `SEND_CERTIFICATE_CREATED_SIGNAL` setting is disabled.
- """
- listen_for_certificate_created_event(None, CERTIFICATE_CREATED)
- mock_producer.assert_not_called()
-
- @override_settings(SEND_CERTIFICATE_CREATED_SIGNAL=True)
- @mock.patch('lms.djangoapps.certificates.signals.get_producer', autospec=True)
- def test_event_enabled(self, mock_producer):
+ def _create_event_data(self, event_type, certificate_status):
"""
- Test to verify that we push `CERTIFICATE_CREATED` events to the event bus if the
- `SEND_CERTIFICATE_CREATED_SIGNAL` setting is enabled.
+ Utility function to create test data for unit tests.
"""
expected_course_data = CourseData(course_key=self.course.id)
expected_user_data = UserData(
@@ -490,12 +480,12 @@ def test_event_enabled(self, mock_producer):
course=expected_course_data,
mode='verified',
grade='',
- current_status='downloadable',
+ current_status=certificate_status,
download_url='',
name='',
)
- event_metadata = EventsMetadata(
- event_type=CERTIFICATE_CREATED.event_type,
+ expected_event_metadata = EventsMetadata(
+ event_type=event_type.event_type,
id=uuid4(),
minorversion=0,
source='openedx/lms/web',
@@ -503,15 +493,59 @@ def test_event_enabled(self, mock_producer):
time=datetime.now(timezone.utc)
)
- event_kwargs = {
+ return {
'certificate': expected_certificate_data,
- 'metadata': event_metadata
+ 'metadata': expected_event_metadata,
}
- listen_for_certificate_created_event(None, CERTIFICATE_CREATED, **event_kwargs)
+ @override_settings(SEND_CERTIFICATE_CREATED_SIGNAL=False)
+ @mock.patch('lms.djangoapps.certificates.signals.get_producer', autospec=True)
+ def test_certificate_created_event_disabled(self, mock_producer):
+ """
+ Test to verify that we do not publish `CERTIFICATE_CREATED` events to the event bus if the
+ `SEND_CERTIFICATE_CREATED_SIGNAL` setting is disabled.
+ """
+ listen_for_certificate_created_event(None, CERTIFICATE_CREATED)
+ mock_producer.assert_not_called()
+
+ @override_settings(SEND_CERTIFICATE_REVOKED_SIGNAL=False)
+ @mock.patch('lms.djangoapps.certificates.signals.get_producer', autospec=True)
+ def test_certificate_revoked_event_disabled(self, mock_producer):
+ """
+ Test to verify that we do not publish `CERTIFICATE_REVOKED` events to the event bus if the
+ `SEND_CERTIFICATE_REVOKED_SIGNAL` setting is disabled.
+ """
+ listen_for_certificate_created_event(None, CERTIFICATE_REVOKED)
+ mock_producer.assert_not_called()
+
+ @override_settings(SEND_CERTIFICATE_CREATED_SIGNAL=True)
+ @mock.patch('lms.djangoapps.certificates.signals.get_producer', autospec=True)
+ def test_certificate_created_event_enabled(self, mock_producer):
+ """
+ Test to verify that we push `CERTIFICATE_CREATED` events to the event bus if the
+ `SEND_CERTIFICATE_CREATED_SIGNAL` setting is enabled.
+ """
+ event_data = self._create_event_data(CERTIFICATE_CREATED, CertificateStatuses.downloadable)
+ listen_for_certificate_created_event(None, CERTIFICATE_CREATED, **event_data)
# verify that the data sent to the event bus matches what we expect
data = mock_producer.return_value.send.call_args.kwargs
assert data['signal'].event_type == CERTIFICATE_CREATED.event_type
- assert data['event_data']['certificate'] == expected_certificate_data
+ assert data['event_data']['certificate'] == event_data['certificate']
+ assert data['topic'] == 'learning-certificate-lifecycle'
+ assert data['event_key_field'] == 'certificate.course.course_key'
+
+ @override_settings(SEND_CERTIFICATE_REVOKED_SIGNAL=True)
+ @mock.patch('lms.djangoapps.certificates.signals.get_producer', autospec=True)
+ def test_certificate_revoked_event_enabled(self, mock_producer):
+ """
+ Test to verify that we push `CERTIFICATE_REVOKED` events to the event bus if the
+ `SEND_CERTIFICATE_REVOKED_SIGNAL` setting is enabled.
+ """
+ event_data = self._create_event_data(CERTIFICATE_REVOKED, CertificateStatuses.notpassing)
+ listen_for_certificate_revoked_event(None, CERTIFICATE_REVOKED, **event_data)
+ # verify that the data sent to the event bus matches what we expect
+ data = mock_producer.return_value.send.call_args.kwargs
+ assert data['signal'].event_type == CERTIFICATE_REVOKED.event_type
+ assert data['event_data']['certificate'] == event_data['certificate']
assert data['topic'] == 'learning-certificate-lifecycle'
assert data['event_key_field'] == 'certificate.course.course_key'
diff --git a/lms/djangoapps/course_home_api/course_metadata/tests/test_views.py b/lms/djangoapps/course_home_api/course_metadata/tests/test_views.py
index 1ff81aaee64b..74b66fa5f068 100644
--- a/lms/djangoapps/course_home_api/course_metadata/tests/test_views.py
+++ b/lms/djangoapps/course_home_api/course_metadata/tests/test_views.py
@@ -5,6 +5,7 @@
import ddt
import json
import mock
+from django.db import transaction
from django.urls import reverse
from edx_toggles.toggles.testutils import override_waffle_flag
from unittest.mock import patch
@@ -86,7 +87,9 @@ def test_get_masqueraded_user(self):
def test_get_unknown_course(self):
url = reverse('course-home:course-metadata', args=['course-v1:unknown+course+2T2020'])
- response = self.client.get(url)
+ # Django TestCase wraps every test in a transaction, so we must specifically wrap this when we expect an error
+ with transaction.atomic():
+ response = self.client.get(url)
assert response.status_code == 404
def _assert_course_access_response(self, response, expect_course_access, expected_error_code):
diff --git a/lms/djangoapps/course_home_api/course_metadata/views.py b/lms/djangoapps/course_home_api/course_metadata/views.py
index e534d03ebbf7..ba789ea25458 100644
--- a/lms/djangoapps/course_home_api/course_metadata/views.py
+++ b/lms/djangoapps/course_home_api/course_metadata/views.py
@@ -2,6 +2,8 @@
General view for the Course Home that contains metadata every page needs.
"""
+from django.db import transaction
+from django.utils.decorators import method_decorator
from opaque_keys.edx.keys import CourseKey
from rest_framework.generics import RetrieveAPIView
from rest_framework.response import Response
@@ -23,6 +25,7 @@
from lms.djangoapps.courseware.tabs import get_course_tab_list
+@method_decorator(transaction.non_atomic_requests, name='dispatch')
class CourseHomeMetadataView(RetrieveAPIView):
"""
**Use Cases**
diff --git a/lms/djangoapps/course_home_api/outline/views.py b/lms/djangoapps/course_home_api/outline/views.py
index 7650c2ae5320..813bde793f88 100644
--- a/lms/djangoapps/course_home_api/outline/views.py
+++ b/lms/djangoapps/course_home_api/outline/views.py
@@ -303,9 +303,20 @@ def get(self, request, *args, **kwargs): # pylint: disable=too-many-statements
)
available_seq_ids = {str(usage_key) for usage_key in user_course_outline.sequences}
+ available_section_ids = {str(section.usage_key) for section in user_course_outline.sections}
+
+ # course_blocks is a reference to the root of the course,
+ # so we go through the chapters (sections) and keep only those
+ # which are part of the outline.
+ course_blocks['children'] = [
+ chapter_data
+ for chapter_data in course_blocks.get('children', [])
+ if chapter_data['id'] in available_section_ids
+ ]
+
# course_blocks is a reference to the root of the course, so we go
# through the chapters (sections) to look for sequences to remove.
- for chapter_data in course_blocks.get('children', []):
+ for chapter_data in course_blocks['children']:
chapter_data['children'] = [
seq_data
for seq_data in chapter_data['children']
diff --git a/lms/djangoapps/course_home_api/toggles.py b/lms/djangoapps/course_home_api/toggles.py
index 4cd1afe9c784..759f8bc48465 100644
--- a/lms/djangoapps/course_home_api/toggles.py
+++ b/lms/djangoapps/course_home_api/toggles.py
@@ -6,7 +6,17 @@
WAFFLE_FLAG_NAMESPACE = 'course_home'
-COURSE_HOME_MICROFRONTEND_PROGRESS_TAB = CourseWaffleFlag( # lint-amnesty, pylint: disable=toggle-missing-annotation
+# .. toggle_name: course_home.course_home_mfe_progress_tab
+# .. toggle_implementation: WaffleFlag
+# .. toggle_default: False
+# .. toggle_description: This toggle controls the user interface behavior of the progress tab in
+# the Learning Management System. When set to True, the progress tab utilizes the newly introduced
+# Learning MFE graphs. When set to False (default), it utilizes existing grade graph from edx-platform.
+# .. toggle_use_cases: temporary
+# .. toggle_creation_date: 2021-03-12
+# .. toggle_target_removal_date: 2024-01-01
+# .. toggle_tickets: https://github.com/openedx/edx-platform/pull/26978
+COURSE_HOME_MICROFRONTEND_PROGRESS_TAB = CourseWaffleFlag(
f'{WAFFLE_FLAG_NAMESPACE}.course_home_mfe_progress_tab', __name__
)
diff --git a/lms/djangoapps/courseware/tests/test_user_state_client.py b/lms/djangoapps/courseware/tests/test_user_state_client.py
index c8d9337f0539..690a64b8b8c5 100644
--- a/lms/djangoapps/courseware/tests/test_user_state_client.py
+++ b/lms/djangoapps/courseware/tests/test_user_state_client.py
@@ -3,18 +3,721 @@
defined in edx_user_state_client.
"""
-
+import pytz
+from opaque_keys.edx.locator import BlockUsageLocator, CourseLocator
+from xblock.fields import Scope
+from datetime import datetime
+from unittest import TestCase
from collections import defaultdict
-
from django.db import connections
-from edx_user_state_client.tests import UserStateClientTestBase
-
from common.djangoapps.student.tests.factories import UserFactory
-from lms.djangoapps.courseware.user_state_client import DjangoXBlockUserStateClient
+from lms.djangoapps.courseware.user_state_client import (
+ DjangoXBlockUserStateClient,
+ XBlockUserStateClient,
+ XBlockUserState
+)
from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase # lint-amnesty, pylint: disable=wrong-import-order
+class _UserStateClientTestUtils(TestCase):
+ """
+ Utility methods for implementing blackbox XBlockUserStateClient tests.
+
+ User and Block indexes should provide unique user ids and UsageKeys.
+ Course indexes should be assigned to blocks by using integer division by 1000
+ (this allows for tests of up to 1000 blocks per course).
+ """
+
+ __test__ = False
+
+ scope = Scope.user_state
+ client = None
+
+ @staticmethod
+ def _user(user):
+ """Return the username for user ``user``."""
+ return f"user{user}"
+
+ def _block(self, block):
+ """Return a UsageKey for the block ``block``."""
+ course = block // 1000
+ return BlockUsageLocator(
+ self._course(course),
+ self._block_type(block),
+ f'block{block}'
+ )
+
+ @staticmethod
+ def _block_type(block): # pylint: disable=unused-argument
+ """Return the block type for the specified ``block``."""
+ return 'block_type'
+
+ @staticmethod
+ def _course(course):
+ """Return a CourseKey for the course ``course``"""
+ return CourseLocator(
+ f'org{course}',
+ f'course{course}',
+ f'run{course}',
+ )
+
+ def get(self, user, block, fields=None):
+ """
+ Get the state for the specified user and block.
+
+ This wraps :meth:`~XBlockUserStateClient.get`
+ to take indexes rather than actual values to make tests easier
+ to write concisely.
+ """
+ return self.client.get(
+ username=self._user(user),
+ block_key=self._block(block),
+ scope=self.scope,
+ fields=fields
+ )
+
+ def set(self, user, block, state):
+ """
+ Set the state for the specified user and block.
+
+ This wraps :meth:`~XBlockUserStateClient.set`
+ to take indexes rather than actual values to make tests easier
+ to write concisely.
+ """
+ return self.client.set(
+ username=self._user(user),
+ block_key=self._block(block),
+ state=state,
+ scope=self.scope,
+ )
+
+ def delete(self, user, block, fields=None):
+ """
+ Delete the state for the specified user and block.
+
+ This wraps :meth:`~XBlockUserStateClient.delete`
+ to take indexes rather than actual values to make tests easier
+ to write concisely.
+ """
+ return self.client.delete(
+ username=self._user(user),
+ block_key=self._block(block),
+ scope=self.scope,
+ fields=fields
+ )
+
+ def get_many(self, user, blocks, fields=None):
+ """
+ Get the state for the specified user and blocks.
+
+ This wraps :meth:`~XBlockUserStateClient.get_many`
+ to take indexes rather than actual values to make tests easier
+ to write concisely.
+ """
+ return self.client.get_many(
+ username=self._user(user),
+ block_keys=[self._block(block) for block in blocks],
+ scope=self.scope,
+ fields=fields,
+ )
+
+ def set_many(self, user, block_to_state):
+ """
+ Set the state for the specified user and blocks.
+
+ This wraps :meth:`~XBlockUserStateClient.set_many`
+ to take indexes rather than actual values to make tests easier
+ to write concisely.
+ """
+ return self.client.set_many(
+ username=self._user(user),
+ block_keys_to_state={
+ self._block(block): state
+ for block, state
+ in list(block_to_state.items())
+ },
+ scope=self.scope,
+ )
+
+ def delete_many(self, user, blocks, fields=None):
+ """
+ Delete the state for the specified user and blocks.
+
+ This wraps :meth:`~XBlockUserStateClient.delete_many`
+ to take indexes rather than actual values to make tests easier
+ to write concisely.
+ """
+ return self.client.delete_many(
+ username=self._user(user),
+ block_keys=[self._block(block) for block in blocks],
+ scope=self.scope,
+ fields=fields,
+ )
+
+ def get_history(self, user, block):
+ """
+ Return the state history for the specified user and block.
+
+ This wraps :meth:`~XBlockUserStateClient.get_history`
+ to take indexes rather than actual values to make tests easier
+ to write concisely.
+ """
+ return self.client.get_history(
+ username=self._user(user),
+ block_key=self._block(block),
+ scope=self.scope,
+ )
+
+ def iter_all_for_block(self, block):
+ """
+ Yield the state for all users for the specified block.
+
+ This wraps :meth:`~XBlockUserStateClient.iter_all_for_blocks`
+ to take indexes rather than actual values, to make tests easier
+ to write concisely.
+ """
+ return self.client.iter_all_for_block(
+ block_key=self._block(block),
+ scope=self.scope,
+ )
+
+ def iter_all_for_course(self, course, block_type=None):
+ """
+ Yield the state for all users for the specified block.
+
+ This wraps :meth:`~XBlockUserStateClient.iter_all_for_blocks`
+ to take indexes rather than actual values, to make tests easier
+ to write concisely.
+ """
+ return self.client.iter_all_for_course(
+ course_key=self._course(course),
+ block_type=block_type,
+ scope=self.scope,
+ )
+
+
+class _UserStateClientTestCRUD(_UserStateClientTestUtils):
+ """
+ Blackbox tests of basic XBlockUserStateClient get/set/delete functionality.
+ """
+
+ __test__ = False
+
+ def test_set_get(self):
+ self.set(user=0, block=0, state={'a': 'b'})
+ self.assertEqual(self.get(user=0, block=0).state, {'a': 'b'})
+
+ def test_set_get_get(self):
+ self.set(user=0, block=0, state={'a': 'b'})
+ self.assertEqual(self.get(user=0, block=0).state, {'a': 'b'})
+ self.assertEqual(self.get(user=0, block=0).state, {'a': 'b'})
+
+ def test_set_set_get(self):
+ self.set(user=0, block=0, state={'a': 'b'})
+ self.set(user=0, block=0, state={'a': 'c'})
+ self.assertEqual(self.get(user=0, block=0).state, {'a': 'c'})
+
+ def test_set_overlay(self):
+ self.set(user=0, block=0, state={'a': 'b'})
+ self.set(user=0, block=0, state={'b': 'c'})
+ self.assertEqual(self.get(user=0, block=0).state, {'a': 'b', 'b': 'c'})
+
+ def test_get_fields(self):
+ self.set(user=0, block=0, state={'a': 'b', 'b': 'c'})
+ self.assertEqual(self.get(user=0, block=0, fields=['a']).state, {'a': 'b'})
+ self.assertEqual(self.get(user=0, block=0, fields=['b']).state, {'b': 'c'})
+ self.assertEqual(self.get(user=0, block=0, fields=['a', 'b']).state, {'a': 'b', 'b': 'c'})
+
+ def test_get_missing_block(self):
+ self.set(user=0, block=1, state={})
+ with self.assertRaises(self.client.DoesNotExist):
+ self.get(user=0, block=0)
+
+ def test_get_missing_user(self):
+ self.set(user=1, block=0, state={})
+ with self.assertRaises(self.client.DoesNotExist):
+ self.get(user=0, block=0)
+
+ def test_get_missing_field(self):
+ self.set(user=0, block=0, state={'a': 'b'})
+ self.assertEqual(self.get(user=0, block=0, fields=['a', 'b']).state, {'a': 'b'})
+
+ def test_set_two_users(self):
+ self.set(user=0, block=0, state={'a': 'b'})
+ self.set(user=1, block=0, state={'b': 'c'})
+ self.assertEqual(self.get(user=0, block=0).state, {'a': 'b'})
+ self.assertEqual(self.get(user=1, block=0).state, {'b': 'c'})
+
+ def test_set_two_blocks(self):
+ self.set(user=0, block=0, state={'a': 'b'})
+ self.set(user=0, block=1, state={'b': 'c'})
+ self.assertEqual(self.get(user=0, block=0).state, {'a': 'b'})
+ self.assertEqual(self.get(user=0, block=1).state, {'b': 'c'})
+
+ def test_set_many(self):
+ self.set_many(user=0, block_to_state={0: {'a': 'b'}, 1: {'b': 'c'}})
+ self.assertEqual(self.get(user=0, block=0).state, {'a': 'b'})
+ self.assertEqual(self.get(user=0, block=1).state, {'b': 'c'})
+
+ def test_get_many(self):
+ self.set_many(user=0, block_to_state={0: {'a': 'b'}, 1: {'b': 'c'}})
+ self.assertCountEqual(
+ [(entry.username, entry.block_key, entry.state) for entry in self.get_many(user=0, blocks=[0, 1])],
+ [
+ (self._user(0), self._block(0), {'a': 'b'}),
+ (self._user(0), self._block(1), {'b': 'c'})
+ ]
+ )
+
+ def test_delete(self):
+ with self.assertRaises(self.client.DoesNotExist):
+ self.get(user=0, block=0)
+
+ self.set(user=0, block=0, state={'a': 'b'})
+ self.assertEqual(self.get(user=0, block=0).state, {'a': 'b'})
+
+ self.delete(user=0, block=0)
+ with self.assertRaises(self.client.DoesNotExist):
+ self.get(user=0, block=0)
+
+ def test_delete_partial(self):
+ with self.assertRaises(self.client.DoesNotExist):
+ self.get(user=0, block=0)
+
+ self.set(user=0, block=0, state={'a': 'b', 'b': 'c'})
+ self.assertEqual(self.get(user=0, block=0).state, {'a': 'b', 'b': 'c'})
+
+ self.delete(user=0, block=0, fields=['a'])
+ self.assertEqual(self.get(user=0, block=0).state, {'b': 'c'})
+
+ def test_delete_last_field(self):
+ with self.assertRaises(self.client.DoesNotExist):
+ self.get(user=0, block=0)
+
+ self.set(user=0, block=0, state={'a': 'b'})
+ self.assertEqual(self.get(user=0, block=0).state, {'a': 'b'})
+
+ self.delete(user=0, block=0, fields=['a'])
+ with self.assertRaises(self.client.DoesNotExist):
+ self.get(user=0, block=0)
+
+ def test_delete_many(self):
+ self.assertCountEqual(self.get_many(user=0, blocks=[0, 1]), [])
+
+ self.set_many(user=0, block_to_state={
+ 0: {'a': 'b'},
+ 1: {'b': 'c'},
+ })
+
+ self.delete_many(user=0, blocks=[0, 1])
+ self.assertCountEqual(self.get_many(user=0, blocks=[0, 1]), [])
+
+ def test_delete_many_partial(self):
+ self.assertCountEqual(self.get_many(user=0, blocks=[0, 1]), [])
+
+ self.set_many(user=0, block_to_state={
+ 0: {'a': 'b'},
+ 1: {'b': 'c'},
+ })
+
+ self.delete_many(user=0, blocks=[0, 1], fields=['a'])
+ self.assertCountEqual(
+ [(entry.block_key, entry.state) for entry in self.get_many(user=0, blocks=[0, 1])],
+ [(self._block(1), {'b': 'c'})]
+ )
+
+ def test_delete_many_last_field(self):
+ self.assertCountEqual(self.get_many(user=0, blocks=[0, 1]), [])
+
+ self.set_many(user=0, block_to_state={
+ 0: {'a': 'b'},
+ 1: {'b': 'c'},
+ })
+
+ self.delete_many(user=0, blocks=[0, 1], fields=['a', 'b'])
+ self.assertCountEqual(self.get_many(user=0, blocks=[0, 1]), [])
+
+ def test_get_mod_date(self):
+ start_time = datetime.now(pytz.utc)
+ self.set_many(user=0, block_to_state={0: {'a': 'b'}, 1: {'b': 'c'}})
+ end_time = datetime.now(pytz.utc)
+
+ mod_dates = self.get(user=0, block=0)
+
+ self.assertCountEqual(list(mod_dates.state.keys()), ["a"])
+ self.assertGreater(mod_dates.updated, start_time)
+ self.assertLess(mod_dates.updated, end_time)
+
+ def test_get_many_mod_date(self):
+ start_time = datetime.now(pytz.utc)
+ self.set_many(
+ user=0,
+ block_to_state={0: {'a': 'b'}, 1: {'a': 'd'}})
+ mid_time = datetime.now(pytz.utc)
+ self.set_many(
+ user=0,
+ block_to_state={1: {'a': 'c'}})
+ end_time = datetime.now(pytz.utc)
+
+ mod_dates = list(self.get_many(
+ user=0,
+ blocks=[0, 1],
+ fields=["a"]))
+
+ self.assertCountEqual(
+ [result.block_key for result in mod_dates],
+ [self._block(0), self._block(1)])
+ self.assertCountEqual(
+ list(mod_dates[0].state.keys()),
+ ["a"])
+ self.assertGreater(mod_dates[0].updated, start_time)
+ self.assertLess(mod_dates[0].updated, mid_time)
+ self.assertCountEqual(
+ list(mod_dates[1].state.keys()),
+ ["a"])
+ self.assertGreater(mod_dates[1].updated, mid_time)
+ self.assertLess(mod_dates[1].updated, end_time)
+
+
+class _UserStateClientTestHistory(_UserStateClientTestUtils):
+ """
+ Blackbox tests of basic XBlockUserStateClient history functionality.
+ """
+
+ __test__ = False
+
+ def test_empty_history(self):
+ with self.assertRaises(self.client.DoesNotExist):
+ next(self.get_history(user=0, block=0))
+
+ def test_single_history(self):
+ self.set(user=0, block=0, state={'a': 'b'})
+ self.assertEqual(
+ [history.state for history in self.get_history(user=0, block=0)],
+ [{'a': 'b'}]
+ )
+
+ def test_multiple_history_entries(self):
+ for val in range(3):
+ self.set(user=0, block=0, state={'a': val})
+
+ history = list(self.get_history(user=0, block=0))
+
+ self.assertEqual(
+ [entry.state for entry in history],
+ [{'a': 2}, {'a': 1}, {'a': 0}]
+ )
+
+ # Assert that the update times are reverse sorted (by
+ # actually reverse-sorting them, and then asserting that
+ # the sorted version is the same as the initial version)
+ self.assertEqual(
+ [entry.updated for entry in history],
+ sorted((entry.updated for entry in history), reverse=True)
+ )
+
+ def test_history_distinct(self):
+ self.set(user=0, block=0, state={'a': 0})
+ self.set(user=0, block=1, state={'a': 1})
+
+ self.assertEqual(
+ [history.state for history in self.get_history(user=0, block=0)],
+ [{'a': 0}]
+ )
+ self.assertEqual(
+ [history.state for history in self.get_history(user=0, block=1)],
+ [{'a': 1}]
+ )
+
+ def test_history_after_delete(self):
+ self.set(user=0, block=0, state={str(val): val for val in range(3)})
+ for val in range(3):
+ self.delete(user=0, block=0, fields=[str(val)])
+
+ self.assertEqual(
+ [history.state for history in self.get_history(user=0, block=0)],
+ [
+ None,
+ {'2': 2},
+ {'2': 2, '1': 1},
+ {'2': 2, '1': 1, '0': 0}
+ ]
+ )
+
+ def test_set_many_with_history(self):
+ self.set_many(user=0, block_to_state={0: {'a': 0}, 1: {'a': 1}})
+
+ self.assertEqual(
+ [history.state for history in self.get_history(user=0, block=0)],
+ [{'a': 0}]
+ )
+ self.assertEqual(
+ [history.state for history in self.get_history(user=0, block=1)],
+ [{'a': 1}]
+ )
+
+
+class _UserStateClientTestIterAll(_UserStateClientTestUtils):
+ """
+ Blackbox tests of basic XBlockUserStateClient global iteration functionality.
+ """
+
+ __test__ = False
+
+ def test_iter_blocks_empty(self):
+ self.assertCountEqual(
+ self.iter_all_for_block(block=0),
+ []
+ )
+
+ def test_iter_blocks_single_user(self):
+ self.set_many(user=0, block_to_state={0: {'a': 'b'}, 1: {'c': 'd'}})
+
+ self.assertCountEqual(
+ (item.state for item in self.iter_all_for_block(block=0)),
+ [{'a': 'b'}]
+ )
+
+ self.assertCountEqual(
+ (item.state for item in self.iter_all_for_block(block=1)),
+ [{'c': 'd'}]
+ )
+
+ def test_iter_blocks_many_users(self):
+ for user in range(3):
+ self.set_many(user, {0: {'a': user}, 1: {'c': user}})
+
+ self.assertCountEqual(
+ ((item.username, item.state) for item in self.iter_all_for_block(block=0)),
+ [
+ (self._user(0), {'a': 0}),
+ (self._user(1), {'a': 1}),
+ (self._user(2), {'a': 2}),
+ ]
+ )
+
+ def test_iter_blocks_deleted_block(self):
+ for user in range(3):
+ self.set_many(user, {0: {'a': user}, 1: {'c': user}})
+
+ self.delete(user=1, block=0)
+
+ self.assertCountEqual(
+ ((item.username, item.state) for item in self.iter_all_for_block(block=0)),
+ [
+ (self._user(0), {'a': 0}),
+ (self._user(2), {'a': 2}),
+ ]
+ )
+
+ def test_iter_course_empty(self):
+ self.assertCountEqual(
+ self.iter_all_for_course(course=0),
+ []
+ )
+
+ def test_iter_course_single_user(self):
+ self.set_many(user=0, block_to_state={0: {'a': 'b'}, 1001: {'c': 'd'}})
+
+ self.assertCountEqual(
+ (item.state for item in self.iter_all_for_course(course=0)),
+ [{'a': 'b'}]
+ )
+
+ self.assertCountEqual(
+ (item.state for item in self.iter_all_for_course(course=1)),
+ [{'c': 'd'}]
+ )
+
+ def test_iter_course_many_users(self):
+ for user in range(2):
+ for course in range(2):
+ self.set_many(
+ user,
+ block_to_state={
+ course * 1000 + 0: {'course': course},
+ course * 1000 + 1: {'user': user}
+ }
+ )
+
+ self.assertCountEqual(
+ ((item.username, item.block_key, item.state) for item in self.iter_all_for_course(course=1)),
+ [
+ (self._user(0), self._block(1000), {'course': 1}),
+ (self._user(0), self._block(1001), {'user': 0}),
+ (self._user(1), self._block(1000), {'course': 1}),
+ (self._user(1), self._block(1001), {'user': 1}),
+ ]
+ )
+
+ def test_iter_course_deleted_block(self):
+ for user in range(2):
+ for course in range(2):
+ self.set_many(
+ user,
+ block_to_state={
+ course * 1000 + 0: {'course': user},
+ course * 1000 + 1: {'user': user}
+ }
+ )
+
+ self.delete(user=1, block=0)
+ self.delete(user=1, block=1001)
+
+ self.assertCountEqual(
+ ((item.username, item.block_key, item.state) for item in self.iter_all_for_course(course=0)),
+ [
+ (self._user(0), self._block(0), {'course': 0}),
+ (self._user(0), self._block(1), {'user': 0}),
+ (self._user(1), self._block(1), {'user': 1}),
+ ]
+ )
+
+ self.assertCountEqual(
+ ((item.username, item.block_key, item.state) for item in self.iter_all_for_course(course=1)),
+ [
+ (self._user(0), self._block(1000), {'course': 0}),
+ (self._user(0), self._block(1001), {'user': 0}),
+ (self._user(1), self._block(1000), {'course': 1}),
+ ]
+ )
+
+
+class UserStateClientTestBase(_UserStateClientTestCRUD,
+ _UserStateClientTestHistory,
+ _UserStateClientTestIterAll):
+ """
+ Blackbox tests for XBlockUserStateClient implementations.
+ """
+
+ __test__ = False
+
+
+class DictUserStateClient(XBlockUserStateClient):
+ """
+ The simplest possible in-memory implementation of DictUserStateClient,
+ for testing the tests.
+ """
+ def __init__(self):
+ self._history = {}
+
+ def _add_state(self, username, block_key, scope, state):
+ """
+ Add the specified state to the state history of this block.
+ """
+ history_list = self._history.setdefault((username, block_key, scope), [])
+ history_list.insert(0, XBlockUserState(username, block_key, state, datetime.now(pytz.utc), scope))
+
+ def get_many(self, username, block_keys, scope=Scope.user_state, fields=None):
+ for key in block_keys:
+ if (username, key, scope) not in self._history:
+ continue
+
+ entry = self._history[(username, key, scope)][0]
+
+ if entry.state is None:
+ continue
+
+ if fields is None:
+ current_fields = list(entry.state.keys())
+ else:
+ current_fields = fields
+
+ yield entry._replace(state={
+ field: entry.state[field]
+ for field in current_fields
+ if field in entry.state
+ })
+
+ def set_many(self, username, block_keys_to_state, scope=Scope.user_state):
+ for key, state in list(block_keys_to_state.items()):
+ if (username, key, scope) in self._history:
+ current_state = self._history[(username, key, scope)][0].state.copy()
+ current_state.update(state)
+ self._add_state(username, key, scope, current_state)
+ else:
+ self._add_state(username, key, scope, state)
+
+ def delete_many(self, username, block_keys, scope=Scope.user_state, fields=None):
+ for key in block_keys:
+ if (username, key, scope) not in self._history:
+ continue
+
+ if fields is None:
+ self._add_state(username, key, scope, None)
+ else:
+ state = self._history[(username, key, scope)][0].state.copy()
+ for field in fields:
+ if field in state:
+ del state[field]
+ if not state:
+ self._add_state(username, key, scope, None)
+ else:
+ self._add_state(username, key, scope, state)
+
+ def get_history(self, username, block_key, scope=Scope.user_state):
+ """
+ Retrieve history of state changes for a given block for a given
+ student. We don't guarantee that history for many blocks will be fast.
+
+ If the specified block doesn't exist, raise :class:`~DoesNotExist`.
+
+ Arguments:
+ username: The name of the user whose history should be retrieved.
+ block_key (UsageKey): The UsageKey identifying which xblock history to retrieve.
+ scope (Scope): The scope to load data from.
+
+ Yields:
+ UserStateHistory entries for each modification to the specified XBlock, from latest
+ to earliest.
+ """
+ if (username, block_key, scope) not in self._history:
+ raise self.DoesNotExist(username, block_key, scope)
+
+ yield from self._history[(username, block_key, scope)]
+
+ def iter_all_for_block(self, block_key, scope=Scope.user_state):
+ """
+ You get no ordering guarantees. If you're using this method, you should be running in an
+ async task.
+ """
+ for (_, key, one_scope), entries in list(self._history.items()):
+ if entries[0].state is None:
+ continue
+
+ if key == block_key and one_scope == scope:
+ yield entries[0]
+
+ def iter_all_for_course(self, course_key, block_type=None, scope=Scope.user_state):
+ """
+ You get no ordering guarantees. If you're using this method, you should be running in an
+ async task.
+ """
+ for (_, key, one_scope), entries in list(self._history.items()):
+ if entries[0].state is None:
+ continue
+
+ if (
+ key.course_key == course_key and
+ one_scope == scope and
+ (block_type is None or key.block_type == block_type)
+ ):
+
+ yield entries[0]
+
+
+class TestDictUserStateClient(UserStateClientTestBase):
+ """
+ Tests of the DictUserStateClient backend.
+ """
+ __test__ = True
+
+ def setUp(self):
+ super().setUp()
+ self.client = DictUserStateClient()
+
+
class TestDjangoUserStateClient(UserStateClientTestBase, ModuleStoreTestCase):
"""
Tests of the DjangoUserStateClient backend.
diff --git a/lms/djangoapps/courseware/user_state_client.py b/lms/djangoapps/courseware/user_state_client.py
index 325c25462a1c..63dcd9da1476 100644
--- a/lms/djangoapps/courseware/user_state_client.py
+++ b/lms/djangoapps/courseware/user_state_client.py
@@ -9,13 +9,15 @@
from operator import attrgetter
from time import time
+from abc import abstractmethod
+from collections import namedtuple
+
from django.conf import settings
from django.contrib.auth.models import User # lint-amnesty, pylint: disable=imported-auth-user
from django.core.paginator import Paginator
from django.db import transaction
from django.db.utils import IntegrityError
from edx_django_utils import monitoring as monitoring_utils
-from edx_user_state_client.interface import XBlockUserState, XBlockUserStateClient
from xblock.fields import Scope
from lms.djangoapps.courseware.models import BaseStudentModuleHistory, StudentModule
@@ -29,6 +31,195 @@
log = logging.getLogger(__name__)
+class XBlockUserState(namedtuple('_XBlockUserState', ['username', 'block_key', 'state', 'updated', 'scope'])):
+ """
+ The current state of a single XBlock.
+
+ Arguments:
+ username: The username of the user that stored this state.
+ block_key: The key identifying the scoped state. Depending on the :class:`~xblock.fields.BlockScope` of
+
+ ``scope``, this may take one of several types:
+
+ * ``USAGE``: :class:`~opaque_keys.edx.keys.UsageKey`
+ * ``DEFINITION``: :class:`~opaque_keys.edx.keys.DefinitionKey`
+ * ``TYPE``: :class:`str`
+ * ``ALL``: ``None``
+ state: A dict mapping field names to the values of those fields for this XBlock.
+ updated: A :class:`datetime.datetime`. We guarantee that the fields
+ that were returned in "state" have not been changed since
+ this time (in UTC).
+ scope: A :class:`xblock.fields.Scope` identifying which XBlock scope this state is coming from.
+ """
+ __slots__ = ()
+
+ def __repr__(self):
+ return "{}{!r}".format( # pylint: disable=consider-using-f-string
+ self.__class__.__name__,
+ tuple(self)
+ )
+
+
+class XBlockUserStateClient():
+ """
+ First stab at an interface for accessing XBlock User State. This will have
+ use StudentModule as a backing store in the default case.
+
+ Scope/Goals:
+
+ 1. Mediate access to all student-specific state stored by XBlocks.
+ a. This includes "preferences" and "user_info" (i.e. UserScope.ONE)
+ b. This includes XBlock Asides.
+ c. This may later include user_state_summary (i.e. UserScope.ALL).
+ d. This may include group state in the future.
+ e. This may include other key types + UserScope.ONE (e.g. Definition)
+ 2. Assume network service semantics.
+ At some point, this will probably be calling out to an external service.
+ Even if it doesn't, we want to be able to implement circuit breakers, so
+ that a failure in StudentModule doesn't bring down the whole site.
+ This also implies that the client is running as a user, and whatever is
+ backing it is smart enough to do authorization checks.
+ 3. This does not yet cover export-related functionality.
+ """
+
+ class ServiceUnavailable(Exception):
+ """
+ This error is raised if the service backing this client is currently unavailable.
+ """
+
+ class PermissionDenied(Exception):
+ """
+ This error is raised if the caller is not allowed to access the requested data.
+ """
+
+ class DoesNotExist(Exception):
+ """
+ This error is raised if the caller has requested data that does not exist.
+ """
+
+ def get(self, username, block_key, scope=Scope.user_state, fields=None):
+ """
+ Retrieve the stored XBlock state for a single xblock usage.
+
+ Arguments:
+ username: The name of the user whose state should be retrieved
+ block_key: The key identifying which xblock state to load.
+ scope (Scope): The scope to load data from
+ fields: A list of field values to retrieve. If None, retrieve all stored fields.
+
+ Returns:
+ XBlockUserState: The current state of the block for the specified username and block_key.
+
+ Raises:
+ DoesNotExist if no entry is found.
+ """
+ try:
+ return next(self.get_many(username, [block_key], scope, fields=fields))
+ except StopIteration as exception:
+ raise self.DoesNotExist() from exception
+
+ def set(self, username, block_key, state, scope=Scope.user_state):
+ """
+ Set fields for a particular XBlock.
+
+ Arguments:
+ username: The name of the user whose state should be retrieved
+ block_key: The key identifying which xblock state to load.
+ state (dict): A dictionary mapping field names to values
+ scope (Scope): The scope to store data to
+ """
+ self.set_many(username, {block_key: state}, scope)
+
+ def delete(self, username, block_key, scope=Scope.user_state, fields=None):
+ """
+ Delete the stored XBlock state for a single xblock usage.
+
+ Arguments:
+ username: The name of the user whose state should be deleted
+ block_key: The key identifying which xblock state to delete.
+ scope (Scope): The scope to delete data from
+ fields: A list of fields to delete. If None, delete all stored fields.
+ """
+ return self.delete_many(username, [block_key], scope, fields=fields)
+
+ @abstractmethod
+ def get_many(self, username, block_keys, scope=Scope.user_state, fields=None):
+ """
+ Retrieve the stored XBlock state for a single xblock usage.
+
+ Arguments:
+ username: The name of the user whose state should be retrieved
+ block_keys: A list of keys identifying which xblock states to load.
+ scope (Scope): The scope to load data from
+ fields: A list of field values to retrieve. If None, retrieve all stored fields.
+
+ Yields:
+ XBlockUserState tuples for each specified key in block_keys.
+ field_state is a dict mapping field names to values.
+ """
+ raise NotImplementedError()
+
+ @abstractmethod
+ def set_many(self, username, block_keys_to_state, scope=Scope.user_state):
+ """
+ Set fields for a particular XBlock.
+
+ Arguments:
+ username: The name of the user whose state should be retrieved
+ block_keys_to_state (dict): A dict mapping keys to state dicts.
+ Each state dict maps field names to values. These state dicts
+ are overlaid over the stored state. To delete fields, use
+ :meth:`delete` or :meth:`delete_many`.
+ scope (Scope): The scope to load data from
+ """
+ raise NotImplementedError()
+
+ @abstractmethod
+ def delete_many(self, username, block_keys, scope=Scope.user_state, fields=None):
+ """
+ Delete the stored XBlock state for a many xblock usages.
+
+ Arguments:
+ username: The name of the user whose state should be deleted
+ block_key: The key identifying which xblock state to delete.
+ scope (Scope): The scope to delete data from
+ fields: A list of fields to delete. If None, delete all stored fields.
+ """
+ raise NotImplementedError()
+
+ def get_history(self, username, block_key, scope=Scope.user_state):
+ """
+ Retrieve history of state changes for a given block for a given
+ student. We don't guarantee that history for many blocks will be fast.
+
+ If the specified block doesn't exist, raise :class:`~DoesNotExist`.
+
+ Arguments:
+ username: The name of the user whose history should be retrieved.
+ block_key: The key identifying which xblock history to retrieve.
+ scope (Scope): The scope to load data from.
+
+ Yields:
+ XBlockUserState entries for each modification to the specified XBlock, from latest
+ to earliest.
+ """
+ raise NotImplementedError()
+
+ def iter_all_for_block(self, block_key, scope=Scope.user_state):
+ """
+ You get no ordering guarantees. If you're using this method, you should be running in an
+ async task.
+ """
+ raise NotImplementedError()
+
+ def iter_all_for_course(self, course_key, block_type=None, scope=Scope.user_state):
+ """
+ You get no ordering guarantees. If you're using this method, you should be running in an
+ async task.
+ """
+ raise NotImplementedError()
+
+
class DjangoXBlockUserStateClient(XBlockUserStateClient):
"""
An interface that uses the Django ORM StudentModule as a backend.
diff --git a/lms/djangoapps/discussion/rest_api/api.py b/lms/djangoapps/discussion/rest_api/api.py
index 4250be781555..2caa901d518a 100644
--- a/lms/djangoapps/discussion/rest_api/api.py
+++ b/lms/djangoapps/discussion/rest_api/api.py
@@ -37,7 +37,6 @@
from lms.djangoapps.course_blocks.api import get_course_blocks
from lms.djangoapps.courseware.courses import get_course_with_access
from lms.djangoapps.courseware.exceptions import CourseAccessRedirect
-from lms.djangoapps.discussion.rest_api.tasks import send_thread_created_notification
from lms.djangoapps.discussion.toggles import ENABLE_DISCUSSIONS_MFE, ENABLE_LEARNERS_TAB_IN_DISCUSSIONS_MFE
from lms.djangoapps.discussion.toggles_utils import reported_content_email_notification_enabled
from lms.djangoapps.discussion.views import is_privileged_user
@@ -129,7 +128,6 @@
get_usernames_for_course,
get_usernames_from_search_string,
is_posting_allowed,
- send_response_notifications,
set_attribute,
)
@@ -1469,8 +1467,6 @@ def create_thread(request, thread_data):
track_thread_created_event(request, course, cc_thread, actions_form.cleaned_data["following"],
from_mfe_sidebar)
- thread_id = cc_thread.attributes['id']
- send_thread_created_notification.apply_async(args=[thread_id, str(course.id), request.user.id])
return api_thread
@@ -1517,8 +1513,6 @@ def create_comment(request, comment_data):
track_comment_created_event(request, course, cc_comment, cc_thread["commentable_id"], followed=False,
from_mfe_sidebar=from_mfe_sidebar)
- send_response_notifications(thread=cc_thread, course=course, creator=request.user,
- parent_id=comment_data.get("parent_id"))
return api_comment
diff --git a/lms/djangoapps/discussion/rest_api/tasks.py b/lms/djangoapps/discussion/rest_api/tasks.py
index 81abe9892975..85de47286f97 100644
--- a/lms/djangoapps/discussion/rest_api/tasks.py
+++ b/lms/djangoapps/discussion/rest_api/tasks.py
@@ -28,3 +28,21 @@ def send_thread_created_notification(thread_id, course_key_str, user_id):
course = get_course_with_access(user, 'load', course_key, check_if_enrolled=True)
notification_sender = DiscussionNotificationSender(thread, course, user)
notification_sender.send_new_thread_created_notification()
+
+
+@shared_task
+@set_code_owner_attribute
+def send_response_notifications(thread_id, course_key_str, user_id, parent_id=None):
+ """
+ Send notifications to users who are subscribed to the thread.
+ """
+ course_key = CourseKey.from_string(course_key_str)
+ if not ENABLE_NOTIFICATIONS.is_enabled(course_key):
+ return
+ thread = Thread(id=thread_id).retrieve()
+ user = User.objects.get(id=user_id)
+ course = get_course_with_access(user, 'load', course_key, check_if_enrolled=True)
+ notification_sender = DiscussionNotificationSender(thread, course, user, parent_id)
+ notification_sender.send_new_comment_notification()
+ notification_sender.send_new_response_notification()
+ notification_sender.send_new_comment_on_response_notification()
diff --git a/lms/djangoapps/discussion/rest_api/tests/test_api.py b/lms/djangoapps/discussion/rest_api/tests/test_api.py
index e99f95b834e0..34e323c723e6 100644
--- a/lms/djangoapps/discussion/rest_api/tests/test_api.py
+++ b/lms/djangoapps/discussion/rest_api/tests/test_api.py
@@ -1853,10 +1853,7 @@ def setUp(self):
}
@mock.patch("eventtracking.tracker.emit")
- @mock.patch(
- 'lms.djangoapps.discussion.rest_api.tasks.send_thread_created_notification.apply_async'
- )
- def test_basic(self, mock_notification_task, mock_emit):
+ def test_basic(self, mock_emit):
cs_thread = make_minimal_cs_thread({
"id": "test_id",
"username": self.user.username,
@@ -1872,7 +1869,6 @@ def test_basic(self, mock_notification_task, mock_emit):
"read": True,
})
assert actual == expected
- mock_notification_task.assert_called_once()
assert parsed_body(httpretty.last_request()) == {
'course_id': [str(self.course.id)],
'commentable_id': ['test_topic'],
@@ -1915,10 +1911,7 @@ def test_basic_in_blackout_period(self):
self.assertEqual(assertion.exception.detail, "Discussions are in blackout period.")
@mock.patch("eventtracking.tracker.emit")
- @mock.patch(
- 'lms.djangoapps.discussion.rest_api.tasks.send_thread_created_notification.apply_async'
- )
- def test_basic_in_blackout_period_with_user_access(self, mock_notification_task, mock_emit):
+ def test_basic_in_blackout_period_with_user_access(self, mock_emit):
"""
Test case when course is in blackout period and user has special privileges.
"""
@@ -1958,7 +1951,6 @@ def test_basic_in_blackout_period_with_user_access(self, mock_notification_task,
],
})
assert actual == expected
- mock_notification_task.assert_called_once()
self.assertEqual(
parsed_body(httpretty.last_request()),
{
@@ -2042,10 +2034,7 @@ def test_title_truncation(self, mock_emit):
)
)
@ddt.unpack
- @mock.patch(
- 'lms.djangoapps.discussion.rest_api.tasks.send_thread_created_notification.apply_async'
- )
- def test_group_id(self, role_name, course_is_cohorted, topic_is_cohorted, data_group_state, mock_notification_task):
+ def test_group_id(self, role_name, course_is_cohorted, topic_is_cohorted, data_group_state):
"""
Tests whether the user has permission to create a thread with certain
group_id values.
@@ -2083,7 +2072,6 @@ def test_group_id(self, role_name, course_is_cohorted, topic_is_cohorted, data_g
try:
create_thread(self.request, data)
assert not expected_error
- mock_notification_task.assert_called_once()
actual_post_data = parsed_body(httpretty.last_request())
if data_group_state == "group_is_set":
assert actual_post_data['group_id'] == [str(data['group_id'])]
@@ -2095,26 +2083,19 @@ def test_group_id(self, role_name, course_is_cohorted, topic_is_cohorted, data_g
if not expected_error:
self.fail(f"Unexpected validation error: {ex}")
- @mock.patch(
- 'lms.djangoapps.discussion.rest_api.tasks.send_thread_created_notification.apply_async'
- )
- def test_following(self, mock_notification_task):
+ def test_following(self):
self.register_post_thread_response({"id": "test_id", "username": self.user.username})
self.register_subscription_response(self.user)
data = self.minimal_data.copy()
data["following"] = "True"
result = create_thread(self.request, data)
assert result['following'] is True
- mock_notification_task.assert_called_once()
cs_request = httpretty.last_request()
assert urlparse(cs_request.path).path == f"/api/v1/users/{self.user.id}/subscriptions" # lint-amnesty, pylint: disable=no-member
assert cs_request.method == 'POST'
assert parsed_body(cs_request) == {'source_type': ['thread'], 'source_id': ['test_id']}
- @mock.patch(
- 'lms.djangoapps.discussion.rest_api.tasks.send_thread_created_notification.apply_async'
- )
- def test_voted(self, mock_notification_task):
+ def test_voted(self):
self.register_post_thread_response({"id": "test_id", "username": self.user.username})
self.register_thread_votes_response("test_id")
data = self.minimal_data.copy()
@@ -2122,16 +2103,12 @@ def test_voted(self, mock_notification_task):
with self.assert_signal_sent(api, 'thread_voted', sender=None, user=self.user, exclude_args=('post',)):
result = create_thread(self.request, data)
assert result['voted'] is True
- mock_notification_task.assert_called_once()
cs_request = httpretty.last_request()
assert urlparse(cs_request.path).path == '/api/v1/threads/test_id/votes' # lint-amnesty, pylint: disable=no-member
assert cs_request.method == 'PUT'
assert parsed_body(cs_request) == {'user_id': [str(self.user.id)], 'value': ['up']}
- @mock.patch(
- 'lms.djangoapps.discussion.rest_api.tasks.send_thread_created_notification.apply_async'
- )
- def test_abuse_flagged(self, mock_notification_task):
+ def test_abuse_flagged(self):
self.register_post_thread_response({"id": "test_id", "username": self.user.username})
self.register_thread_flag_response("test_id")
data = self.minimal_data.copy()
@@ -2139,7 +2116,6 @@ def test_abuse_flagged(self, mock_notification_task):
result = create_thread(self.request, data)
assert result['abuse_flagged'] is True
cs_request = httpretty.last_request()
- mock_notification_task.assert_called_once()
assert urlparse(cs_request.path).path == '/api/v1/threads/test_id/abuse_flag' # lint-amnesty, pylint: disable=no-member
assert cs_request.method == 'PUT'
assert parsed_body(cs_request) == {'user_id': [str(self.user.id)]}
diff --git a/lms/djangoapps/discussion/rest_api/tests/test_tasks.py b/lms/djangoapps/discussion/rest_api/tests/test_tasks.py
index 7d689adc761c..e7bc03c0adcd 100644
--- a/lms/djangoapps/discussion/rest_api/tests/test_tasks.py
+++ b/lms/djangoapps/discussion/rest_api/tests/test_tasks.py
@@ -2,14 +2,16 @@
Test cases for tasks.py
"""
from unittest import mock
+from django.conf import settings
from edx_toggles.toggles.testutils import override_waffle_flag
+
import ddt
import httpretty
from common.djangoapps.student.models import CourseEnrollment
from common.djangoapps.student.tests.factories import StaffFactory, UserFactory
from lms.djangoapps.discussion.django_comment_client.tests.factories import RoleFactory
-from lms.djangoapps.discussion.rest_api.tasks import send_thread_created_notification
-from lms.djangoapps.discussion.rest_api.tests.utils import make_minimal_cs_thread
+from lms.djangoapps.discussion.rest_api.tasks import send_response_notifications, send_thread_created_notification
+from lms.djangoapps.discussion.rest_api.tests.utils import ThreadMock, make_minimal_cs_thread
from openedx.core.djangoapps.course_groups.models import CohortMembership, CourseCohortsSettings
from openedx.core.djangoapps.course_groups.tests.helpers import CohortFactory
from openedx.core.djangoapps.django_comment_common.models import (
@@ -27,6 +29,13 @@
from .test_views import DiscussionAPIViewTestMixin
+def _get_mfe_url(course_id, post_id):
+ """
+ get discussions mfe url to specific post.
+ """
+ return f"{settings.DISCUSSIONS_MICROFRONTEND_URL}/{str(course_id)}/posts/{post_id}"
+
+
@ddt.ddt
@httpretty.activate
@mock.patch.dict("django.conf.settings.FEATURES", {"ENABLE_DISCUSSION_SERVICE": True})
@@ -230,3 +239,224 @@ def test_notification_is_send_to_cohort_ids(self, cohort_text, notification_type
self.assertEqual(handler.call_count, 1)
user_ids_list = [user.id for user in audience]
self.assert_users_id_list(user_ids_list, handler.call_args[1]['notification_data'].user_ids)
+
+
+@override_waffle_flag(ENABLE_NOTIFICATIONS, active=True)
+class TestSendResponseNotifications(DiscussionAPIViewTestMixin, ModuleStoreTestCase):
+ """
+ Test for the send_response_notifications function
+ """
+
+ def setUp(self):
+ super().setUp()
+ httpretty.reset()
+ httpretty.enable()
+
+ self.course = CourseFactory.create()
+ self.user_1 = UserFactory.create()
+ CourseEnrollment.enroll(self.user_1, self.course.id)
+ self.user_2 = UserFactory.create()
+ CourseEnrollment.enroll(self.user_2, self.course.id)
+ self.user_3 = UserFactory.create()
+ CourseEnrollment.enroll(self.user_3, self.course.id)
+ self.thread = ThreadMock(thread_id=1, creator=self.user_1, title='test thread')
+ self.thread_2 = ThreadMock(thread_id=2, creator=self.user_2, title='test thread 2')
+ self.thread_3 = ThreadMock(thread_id=2, creator=self.user_1, title='test thread 3')
+ for thread in [self.thread, self.thread_2, self.thread_3]:
+ self.register_get_thread_response({
+ 'id': thread.id,
+ 'course_id': str(self.course.id),
+ 'topic_id': 'abc',
+ "user_id": thread.user_id,
+ "username": thread.username,
+ "thread_type": 'discussion',
+ "title": thread.title,
+ })
+
+ def test_basic(self):
+ """
+ Left empty intentionally. This test case is inherited from DiscussionAPIViewTestMixin
+ """
+
+ def test_not_authenticated(self):
+ """
+ Left empty intentionally. This test case is inherited from DiscussionAPIViewTestMixin
+ """
+
+ def test_send_notification_to_thread_creator(self):
+ """
+ Test that the notification is sent to the thread creator
+ """
+ handler = mock.Mock()
+ USER_NOTIFICATION_REQUESTED.connect(handler)
+
+ # Post the form or do what it takes to send the signal
+
+ send_response_notifications(self.thread.id, str(self.course.id), self.user_2.id, parent_id=None)
+ self.assertEqual(handler.call_count, 1)
+ args = handler.call_args[1]['notification_data']
+ self.assertEqual([int(user_id) for user_id in args.user_ids], [self.user_1.id])
+ self.assertEqual(args.notification_type, 'new_response')
+ expected_context = {
+ 'replier_name': self.user_2.username,
+ 'post_title': 'test thread',
+ 'course_name': self.course.display_name,
+ }
+ self.assertDictEqual(args.context, expected_context)
+ self.assertEqual(
+ args.content_url,
+ _get_mfe_url(self.course.id, self.thread.id)
+ )
+ self.assertEqual(args.app_name, 'discussion')
+
+ def test_send_notification_to_parent_threads(self):
+ """
+ Test that the notification signal is sent to the parent response creator and
+ parent thread creator, it checks signal is sent with correct arguments for both
+ types of notifications.
+ """
+ handler = mock.Mock()
+ USER_NOTIFICATION_REQUESTED.connect(handler)
+
+ self.register_get_comment_response({
+ 'id': self.thread_2.id,
+ 'thread_id': self.thread.id,
+ 'user_id': self.thread_2.user_id
+ })
+
+ send_response_notifications(self.thread.id, str(self.course.id), self.user_3.id, parent_id=self.thread_2.id)
+ # check if 2 call are made to the handler i.e. one for the response creator and one for the thread creator
+ self.assertEqual(handler.call_count, 2)
+
+ # check if the notification is sent to the thread creator
+ args_comment = handler.call_args_list[0][1]['notification_data']
+ args_comment_on_response = handler.call_args_list[1][1]['notification_data']
+ self.assertEqual([int(user_id) for user_id in args_comment.user_ids], [self.user_1.id])
+ self.assertEqual(args_comment.notification_type, 'new_comment')
+ expected_context = {
+ 'replier_name': self.user_3.username,
+ 'post_title': self.thread.title,
+ 'author_name': 'dummy\'s',
+ 'course_name': self.course.display_name,
+ }
+ self.assertDictEqual(args_comment.context, expected_context)
+ self.assertEqual(
+ args_comment.content_url,
+ _get_mfe_url(self.course.id, self.thread.id)
+ )
+ self.assertEqual(args_comment.app_name, 'discussion')
+
+ # check if the notification is sent to the parent response creator
+ self.assertEqual([int(user_id) for user_id in args_comment_on_response.user_ids], [self.user_2.id])
+ self.assertEqual(args_comment_on_response.notification_type, 'new_comment_on_response')
+ expected_context = {
+ 'replier_name': self.user_3.username,
+ 'post_title': self.thread.title,
+ 'course_name': self.course.display_name,
+ }
+ self.assertDictEqual(args_comment_on_response.context, expected_context)
+ self.assertEqual(
+ args_comment_on_response.content_url,
+ _get_mfe_url(self.course.id, self.thread.id)
+ )
+ self.assertEqual(args_comment_on_response.app_name, 'discussion')
+
+ def test_no_signal_on_creators_own_thread(self):
+ """
+ Makes sure that no signal is emitted if user creates response on
+ their own thread.
+ """
+ handler = mock.Mock()
+ USER_NOTIFICATION_REQUESTED.connect(handler)
+ send_response_notifications(self.thread.id, str(self.course.id), self.user_1.id, parent_id=None)
+ self.assertEqual(handler.call_count, 0)
+
+ def test_comment_creators_own_response(self):
+ """
+ Check incase post author and response auther is same only send
+ new comment signal , with your as author_name.
+ """
+ handler = mock.Mock()
+ USER_NOTIFICATION_REQUESTED.connect(handler)
+
+ self.register_get_comment_response({
+ 'id': self.thread_3.id,
+ 'thread_id': self.thread.id,
+ 'user_id': self.thread_3.user_id
+ })
+
+ send_response_notifications(self.thread.id, str(self.course.id), self.user_3.id, parent_id=self.thread_2.id)
+ # check if 1 call is made to the handler i.e. for the thread creator
+ self.assertEqual(handler.call_count, 1)
+
+ # check if the notification is sent to the thread creator
+ args_comment = handler.call_args_list[0][1]['notification_data']
+ self.assertEqual(args_comment.user_ids, [self.user_1.id])
+ self.assertEqual(args_comment.notification_type, 'new_comment')
+ expected_context = {
+ 'replier_name': self.user_3.username,
+ 'post_title': self.thread.title,
+ 'author_name': 'your',
+ 'course_name': self.course.display_name,
+ }
+ self.assertDictEqual(args_comment.context, expected_context)
+ self.assertEqual(
+ args_comment.content_url,
+ _get_mfe_url(self.course.id, self.thread.id)
+ )
+ self.assertEqual(args_comment.app_name, 'discussion')
+
+
+@override_waffle_flag(ENABLE_NOTIFICATIONS, active=True)
+class TestSendCommentNotification(DiscussionAPIViewTestMixin, ModuleStoreTestCase):
+ """
+ Test case to send new_comment notification
+ """
+ def setUp(self):
+ super().setUp()
+ httpretty.reset()
+ httpretty.enable()
+
+ self.course = CourseFactory.create()
+ self.user_1 = UserFactory.create()
+ CourseEnrollment.enroll(self.user_1, self.course.id)
+ self.user_2 = UserFactory.create()
+ CourseEnrollment.enroll(self.user_2, self.course.id)
+
+ def test_basic(self):
+ """
+ Left empty intentionally. This test case is inherited from DiscussionAPIViewTestMixin
+ """
+
+ def test_not_authenticated(self):
+ """
+ Left empty intentionally. This test case is inherited from DiscussionAPIViewTestMixin
+ """
+
+ def test_new_comment_notification(self):
+ """
+ Tests new comment notification generation
+ """
+ handler = mock.Mock()
+ USER_NOTIFICATION_REQUESTED.connect(handler)
+
+ thread = ThreadMock(thread_id=1, creator=self.user_1, title='test thread')
+ response = ThreadMock(thread_id=2, creator=self.user_2, title='test response')
+ self.register_get_thread_response({
+ 'id': thread.id,
+ 'course_id': str(self.course.id),
+ 'topic_id': 'abc',
+ "user_id": thread.user_id,
+ "username": thread.username,
+ "thread_type": 'discussion',
+ "title": thread.title,
+ })
+ self.register_get_comment_response({
+ 'id': response.id,
+ 'thread_id': thread.id,
+ 'user_id': response.user_id
+ })
+ send_response_notifications(thread.id, str(self.course.id), self.user_2.id, parent_id=response.id)
+ handler.assert_called_once()
+ context = handler.call_args[1]['notification_data'].context
+ self.assertEqual(context['author_name'], 'their')
diff --git a/lms/djangoapps/discussion/rest_api/tests/test_utils.py b/lms/djangoapps/discussion/rest_api/tests/test_utils.py
index b6c08c509417..a0e7790cba7b 100644
--- a/lms/djangoapps/discussion/rest_api/tests/test_utils.py
+++ b/lms/djangoapps/discussion/rest_api/tests/test_utils.py
@@ -3,16 +3,13 @@
"""
from datetime import datetime, timedelta
-from unittest.mock import Mock
import ddt
-from django.conf import settings
-from httpretty import httpretty
from pytz import UTC
import unittest
from common.djangoapps.student.roles import CourseStaffRole, CourseInstructorRole
from lms.djangoapps.discussion.django_comment_client.tests.utils import ForumsEnableMixin
-from lms.djangoapps.discussion.rest_api.tests.utils import CommentsServiceMockMixin, ThreadMock
+from lms.djangoapps.discussion.rest_api.tests.utils import CommentsServiceMockMixin
from openedx.core.djangoapps.discussions.models import PostingRestriction, DiscussionsConfiguration
from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase
from xmodule.modulestore.tests.factories import CourseFactory
@@ -26,9 +23,8 @@
get_moderator_users_list,
get_archived_topics,
remove_empty_sequentials,
- send_response_notifications, is_posting_allowed
+ is_posting_allowed
)
-from openedx_events.learning.signals import USER_NOTIFICATION_REQUESTED
class DiscussionAPIUtilsTestCase(ModuleStoreTestCase):
@@ -165,185 +161,6 @@ def test_remove_empty_sequentials(self):
self.assertEqual(result, expected_output)
-def _get_mfe_url(course_id, post_id):
- """
- get discussions mfe url to specific post.
- """
- return f"{settings.DISCUSSIONS_MICROFRONTEND_URL}/{str(course_id)}/posts/{post_id}"
-
-
-class TestSendResponseNotifications(ForumsEnableMixin, CommentsServiceMockMixin, ModuleStoreTestCase):
- """
- Test for the send_response_notifications function
- """
-
- def setUp(self):
- super().setUp()
- httpretty.reset()
- httpretty.enable()
-
- self.user_1 = UserFactory.create()
- self.user_2 = UserFactory.create()
- self.user_3 = UserFactory.create()
- self.thread = ThreadMock(thread_id=1, creator=self.user_1, title='test thread')
- self.thread_2 = ThreadMock(thread_id=2, creator=self.user_2, title='test thread 2')
- self.thread_3 = ThreadMock(thread_id=2, creator=self.user_1, title='test thread 3')
- self.course = CourseFactory.create()
-
- def test_send_notification_to_thread_creator(self):
- """
- Test that the notification is sent to the thread creator
- """
- handler = Mock()
- USER_NOTIFICATION_REQUESTED.connect(handler)
-
- # Post the form or do what it takes to send the signal
-
- send_response_notifications(self.thread, self.course, self.user_2, parent_id=None)
- self.assertEqual(handler.call_count, 1)
- args = handler.call_args[1]['notification_data']
- self.assertEqual([int(user_id) for user_id in args.user_ids], [self.user_1.id])
- self.assertEqual(args.notification_type, 'new_response')
- expected_context = {
- 'replier_name': self.user_2.username,
- 'post_title': 'test thread',
- 'course_name': self.course.display_name,
- }
- self.assertDictEqual(args.context, expected_context)
- self.assertEqual(
- args.content_url,
- _get_mfe_url(self.course.id, self.thread.id)
- )
- self.assertEqual(args.app_name, 'discussion')
-
- def test_send_notification_to_parent_threads(self):
- """
- Test that the notification signal is sent to the parent response creator and
- parent thread creator, it checks signal is sent with correct arguments for both
- types of notifications.
- """
- handler = Mock()
- USER_NOTIFICATION_REQUESTED.connect(handler)
-
- self.register_get_comment_response({
- 'id': self.thread_2.id,
- 'thread_id': self.thread.id,
- 'user_id': self.thread_2.user_id
- })
-
- send_response_notifications(self.thread, self.course, self.user_3, parent_id=self.thread_2.id)
- # check if 2 call are made to the handler i.e. one for the response creator and one for the thread creator
- self.assertEqual(handler.call_count, 2)
-
- # check if the notification is sent to the thread creator
- args_comment = handler.call_args_list[0][1]['notification_data']
- args_comment_on_response = handler.call_args_list[1][1]['notification_data']
- self.assertEqual([int(user_id) for user_id in args_comment.user_ids], [self.user_1.id])
- self.assertEqual(args_comment.notification_type, 'new_comment')
- expected_context = {
- 'replier_name': self.user_3.username,
- 'post_title': self.thread.title,
- 'author_name': 'dummy\'s',
- 'course_name': self.course.display_name,
- }
- self.assertDictEqual(args_comment.context, expected_context)
- self.assertEqual(
- args_comment.content_url,
- _get_mfe_url(self.course.id, self.thread.id)
- )
- self.assertEqual(args_comment.app_name, 'discussion')
-
- # check if the notification is sent to the parent response creator
- self.assertEqual([int(user_id) for user_id in args_comment_on_response.user_ids], [self.user_2.id])
- self.assertEqual(args_comment_on_response.notification_type, 'new_comment_on_response')
- expected_context = {
- 'replier_name': self.user_3.username,
- 'post_title': self.thread.title,
- 'course_name': self.course.display_name,
- }
- self.assertDictEqual(args_comment_on_response.context, expected_context)
- self.assertEqual(
- args_comment_on_response.content_url,
- _get_mfe_url(self.course.id, self.thread.id)
- )
- self.assertEqual(args_comment_on_response.app_name, 'discussion')
-
- def test_no_signal_on_creators_own_thread(self):
- """
- Makes sure that no signal is emitted if user creates response on
- their own thread.
- """
- handler = Mock()
- USER_NOTIFICATION_REQUESTED.connect(handler)
- send_response_notifications(self.thread, self.course, self.user_1, parent_id=None)
- self.assertEqual(handler.call_count, 0)
-
- def test_comment_creators_own_response(self):
- """
- Check incase post author and response auther is same only send
- new comment signal , with your as author_name.
- """
- handler = Mock()
- USER_NOTIFICATION_REQUESTED.connect(handler)
-
- self.register_get_comment_response({
- 'id': self.thread_3.id,
- 'thread_id': self.thread.id,
- 'user_id': self.thread_3.user_id
- })
-
- send_response_notifications(self.thread, self.course, self.user_3, parent_id=self.thread_2.id)
- # check if 1 call is made to the handler i.e. for the thread creator
- self.assertEqual(handler.call_count, 1)
-
- # check if the notification is sent to the thread creator
- args_comment = handler.call_args_list[0][1]['notification_data']
- self.assertEqual(args_comment.user_ids, [self.user_1.id])
- self.assertEqual(args_comment.notification_type, 'new_comment')
- expected_context = {
- 'replier_name': self.user_3.username,
- 'post_title': self.thread.title,
- 'author_name': 'your',
- 'course_name': self.course.display_name,
- }
- self.assertDictEqual(args_comment.context, expected_context)
- self.assertEqual(
- args_comment.content_url,
- _get_mfe_url(self.course.id, self.thread.id)
- )
- self.assertEqual(args_comment.app_name, 'discussion')
-
-
-class TestSendCommentNotification(ForumsEnableMixin, CommentsServiceMockMixin, ModuleStoreTestCase):
- """
- Test case to send new_comment notification
- """
- def setUp(self):
- super().setUp()
- httpretty.reset()
- httpretty.enable()
-
- self.course = CourseFactory.create()
- self.user_1 = UserFactory.create()
- self.user_2 = UserFactory.create()
-
- def test_new_comment_notification(self):
- handler = Mock()
- USER_NOTIFICATION_REQUESTED.connect(handler)
-
- thread = ThreadMock(thread_id=1, creator=self.user_1, title='test thread')
- response = ThreadMock(thread_id=2, creator=self.user_2, title='test response')
- self.register_get_comment_response({
- 'id': response.id,
- 'thread_id': 'abc',
- 'user_id': response.user_id
- })
- send_response_notifications(thread, self.course, self.user_2, parent_id=response.id)
- handler.assert_called_once()
- context = handler.call_args[1]['notification_data'].context
- self.assertEqual(context['author_name'], 'their')
-
-
@ddt.ddt
class TestBlackoutDates(ForumsEnableMixin, CommentsServiceMockMixin, ModuleStoreTestCase):
"""
diff --git a/lms/djangoapps/discussion/rest_api/tests/test_views.py b/lms/djangoapps/discussion/rest_api/tests/test_views.py
index 81f9e611fea1..0e303cc24092 100644
--- a/lms/djangoapps/discussion/rest_api/tests/test_views.py
+++ b/lms/djangoapps/discussion/rest_api/tests/test_views.py
@@ -1360,10 +1360,7 @@ def setUp(self):
super().setUp()
self.url = reverse("thread-list")
- @mock.patch(
- 'lms.djangoapps.discussion.rest_api.tasks.send_thread_created_notification.apply_async'
- )
- def test_basic(self, mock_notification_task):
+ def test_basic(self):
self.register_get_user_response(self.user)
cs_thread = make_minimal_cs_thread({
"id": "test_thread",
@@ -1384,7 +1381,6 @@ def test_basic(self, mock_notification_task):
content_type="application/json"
)
assert response.status_code == 200
- mock_notification_task.assert_called_once()
response_data = json.loads(response.content.decode('utf-8'))
assert response_data == self.expected_thread_data({
"read": True,
diff --git a/lms/djangoapps/discussion/rest_api/urls.py b/lms/djangoapps/discussion/rest_api/urls.py
index b861bd7848d6..13d06288d639 100644
--- a/lms/djangoapps/discussion/rest_api/urls.py
+++ b/lms/djangoapps/discussion/rest_api/urls.py
@@ -64,7 +64,7 @@
CourseView.as_view(),
name="discussion_course"
),
- path('v1/accounts/retire_forum', RetireUserView.as_view(), name="retire_discussion_user"),
+ re_path(r'^v1/accounts/retire_forum/?$', RetireUserView.as_view(), name="retire_discussion_user"),
path('v1/accounts/replace_username', ReplaceUsernamesView.as_view(), name="replace_discussion_username"),
re_path(
fr"^v1/course_topics/{settings.COURSE_ID_PATTERN}",
diff --git a/lms/djangoapps/discussion/rest_api/utils.py b/lms/djangoapps/discussion/rest_api/utils.py
index 8ec6eeb987ae..0b84cf2ac63b 100644
--- a/lms/djangoapps/discussion/rest_api/utils.py
+++ b/lms/djangoapps/discussion/rest_api/utils.py
@@ -13,6 +13,7 @@
from common.djangoapps.student.models import CourseEnrollment
from common.djangoapps.student.roles import CourseStaffRole, CourseInstructorRole
+from lms.djangoapps.discussion.django_comment_client.permissions import get_team
from lms.djangoapps.discussion.django_comment_client.utils import has_discussion_privileges
from openedx.core.djangoapps.course_groups.models import CourseCohortsSettings, CourseUserGroup
from openedx.core.djangoapps.discussions.models import DiscussionsConfiguration, PostingRestriction
@@ -370,16 +371,6 @@ def get_archived_topics(filtered_topic_ids: List[str], topics: List[Dict[str, st
return archived_topics
-def send_response_notifications(thread, course, creator, parent_id=None):
- """
- Send notifications to users who are subscribed to the thread.
- """
- notification_sender = DiscussionNotificationSender(thread, course, creator, parent_id)
- notification_sender.send_new_comment_notification()
- notification_sender.send_new_response_notification()
- notification_sender.send_new_comment_on_response_notification()
-
-
def is_discussion_cohorted(course_key_str):
"""
Returns if the discussion is divided by cohorts
@@ -460,8 +451,13 @@ def _create_cohort_course_audience(self):
all_topics = divided_inline_discussions + divided_course_wide_discussions
topic_divided = topic_id in all_topics or discussion_settings.always_divide_inline_discussions
+ # Team object from topic id
+ team = get_team(topic_id)
+
user_ids = []
- if discussion_cohorted and topic_divided and group_id is not None:
+ if team:
+ user_ids = team.users.all().values_list('id', flat=True)
+ elif discussion_cohorted and topic_divided and group_id is not None:
users_in_cohort = CourseUserGroup.objects.filter(
course_id=course_key_str, id=group_id
).values_list('users__id', flat=True)
diff --git a/lms/djangoapps/discussion/signals/handlers.py b/lms/djangoapps/discussion/signals/handlers.py
index eb084c866590..3e142aecd9c0 100644
--- a/lms/djangoapps/discussion/signals/handlers.py
+++ b/lms/djangoapps/discussion/signals/handlers.py
@@ -12,6 +12,7 @@
from xmodule.modulestore.django import SignalHandler
from lms.djangoapps.discussion import tasks
+from lms.djangoapps.discussion.rest_api.tasks import send_response_notifications, send_thread_created_notification
from openedx.core.djangoapps.django_comment_common import signals
from openedx.core.djangoapps.site_configuration.models import SiteConfiguration
from openedx.core.djangoapps.theming.helpers import get_current_site
@@ -133,3 +134,26 @@ def send_message(comment, site): # lint-amnesty, pylint: disable=missing-functi
def send_message_for_reported_content(user, post, site, sender): # lint-amnesty, pylint: disable=missing-function-docstring
context = create_message_context_for_reported_content(user, post, site, sender)
tasks.send_ace_message_for_reported_content.apply_async(args=[context], countdown=120)
+
+
+@receiver(signals.thread_created)
+def create_thread_created_notification(*args, **kwargs):
+ """
+ Creates a notification when new thread is created
+ """
+ user = kwargs['user']
+ post = kwargs['post']
+ send_thread_created_notification.apply_async(args=[post.id, post.attributes['course_id'], user.id])
+
+
+@receiver(signals.comment_created)
+def create_comment_created_notification(*args, **kwargs):
+ """
+ Creates a notification when new response or comment is created
+ """
+ user = kwargs['user']
+ comment = kwargs['post']
+ thread_id = comment.attributes['thread_id']
+ parent_id = comment.attributes['parent_id']
+ course_key_str = comment.attributes['course_id']
+ send_response_notifications.apply_async(args=[thread_id, course_key_str, user.id, parent_id])
diff --git a/lms/djangoapps/discussion/tests/test_signals.py b/lms/djangoapps/discussion/tests/test_signals.py
index a835a528daa7..d61b706292cf 100644
--- a/lms/djangoapps/discussion/tests/test_signals.py
+++ b/lms/djangoapps/discussion/tests/test_signals.py
@@ -21,8 +21,14 @@ class SendMessageHandlerTestCase(TestCase): # lint-amnesty, pylint: disable=mis
def setUp(self): # lint-amnesty, pylint: disable=super-method-not-called
self.sender = mock.Mock()
self.user = mock.Mock()
- self.post = mock.Mock()
- self.post.thread.course_id = 'course-v1:edX+DemoX+Demo_Course'
+ self.post = mock.MagicMock()
+ self.course_key_str = 'course-v1:edX+DemoX+Demo_Course'
+ self.post.thread.course_id = self.course_key_str
+ self.post.thread.attributes = {
+ 'thread_id': 'thread-id',
+ 'course_id': self.course_key_str,
+ 'parent_id': None
+ }
self.site = SiteFactory.create()
@@ -34,14 +40,16 @@ def test_comment_created_signal_sends_message(self, mock_send_message, mock_get_
site_config.site_values = enable_notifications_cfg
site_config.save()
mock_get_current_site.return_value = self.site
- signals.comment_created.send(sender=self.sender, user=self.user, post=self.post)
+ with mock.patch('lms.djangoapps.discussion.rest_api.tasks.send_response_notifications.apply_async'):
+ signals.comment_created.send(sender=self.sender, user=self.user, post=self.post)
mock_send_message.assert_called_once_with(self.post, mock_get_current_site.return_value)
@mock.patch('lms.djangoapps.discussion.signals.handlers.get_current_site', return_value=None)
@mock.patch('lms.djangoapps.discussion.signals.handlers.send_message')
def test_comment_created_signal_message_not_sent_without_site(self, mock_send_message, mock_get_current_site): # lint-amnesty, pylint: disable=unused-argument
- signals.comment_created.send(sender=self.sender, user=self.user, post=self.post)
+ with mock.patch('lms.djangoapps.discussion.rest_api.tasks.send_response_notifications.apply_async'):
+ signals.comment_created.send(sender=self.sender, user=self.user, post=self.post)
assert not mock_send_message.called
@@ -49,7 +57,8 @@ def test_comment_created_signal_message_not_sent_without_site(self, mock_send_me
@mock.patch('lms.djangoapps.discussion.signals.handlers.send_message')
def test_comment_created_signal_msg_not_sent_without_site_config(self, mock_send_message, mock_get_current_site):
mock_get_current_site.return_value = self.site
- signals.comment_created.send(sender=self.sender, user=self.user, post=self.post)
+ with mock.patch('lms.djangoapps.discussion.rest_api.tasks.send_response_notifications.apply_async'):
+ signals.comment_created.send(sender=self.sender, user=self.user, post=self.post)
assert not mock_send_message.called
@@ -63,7 +72,8 @@ def test_comment_created_signal_msg_not_sent_with_site_config_disabled(
site_config.site_values = enable_notifications_cfg
site_config.save()
mock_get_current_site.return_value = self.site
- signals.comment_created.send(sender=self.sender, user=self.user, post=self.post)
+ with mock.patch('lms.djangoapps.discussion.rest_api.tasks.send_response_notifications.apply_async'):
+ signals.comment_created.send(sender=self.sender, user=self.user, post=self.post)
assert not mock_send_message.called
diff --git a/lms/djangoapps/discussion/tests/test_tasks.py b/lms/djangoapps/discussion/tests/test_tasks.py
index 84363311bafe..f6cce4437546 100644
--- a/lms/djangoapps/discussion/tests/test_tasks.py
+++ b/lms/djangoapps/discussion/tests/test_tasks.py
@@ -126,6 +126,7 @@ def create_threads_and_comments(cls): # lint-amnesty, pylint: disable=missing-f
'parent_id': None,
'user_id': cls.comment_author.id,
'username': cls.comment_author.username,
+ 'course_id': str(cls.course.id),
}
cls.discussion_comment2 = {
'id': 'discussion-comment2',
@@ -134,7 +135,8 @@ def create_threads_and_comments(cls): # lint-amnesty, pylint: disable=missing-f
'thread_id': cls.discussion_thread['id'],
'parent_id': None,
'user_id': cls.comment_author.id,
- 'username': cls.comment_author.username
+ 'username': cls.comment_author.username,
+ 'course_id': str(cls.course.id)
}
cls.discussion_subcomment = {
'id': 'discussion-subcomment',
@@ -144,6 +146,7 @@ def create_threads_and_comments(cls): # lint-amnesty, pylint: disable=missing-f
'parent_id': cls.discussion_comment['id'],
'user_id': cls.comment_author.id,
'username': cls.comment_author.username,
+ 'course_id': str(cls.course.id),
}
cls.discussion_thread['children'] = [cls.discussion_comment, cls.discussion_comment2]
cls.discussion_comment['child_count'] = 1
@@ -176,6 +179,7 @@ def create_threads_and_comments(cls): # lint-amnesty, pylint: disable=missing-f
'parent_id': None,
'user_id': cls.comment_author.id,
'username': cls.comment_author.username,
+ 'course_id': str(cls.course.id),
}
cls.question_comment2 = {
'id': 'question-comment2',
@@ -184,7 +188,8 @@ def create_threads_and_comments(cls): # lint-amnesty, pylint: disable=missing-f
'thread_id': cls.question_thread['id'],
'parent_id': None,
'user_id': cls.comment_author.id,
- 'username': cls.comment_author.username
+ 'username': cls.comment_author.username,
+ 'course_id': str(cls.course.id),
}
cls.question_subcomment = {
'id': 'question-subcomment',
@@ -194,6 +199,7 @@ def create_threads_and_comments(cls): # lint-amnesty, pylint: disable=missing-f
'parent_id': cls.question_comment['id'],
'user_id': cls.comment_author.id,
'username': cls.comment_author.username,
+ 'course_id': str(cls.course.id),
}
cls.question_thread['endorsed_responses'] = [cls.question_comment]
cls.question_thread['non_endorsed_responses'] = [cls.question_comment2]
@@ -256,8 +262,9 @@ def test_send_discussion_email_notification(self, user_subscribed):
)
user = mock.Mock()
comment = cc.Comment.find(id=comment['id']).retrieve()
- with mock.patch('lms.djangoapps.discussion.signals.handlers.get_current_site', return_value=site):
- comment_created.send(sender=None, user=user, post=comment)
+ with mock.patch('lms.djangoapps.discussion.rest_api.tasks.send_response_notifications.apply_async'):
+ with mock.patch('lms.djangoapps.discussion.signals.handlers.get_current_site', return_value=site):
+ comment_created.send(sender=None, user=user, post=comment)
if user_subscribed:
expected_message_context = get_base_template_context(site)
@@ -310,7 +317,8 @@ def run_should_not_send_email_test(self, thread, comment_dict):
)
user = mock.Mock()
comment = cc.Comment.find(id=comment_dict['id']).retrieve()
- comment_created.send(sender=None, user=user, post=comment)
+ with mock.patch('lms.djangoapps.discussion.rest_api.tasks.send_response_notifications.apply_async'):
+ comment_created.send(sender=None, user=user, post=comment)
actual_result = _should_send_message({
'thread_author_id': self.thread_author.id,
diff --git a/lms/djangoapps/experiments/tests/test_views.py b/lms/djangoapps/experiments/tests/test_views.py
index ebd6bb74fb30..1378fbd9f036 100644
--- a/lms/djangoapps/experiments/tests/test_views.py
+++ b/lms/djangoapps/experiments/tests/test_views.py
@@ -6,6 +6,7 @@
import six.moves.urllib.parse
from datetime import timedelta
+import django
from django.conf import settings
from django.core.handlers.wsgi import WSGIRequest
from django.test.utils import override_settings
@@ -166,6 +167,13 @@ def test_update_permissions(self):
response = self.client.patch(url, data)
assert response.status_code == 404
+ def test_loads_valid_csrf_trusted_origins_list(self):
+ """checking CSRF_TRUSTED_ORIGINS here. in django4.2 they will require schemes"""
+ if django.VERSION[0] < 4: # for greater than django 3.2 use schemes.
+ assert settings.CSRF_TRUSTED_ORIGINS == ['.example.com']
+ else:
+ assert settings.CSRF_TRUSTED_ORIGINS == ['https://*.example.com']
+
def cross_domain_config(func):
"""Decorator for configuring a cross-domain request. """
diff --git a/lms/djangoapps/teams/tests/test_models.py b/lms/djangoapps/teams/tests/test_models.py
index 508377cfc423..02e238bf2a54 100644
--- a/lms/djangoapps/teams/tests/test_models.py
+++ b/lms/djangoapps/teams/tests/test_models.py
@@ -6,7 +6,7 @@
import itertools
from contextlib import contextmanager
from datetime import datetime
-from unittest.mock import Mock
+from unittest.mock import MagicMock, patch
import ddt
import pytest
@@ -270,7 +270,7 @@ def mock_comment(self, context=TEAM_DISCUSSION_CONTEXT, user=None):
"""Create a mock comment service object with the given context."""
if user is None:
user = self.user
- return Mock(
+ return MagicMock(
user_id=user.id,
commentable_id=self.DISCUSSION_TOPIC_ID,
context=context,
@@ -318,8 +318,10 @@ def test_signals(self, signal_name, user_should_update):
(user, should_update) = user_should_update
with self.assert_last_activity_updated(should_update):
user = getattr(self, user)
- signal = self.SIGNALS[signal_name]
- signal.send(sender=None, user=user, post=self.mock_comment())
+ with patch('lms.djangoapps.discussion.rest_api.tasks.send_response_notifications.apply_async'):
+ with patch('lms.djangoapps.discussion.rest_api.tasks.send_thread_created_notification.apply_async'):
+ signal = self.SIGNALS[signal_name]
+ signal.send(sender=None, user=user, post=self.mock_comment())
@ddt.data('thread_voted', 'comment_voted')
def test_vote_others_post(self, signal_name):
@@ -335,5 +337,7 @@ def test_signals_course_context(self, signal_name):
place in discussions outside of a team.
"""
with self.assert_last_activity_updated(False):
- signal = self.SIGNALS[signal_name]
- signal.send(sender=None, user=self.user, post=self.mock_comment(context='course'))
+ with patch('lms.djangoapps.discussion.rest_api.tasks.send_response_notifications.apply_async'):
+ with patch('lms.djangoapps.discussion.rest_api.tasks.send_thread_created_notification.apply_async'):
+ signal = self.SIGNALS[signal_name]
+ signal.send(sender=None, user=self.user, post=self.mock_comment(context='course'))
diff --git a/lms/envs/common.py b/lms/envs/common.py
index 4f9d9d17f440..130c485fea76 100644
--- a/lms/envs/common.py
+++ b/lms/envs/common.py
@@ -3230,7 +3230,7 @@ def _make_locale_paths(settings): # pylint: disable=missing-function-docstring
# Tagging
'openedx_tagging.core.tagging.apps.TaggingConfig',
- 'openedx.features.content_tagging',
+ 'openedx.core.djangoapps.content_tagging',
# Features
'openedx.features.calendar_sync',
diff --git a/lms/envs/devstack-experimental.yml b/lms/envs/devstack-experimental.yml
index 17dadd7e1aa6..5ab37724ae3c 100644
--- a/lms/envs/devstack-experimental.yml
+++ b/lms/envs/devstack-experimental.yml
@@ -614,7 +614,7 @@ VIDEO_IMAGE_MAX_AGE: 31536000
VIDEO_IMAGE_SETTINGS:
DIRECTORY_PREFIX: video-images/
STORAGE_KWARGS:
- location: edx/var/edxapp/media//
+ location: /edx/var/edxapp/media/
VIDEO_IMAGE_MAX_BYTES: 2097152
VIDEO_IMAGE_MIN_BYTES: 2048
BASE_URL: /media/
@@ -622,7 +622,7 @@ VIDEO_TRANSCRIPTS_MAX_AGE: 31536000
VIDEO_TRANSCRIPTS_SETTINGS:
DIRECTORY_PREFIX: video-transcripts/
STORAGE_KWARGS:
- location: edx/var/edxapp/media//
+ location: /edx/var/edxapp/media/
VIDEO_TRANSCRIPTS_MAX_BYTES: 3145728
BASE_URL: /media/
VIDEO_UPLOAD_PIPELINE:
diff --git a/lms/envs/devstack.py b/lms/envs/devstack.py
index 6e4498a20028..4eae239aabbe 100644
--- a/lms/envs/devstack.py
+++ b/lms/envs/devstack.py
@@ -165,10 +165,17 @@ def should_show_debug_toolbar(request): # lint-amnesty, pylint: disable=missing
########################## Courseware Search #######################
-FEATURES['ENABLE_COURSEWARE_SEARCH'] = False
+FEATURES['ENABLE_COURSEWARE_SEARCH'] = True
FEATURES['ENABLE_COURSEWARE_SEARCH_FOR_COURSE_STAFF'] = True
SEARCH_ENGINE = 'search.elastic.ElasticSearchEngine'
+ELASTIC_SEARCH_CONFIG = [
+ {
+ 'use_ssl': False,
+ 'host': 'edx.devstack.elasticsearch710',
+ 'port': 9200
+ }
+]
########################## Dashboard Search #######################
FEATURES['ENABLE_DASHBOARD_SEARCH'] = False
diff --git a/lms/envs/minimal.yml b/lms/envs/minimal.yml
index 0688b7c49c3a..4d5ccc7ec9db 100644
--- a/lms/envs/minimal.yml
+++ b/lms/envs/minimal.yml
@@ -28,7 +28,7 @@ MEDIA_ROOT: "/tmp/edx-platform/media/"
# DATA_DIR is overridden twice in ./lms/envs/common.py override it here temporarily until that's cleaned up and we
# can default to something dev friendly and have overrides in production.py for production friendly settings.
-DATA_DIR: "/tmp/edx-platform/data_dir"
+DATA_DIR: "/tmp/edx-platform/data_dir/"
# For just the CMS
LMS_ROOT_URL: "http://localhost"
diff --git a/lms/envs/production.py b/lms/envs/production.py
index 48554b9d097c..0924c85e1ef9 100644
--- a/lms/envs/production.py
+++ b/lms/envs/production.py
@@ -23,6 +23,7 @@
import yaml
from corsheaders.defaults import default_headers as corsheaders_default_headers
+import django
from django.core.exceptions import ImproperlyConfigured
from edx_django_utils.plugins import add_plugins
from path import Path as path
@@ -146,8 +147,9 @@ def get_env_setting(setting):
PLATFORM_NAME = ENV_TOKENS.get('PLATFORM_NAME') or PLATFORM_NAME
PLATFORM_DESCRIPTION = ENV_TOKENS.get('PLATFORM_DESCRIPTION') or PLATFORM_DESCRIPTION
+DATA_DIR = path(ENV_TOKENS.get('DATA_DIR', DATA_DIR))
CC_MERCHANT_NAME = ENV_TOKENS.get('CC_MERCHANT_NAME', PLATFORM_NAME)
-EMAIL_FILE_PATH = ENV_TOKENS.get('EMAIL_FILE_PATH', None)
+EMAIL_FILE_PATH = ENV_TOKENS.get('EMAIL_FILE_PATH', DATA_DIR / "emails" / "lms")
EMAIL_HOST = ENV_TOKENS.get('EMAIL_HOST', 'localhost') # django default is localhost
EMAIL_PORT = ENV_TOKENS.get('EMAIL_PORT', 25) # django default is 25
EMAIL_USE_TLS = ENV_TOKENS.get('EMAIL_USE_TLS', False) # django default is False
@@ -317,7 +319,6 @@ def get_env_setting(setting):
local_loglevel = ENV_TOKENS.get('LOCAL_LOGLEVEL', 'INFO')
LOG_DIR = ENV_TOKENS.get('LOG_DIR', LOG_DIR)
-DATA_DIR = path(ENV_TOKENS.get('DATA_DIR', DATA_DIR))
LOGGING = get_logger_config(LOG_DIR,
logging_env=ENV_TOKENS.get('LOGGING_ENV', LOGGING_ENV),
@@ -366,6 +367,10 @@ def get_env_setting(setting):
# Determines which origins are trusted for unsafe requests eg. POST requests.
CSRF_TRUSTED_ORIGINS = ENV_TOKENS.get('CSRF_TRUSTED_ORIGINS', [])
+# values are already updated above with default CSRF_TRUSTED_ORIGINS values but in
+# case of new django version these values will override.
+if django.VERSION[0] >= 4: # for greater than django 3.2 use schemes.
+ CSRF_TRUSTED_ORIGINS = ENV_TOKENS.get('CSRF_TRUSTED_ORIGINS_WITH_SCHEME', [])
############# CORS headers for cross-domain requests #################
@@ -472,6 +477,7 @@ def get_env_setting(setting):
else:
DEFAULT_FILE_STORAGE = 'django.core.files.storage.FileSystemStorage'
+
# If there is a database called 'read_replica', you can use the use_read_replica_if_available
# function in util/query.py, which is useful for very large database reads
DATABASES = AUTH_TOKENS.get('DATABASES', DATABASES)
diff --git a/lms/envs/test.py b/lms/envs/test.py
index 284ebc915d47..32352c849837 100644
--- a/lms/envs/test.py
+++ b/lms/envs/test.py
@@ -18,6 +18,7 @@
from uuid import uuid4
import openid.oidutil
+import django
from django.utils.translation import gettext_lazy
from edx_django_utils.plugins import add_plugins
from path import Path as path
@@ -677,3 +678,10 @@
SUBSCRIPTIONS_MANAGE_SUBSCRIPTION_URL = None
SUBSCRIPTIONS_MINIMUM_PRICE = '$39'
SUBSCRIPTIONS_TRIAL_LENGTH = 7
+CSRF_TRUSTED_ORIGINS = ['.example.com']
+CSRF_TRUSTED_ORIGINS_WITH_SCHEME = ['https://*.example.com']
+
+# values are already updated above with default CSRF_TRUSTED_ORIGINS values but in
+# case of new django version these values will override.
+if django.VERSION[0] >= 4: # for greater than django 3.2 use with schemes.
+ CSRF_TRUSTED_ORIGINS = CSRF_TRUSTED_ORIGINS_WITH_SCHEME
diff --git a/lms/static/js/i18n/ar/djangojs.js b/lms/static/js/i18n/ar/djangojs.js
index e7c5aae5ceb9..12dc71be061a 100644
--- a/lms/static/js/i18n/ar/djangojs.js
+++ b/lms/static/js/i18n/ar/djangojs.js
@@ -1903,7 +1903,6 @@
"This learner will be removed from the team,allowing another learner to take the available spot.": "\u0633\u064a\u062a\u0645 \u0627\u0633\u062a\u0628\u0639\u0627\u062f \u0647\u0630\u0627 \u0627\u0644\u0645\u062a\u0639\u0644\u0645 \u0645\u0646 \u0627\u0644\u0641\u0631\u064a\u0642\u060c \u0645\u0645\u0627 \u064a\u0633\u0645\u062d \u0644\u0645\u062a\u0639\u0644\u0645 \u0622\u062e\u0631 \u0628\u0623\u062e\u0630 \u0627\u0644\u0645\u0643\u0627\u0646 \u0627\u0644\u0645\u062a\u0627\u062d.",
"This link will open in a modal window": "\u0633\u064a\u0641\u062a\u062d \u0647\u0630\u0627 \u0627\u0644\u0631\u0627\u0628\u0637 \u0641\u064a \u0646\u0627\u0641\u0630\u0629 \u0645\u0646\u0628\u062b\u0642\u0629 \u062c\u062f\u064a\u062f\u0629.",
"This link will open in a new browser window/tab": "\u0633\u064a\u0641\u062a\u062d \u0647\u0630\u0627 \u0627\u0644\u0631\u0627\u0628\u0637 \u0641\u064a \u0646\u0627\u0641\u0630\u0629 \u0645\u062a\u0635\u0641\u0651\u062d \u062c\u062f\u064a\u062f\u0629/\u062a\u0628\u0648\u064a\u0628\u0629 \u062c\u062f\u064a\u062f\u0629",
- "This may be happening because of an error with our server or your internet connection. Try refreshing the page or making sure you are online.": "\u062a\u0648\u062c\u062f \u0645\u0634\u0643\u0644\u0629 \u0641\u064a \u0627\u0644\u062e\u0627\u062f\u0645 \u0623\u0648 \u0641\u064a \u0627\u0644\u0627\u062a\u0635\u0627\u0644 \u0628\u0627\u0644\u0634\u0628\u0643\u0629\u060c \u064a\u0631\u062c\u0649 \u062a\u062d\u062f\u064a\u062b \u0627\u0644\u0635\u0641\u062d\u0629 \u0623\u0648 \u0627\u0644\u062a\u0623\u0643\u062f \u0645\u0646 \u0627\u0644\u0627\u062a\u0635\u0627\u0644 \u0628\u0627\u0644\u0634\u0628\u0643\u0629.",
"This page contains information about orders that you have placed with {platform_name}.": "\u062a\u062d\u062a\u0648\u064a \u0647\u0630\u0647 \u0627\u0644\u0635\u0641\u062d\u0629 \u0639\u0644\u0649 \u0645\u0639\u0644\u0648\u0645\u0627\u062a \u0639\u0646 \u0627\u0644\u0637\u0644\u0628\u064a\u0627\u062a \u0627\u0644\u062a\u064a \u0642\u0645\u062a \u0628\u0647\u0627 \u0639\u0646\u062f {platform_name}.",
"This post could not be closed. Refresh the page and try again.": "\u062a\u0639\u0630\u0631 \u0625\u063a\u0644\u0627\u0642 \u0647\u0630\u0627 \u0627\u0644\u0645\u0646\u0634\u0648\u0631\u060c \u0641\u0636\u0644\u064b\u0627 \u0642\u0645 \u0628\u062a\u062d\u062f\u064a\u062b \u0627\u0644\u0635\u0641\u062d\u0629 \u0648\u0625\u0639\u0627\u062f\u0629 \u0627\u0644\u0645\u062d\u0627\u0648\u0644\u0629.",
"This post could not be flagged for abuse. Refresh the page and try again.": "\u0644\u0627 \u064a\u0645\u0643\u0646 \u0627\u0644\u0625\u0628\u0644\u0627\u063a \u0639\u0646 \u0627\u0633\u0627\u0621\u0629 \u0641\u064a \u0647\u0630\u0627 \u0627\u0644\u0645\u0646\u0634\u0648\u0631. \u0642\u0645 \u0628\u062a\u062d\u062f\u064a\u062b \u0627\u0644\u0635\u0641\u062d\u0629 \u0648\u062d\u0627\u0648\u0644 \u0645\u0631\u0629 \u0623\u062e\u0631\u0649.",
@@ -1999,7 +1998,6 @@
"Unable to load": "\u062a\u0639\u0630\u0651\u0631 \u0625\u062c\u0631\u0627\u0621 \u0627\u0644\u062a\u062d\u0645\u064a\u0644.",
"Unable to submit application": "\u0646\u0639\u062a\u0630\u0651\u0631 \u0644\u062a\u0639\u0630\u0651\u0631 \u062a\u0642\u062f\u064a\u0645 \u0627\u0644\u0637\u0644\u0628",
"Unable to submit request to generate report.": "\u062a\u0639\u0630\u0631 \u0625\u0631\u0633\u0627\u0644 \u0637\u0644\u0628 \u0644\u0625\u0646\u0634\u0627\u0621 \u0627\u0644\u062a\u0642\u0631\u064a\u0631.",
- "Unable to update settings": "\u062a\u0639\u0630\u0631 \u062a\u062d\u062f\u064a\u062b \u0627\u0644\u0625\u0639\u062f\u0627\u062f\u0627\u062a",
"Underline": "\u062e\u0637 \u062a\u062d\u062a \u0627\u0644\u0646\u0635",
"Undo": "\u062a\u0631\u0627\u062c\u064f\u0639",
"Undo (Ctrl+Z)": "\u0625\u0644\u063a\u0627\u0621 (Ctrl+Z)",
diff --git a/lms/static/js/i18n/de-de/djangojs.js b/lms/static/js/i18n/de-de/djangojs.js
index 783bf8d0469d..24637b410460 100644
--- a/lms/static/js/i18n/de-de/djangojs.js
+++ b/lms/static/js/i18n/de-de/djangojs.js
@@ -1084,7 +1084,6 @@
"Loading more threads": "Lade weitere Diskussionsstr\u00e4nge",
"Loading posts list": "Lade Beitrags\u00fcbersicht",
"Loading your courses": "Lade ihren Kurs",
- "Loading...": "Lade...",
"Location": "Ort",
"Location in Course": "Position im Kurs",
"Lock this asset": "Objekt sperren",
@@ -1517,7 +1516,6 @@
"Select the course-wide discussion topics that you want to divide.": "W\u00e4hlen Sie die kursweiten Diskussionsthemen aus, die Sie aufteilen m\u00f6chten.",
"Select the time zone for displaying course dates. If you do not specify a time zone, course dates, including assignment deadlines, will be displayed in your browser's local time zone.": "W\u00e4hlen Sie die Zeitzone des angebotenen Kurses aus. Wenn Sie keine bestimmte Zeitzone ausw\u00e4hlen, werden Kursdaten, inklusive Abgabetermine f\u00fcr Aufgaben, in der lokalen Zeit ihres Browsers dargestellt.",
"Select turnaround": "Wendepunkt ausw\u00e4hlen",
- "Selected blocks": "Ausgew\u00e4hlte Bl\u00f6cke",
"Selected tab": "Ausgew\u00e4hlter Tab",
"Self": "Selbst",
"Send to:": "Senden an:",
@@ -1851,7 +1849,6 @@
"This learner will be removed from the team,allowing another learner to take the available spot.": "Dieser Lernende wird aus dem Team entfernt, so dass ein anderer Lernender den verf\u00fcgbaren Platz einnehmen kann. ",
"This link will open in a modal window": "Dieser Link wird in einem Dialogfenster ge\u00f6ffnet",
"This link will open in a new browser window/tab": "Dieser Link wird in einem neuen Browserfenster/Reiter ge\u00f6ffnet",
- "This may be happening because of an error with our server or your internet connection. Try refreshing the page or making sure you are online.": "Dieses Problem wurde durch einen Fehler auf unserem Server oder mit Ihrer Internetverbindung verursacht. Versuchen Sie die Seite neu zu laden und/oder pr\u00fcfen Sie ihre Internetverbindung",
"This page contains information about orders that you have placed with {platform_name}.": "Diese Seite beinhaltet alle Informationen zu Ihren Bestellungen, welche Sie auf der {platform_name} get\u00e4tigt haben.",
"This post could not be closed. Refresh the page and try again.": "Dieser Beitrag konnte nicht geschlossen werden. Aktualisieren Sie die Seite und versuchen Sie es erneut.",
"This post could not be flagged for abuse. Refresh the page and try again.": "Dieser Beitrag konnte nicht als missbr\u00e4uchlich gekennzeichnet werden. Aktualisieren Sie die Seite und versuchen Sie es erneut.",
@@ -1946,7 +1943,6 @@
"Unable to load": "Laden nicht m\u00f6glich",
"Unable to submit application": "Antrag kann nicht gestellt werden",
"Unable to submit request to generate report.": "Anfrage zur Erstellung eines Berichts nicht m\u00f6glich.",
- "Unable to update settings": "Einstellungen aktualisieren nicht m\u00f6glich",
"Underline": "Unterstrich",
"Undo": "Undo",
"Undo (Ctrl+Z)": "R\u00fcckg\u00e4ngig (STRG+Z)",
diff --git a/lms/static/js/i18n/eo/djangojs.js b/lms/static/js/i18n/eo/djangojs.js
index f9ba7aa9d95c..5ef96bc3e679 100644
--- a/lms/static/js/i18n/eo/djangojs.js
+++ b/lms/static/js/i18n/eo/djangojs.js
@@ -616,6 +616,7 @@
"Discussion topics in the course are not divided.": "D\u00efs\u00e7\u00fcss\u00ef\u00f6n t\u00f6p\u00ef\u00e7s \u00efn th\u00e9 \u00e7\u00f6\u00fcrs\u00e9 \u00e4r\u00e9 n\u00f6t d\u00efv\u00efd\u00e9d. \u2c60'\u03c3\u044f\u0454\u043c \u03b9\u03c1\u0455\u03c5\u043c \u2202\u03c3\u0142\u03c3\u044f \u0455\u03b9\u0442 \u03b1\u043c\u0454\u0442, \u00a2\u03c3\u03b7\u0455\u0454\u00a2\u0442\u0454\u0442\u03c5\u044f \u03b1#",
"Discussions are unified; all learners interact with posts from other learners, regardless of the group they are in.": "D\u00efs\u00e7\u00fcss\u00ef\u00f6ns \u00e4r\u00e9 \u00fcn\u00eff\u00ef\u00e9d; \u00e4ll l\u00e9\u00e4rn\u00e9rs \u00efnt\u00e9r\u00e4\u00e7t w\u00efth p\u00f6sts fr\u00f6m \u00f6th\u00e9r l\u00e9\u00e4rn\u00e9rs, r\u00e9g\u00e4rdl\u00e9ss \u00f6f th\u00e9 gr\u00f6\u00fcp th\u00e9\u00fd \u00e4r\u00e9 \u00efn. \u2c60'\u03c3\u044f\u0454\u043c \u03b9\u03c1\u0455\u03c5\u043c \u2202\u03c3\u0142#",
"Discussions enabled": "D\u00efs\u00e7\u00fcss\u00ef\u00f6ns \u00e9n\u00e4\u00dfl\u00e9d \u2c60'\u03c3\u044f\u0454\u043c \u03b9\u03c1\u0455\u03c5\u043c \u2202\u03c3\u0142\u03c3\u044f \u0455\u03b9\u0442 \u03b1\u043c\u0454\u0442,#",
+ "Dismiss": "D\u00efsm\u00efss \u2c60'\u03c3\u044f\u0454\u043c \u03b9\u03c1\u0455\u03c5\u043c #",
"Display Name": "D\u00efspl\u00e4\u00fd N\u00e4m\u00e9 \u2c60'\u03c3\u044f\u0454\u043c \u03b9\u03c1\u0455\u03c5\u043c \u2202\u03c3\u0142\u03c3\u044f \u0455#",
"Div": "D\u00efv \u2c60'\u03c3\u044f\u0454\u043c#",
"Divide the selected content-specific discussion topics": "D\u00efv\u00efd\u00e9 th\u00e9 s\u00e9l\u00e9\u00e7t\u00e9d \u00e7\u00f6nt\u00e9nt-sp\u00e9\u00e7\u00eff\u00ef\u00e7 d\u00efs\u00e7\u00fcss\u00ef\u00f6n t\u00f6p\u00ef\u00e7s \u2c60'\u03c3\u044f\u0454\u043c \u03b9\u03c1\u0455\u03c5\u043c \u2202\u03c3\u0142\u03c3\u044f \u0455\u03b9\u0442 \u03b1\u043c\u0454\u0442, \u00a2\u03c3\u03b7\u0455\u0454\u00a2\u0442\u0454\u0442\u03c5\u044f \u03b1#",
@@ -1088,7 +1089,6 @@
"Loading more threads": "L\u00f6\u00e4d\u00efng m\u00f6r\u00e9 thr\u00e9\u00e4ds \u2c60'\u03c3\u044f\u0454\u043c \u03b9\u03c1\u0455\u03c5\u043c \u2202\u03c3\u0142\u03c3\u044f \u0455\u03b9\u0442 \u03b1\u043c\u0454\u0442, #",
"Loading posts list": "L\u00f6\u00e4d\u00efng p\u00f6sts l\u00efst \u2c60'\u03c3\u044f\u0454\u043c \u03b9\u03c1\u0455\u03c5\u043c \u2202\u03c3\u0142\u03c3\u044f \u0455\u03b9\u0442 \u03b1\u043c\u0454\u0442#",
"Loading your courses": "L\u00f6\u00e4d\u00efng \u00fd\u00f6\u00fcr \u00e7\u00f6\u00fcrs\u00e9s \u2c60'\u03c3\u044f\u0454\u043c \u03b9\u03c1\u0455\u03c5\u043c \u2202\u03c3\u0142\u03c3\u044f \u0455\u03b9\u0442 \u03b1\u043c\u0454\u0442, #",
- "Loading...": "L\u00f6\u00e4d\u00efng... \u2c60'\u03c3\u044f\u0454\u043c \u03b9\u03c1\u0455\u03c5\u043c \u2202\u03c3\u0142\u03c3#",
"Location": "L\u00f6\u00e7\u00e4t\u00ef\u00f6n \u2c60'\u03c3\u044f\u0454\u043c \u03b9\u03c1\u0455\u03c5\u043c \u2202#",
"Location in Course": "L\u00f6\u00e7\u00e4t\u00ef\u00f6n \u00efn \u00c7\u00f6\u00fcrs\u00e9 \u2c60'\u03c3\u044f\u0454\u043c \u03b9\u03c1\u0455\u03c5\u043c \u2202\u03c3\u0142\u03c3\u044f \u0455\u03b9\u0442 \u03b1\u043c\u0454\u0442#",
"Lock this asset": "L\u00f6\u00e7k th\u00efs \u00e4ss\u00e9t \u2c60'\u03c3\u044f\u0454\u043c \u03b9\u03c1\u0455\u03c5\u043c \u2202\u03c3\u0142\u03c3\u044f \u0455\u03b9\u0442 \u03b1#",
@@ -1166,7 +1166,7 @@
"New Password": "N\u00e9w P\u00e4ssw\u00f6rd \u2c60'\u03c3\u044f\u0454\u043c \u03b9\u03c1\u0455\u03c5\u043c \u2202\u03c3\u0142\u03c3\u044f \u0455#",
"New document": "N\u00e9w d\u00f6\u00e7\u00fcm\u00e9nt \u2c60'\u03c3\u044f\u0454\u043c \u03b9\u03c1\u0455\u03c5\u043c \u2202\u03c3\u0142\u03c3\u044f \u0455#",
"New enrollment mode:": "N\u00e9w \u00e9nr\u00f6llm\u00e9nt m\u00f6d\u00e9: \u2c60'\u03c3\u044f\u0454\u043c \u03b9\u03c1\u0455\u03c5\u043c \u2202\u03c3\u0142\u03c3\u044f \u0455\u03b9\u0442 \u03b1\u043c\u0454\u0442, #",
- "New files were added to this course's Files & Uploads": "N\u00e9w f\u00efl\u00e9s w\u00e9r\u00e9 \u00e4dd\u00e9d t\u00f6 th\u00efs \u00e7\u00f6\u00fcrs\u00e9's F\u00efl\u00e9s & \u00dbpl\u00f6\u00e4ds \u2c60'\u03c3\u044f\u0454\u043c \u03b9\u03c1\u0455\u03c5\u043c \u2202\u03c3\u0142\u03c3\u044f \u0455\u03b9\u0442 \u03b1\u043c\u0454\u0442, \u00a2\u03c3\u03b7\u0455\u0454\u00a2\u0442\u0454\u0442\u03c5\u044f \u03b1#",
+ "New file(s) added to Files & Uploads.": "N\u00e9w f\u00efl\u00e9(s) \u00e4dd\u00e9d t\u00f6 F\u00efl\u00e9s & \u00dbpl\u00f6\u00e4ds. \u2c60'\u03c3\u044f\u0454\u043c \u03b9\u03c1\u0455\u03c5\u043c \u2202\u03c3\u0142\u03c3\u044f \u0455\u03b9\u0442 \u03b1\u043c\u0454\u0442, \u00a2\u03c3\u03b7\u0455\u0454\u00a2\u0442\u0454\u0442\u03c5#",
"New window": "N\u00e9w w\u00efnd\u00f6w \u2c60'\u03c3\u044f\u0454\u043c \u03b9\u03c1\u0455\u03c5\u043c \u2202\u03c3\u0142\u03c3#",
"New {component_type}": "N\u00e9w {component_type} \u2c60'\u03c3\u044f\u0454\u043c \u03b9\u03c1\u0455\u03c5\u043c #",
"Next": "N\u00e9xt \u2c60'\u03c3\u044f\u0454\u043c \u03b9#",
@@ -1558,7 +1558,6 @@
"Select the course-wide discussion topics that you want to divide.": "S\u00e9l\u00e9\u00e7t th\u00e9 \u00e7\u00f6\u00fcrs\u00e9-w\u00efd\u00e9 d\u00efs\u00e7\u00fcss\u00ef\u00f6n t\u00f6p\u00ef\u00e7s th\u00e4t \u00fd\u00f6\u00fc w\u00e4nt t\u00f6 d\u00efv\u00efd\u00e9. \u2c60'\u03c3\u044f\u0454\u043c \u03b9\u03c1\u0455\u03c5\u043c \u2202\u03c3\u0142\u03c3\u044f \u0455\u03b9\u0442 \u03b1\u043c\u0454\u0442, \u00a2\u03c3\u03b7\u0455\u0454\u00a2\u0442\u0454\u0442\u03c5\u044f \u03b1#",
"Select the time zone for displaying course dates. If you do not specify a time zone, course dates, including assignment deadlines, will be displayed in your browser's local time zone.": "S\u00e9l\u00e9\u00e7t th\u00e9 t\u00efm\u00e9 z\u00f6n\u00e9 f\u00f6r d\u00efspl\u00e4\u00fd\u00efng \u00e7\u00f6\u00fcrs\u00e9 d\u00e4t\u00e9s. \u00ccf \u00fd\u00f6\u00fc d\u00f6 n\u00f6t sp\u00e9\u00e7\u00eff\u00fd \u00e4 t\u00efm\u00e9 z\u00f6n\u00e9, \u00e7\u00f6\u00fcrs\u00e9 d\u00e4t\u00e9s, \u00efn\u00e7l\u00fcd\u00efng \u00e4ss\u00efgnm\u00e9nt d\u00e9\u00e4dl\u00efn\u00e9s, w\u00efll \u00df\u00e9 d\u00efspl\u00e4\u00fd\u00e9d \u00efn \u00fd\u00f6\u00fcr \u00dfr\u00f6ws\u00e9r's l\u00f6\u00e7\u00e4l t\u00efm\u00e9 z\u00f6n\u00e9. \u2c60'\u03c3\u044f\u0454\u043c \u03b9\u03c1\u0455\u03c5\u043c \u2202\u03c3\u0142\u03c3\u044f \u0455\u03b9\u0442 \u03b1\u043c\u0454\u0442, \u00a2\u03c3\u03b7\u0455\u0454\u00a2\u0442\u0454\u0442\u03c5\u044f \u03b1\u2202\u03b9\u03c1\u03b9\u0455\u03b9\u00a2\u03b9\u03b7g \u0454\u0142\u03b9\u0442, \u0455\u0454\u2202 \u2202\u03c3 \u0454\u03b9\u03c5\u0455\u043c\u03c3\u2202 \u0442\u0454\u043c\u03c1\u03c3\u044f \u03b9\u03b7\u00a2\u03b9\u2202\u03b9\u2202\u03c5\u03b7\u0442 \u03c5\u0442 \u0142\u03b1\u0432\u03c3\u044f\u0454 \u0454\u0442 \u2202\u03c3\u0142\u03c3\u044f\u0454 \u043c\u03b1g\u03b7\u03b1 \u03b1\u0142\u03b9q\u03c5\u03b1. \u03c5\u0442 \u0454\u03b7\u03b9\u043c \u03b1\u2202 \u043c\u03b9\u03b7\u03b9\u043c \u03bd\u0454\u03b7\u03b9\u03b1\u043c, q\u03c5\u03b9\u0455 \u03b7\u03c3\u0455\u0442\u044f\u03c5\u2202 \u0454\u03c7\u0454\u044f\u00a2\u03b9\u0442\u03b1\u0442\u03b9\u03c3\u03b7 \u03c5\u0142\u0142\u03b1\u043c\u00a2\u03c3 \u0142\u03b1\u0432\u03c3\u044f\u03b9\u0455 \u03b7\u03b9\u0455\u03b9 \u03c5\u0442 \u03b1\u0142\u03b9q\u03c5\u03b9\u03c1 \u0454\u03c7 \u0454\u03b1 \u00a2\u03c3\u043c\u043c\u03c3\u2202\u03c3 \u00a2\u03c3\u03b7\u0455\u0454q\u03c5\u03b1\u0442. \u2202\u03c5\u03b9\u0455 \u03b1\u03c5\u0442\u0454 \u03b9\u044f\u03c5\u044f\u0454 \u2202\u03c3\u0142\u03c3\u044f \u03b9\u03b7 \u044f\u0454\u03c1\u044f\u0454\u043d\u0454\u03b7\u2202\u0454\u044f\u03b9\u0442 \u03b9\u03b7 \u03bd\u03c3\u0142\u03c5\u03c1\u0442\u03b1\u0442\u0454 \u03bd\u0454\u0142\u03b9\u0442 \u0454\u0455\u0455\u0454 \u00a2\u03b9\u0142\u0142\u03c5\u043c \u2202\u03c3\u0142\u03c3\u044f\u0454 \u0454\u03c5 \u0192\u03c5g\u03b9\u03b1\u0442 \u03b7\u03c5\u0142\u0142\u03b1 \u03c1\u03b1\u044f\u03b9\u03b1\u0442\u03c5\u044f. \u0454\u03c7\u00a2\u0454\u03c1\u0442\u0454\u03c5\u044f \u0455\u03b9\u03b7\u0442 \u03c3\u00a2\u00a2\u03b1\u0454\u00a2\u03b1\u0442 \u00a2\u03c5\u03c1\u03b9\u2202\u03b1\u0442\u03b1\u0442 \u03b7\u03c3\u03b7 \u03c1\u044f\u03c3\u03b9\u2202\u0454\u03b7\u0442, \u0455#",
"Select turnaround": "S\u00e9l\u00e9\u00e7t t\u00fcrn\u00e4r\u00f6\u00fcnd \u2c60'\u03c3\u044f\u0454\u043c \u03b9\u03c1\u0455\u03c5\u043c \u2202\u03c3\u0142\u03c3\u044f \u0455\u03b9\u0442 \u03b1\u043c\u0454#",
- "Selected blocks": "S\u00e9l\u00e9\u00e7t\u00e9d \u00dfl\u00f6\u00e7ks \u2c60'\u03c3\u044f\u0454\u043c \u03b9\u03c1\u0455\u03c5\u043c \u2202\u03c3\u0142\u03c3\u044f \u0455\u03b9\u0442 \u03b1#",
"Selected tab": "S\u00e9l\u00e9\u00e7t\u00e9d t\u00e4\u00df \u2c60'\u03c3\u044f\u0454\u043c \u03b9\u03c1\u0455\u03c5\u043c \u2202\u03c3\u0142\u03c3\u044f \u0455#",
"Self": "S\u00e9lf \u2c60'\u03c3\u044f\u0454\u043c \u03b9#",
"Send to:": "S\u00e9nd t\u00f6: \u2c60'\u03c3\u044f\u0454\u043c \u03b9\u03c1\u0455\u03c5\u043c \u2202#",
@@ -2021,7 +2020,6 @@
"Unable to load": "\u00dbn\u00e4\u00dfl\u00e9 t\u00f6 l\u00f6\u00e4d \u2c60'\u03c3\u044f\u0454\u043c \u03b9\u03c1\u0455\u03c5\u043c \u2202\u03c3\u0142\u03c3\u044f \u0455\u03b9\u0442#",
"Unable to submit application": "\u00dbn\u00e4\u00dfl\u00e9 t\u00f6 s\u00fc\u00dfm\u00eft \u00e4ppl\u00ef\u00e7\u00e4t\u00ef\u00f6n \u2c60'\u03c3\u044f\u0454\u043c \u03b9\u03c1\u0455\u03c5\u043c \u2202\u03c3\u0142\u03c3\u044f \u0455\u03b9\u0442 \u03b1\u043c\u0454\u0442, \u00a2\u03c3\u03b7\u0455\u0454\u00a2#",
"Unable to submit request to generate report.": "\u00dbn\u00e4\u00dfl\u00e9 t\u00f6 s\u00fc\u00dfm\u00eft r\u00e9q\u00fc\u00e9st t\u00f6 g\u00e9n\u00e9r\u00e4t\u00e9 r\u00e9p\u00f6rt. \u2c60'\u03c3\u044f\u0454\u043c \u03b9\u03c1\u0455\u03c5\u043c \u2202\u03c3\u0142\u03c3\u044f \u0455\u03b9\u0442 \u03b1\u043c\u0454\u0442, \u00a2\u03c3\u03b7\u0455\u0454\u00a2\u0442\u0454\u0442\u03c5\u044f #",
- "Unable to update settings": "\u00dbn\u00e4\u00dfl\u00e9 t\u00f6 \u00fcpd\u00e4t\u00e9 s\u00e9tt\u00efngs \u2c60'\u03c3\u044f\u0454\u043c \u03b9\u03c1\u0455\u03c5\u043c \u2202\u03c3\u0142\u03c3\u044f \u0455\u03b9\u0442 \u03b1\u043c\u0454\u0442, \u00a2\u03c3\u03b7\u0455#",
"Underline": "\u00dbnd\u00e9rl\u00efn\u00e9 \u2c60'\u03c3\u044f\u0454\u043c \u03b9\u03c1\u0455\u03c5\u043c \u2202\u03c3\u0142#",
"Undo": "\u00dbnd\u00f6 \u2c60'\u03c3\u044f\u0454\u043c \u03b9#",
"Undo (Ctrl+Z)": "\u00dbnd\u00f6 (\u00c7trl+Z) \u2c60'\u03c3\u044f\u0454\u043c \u03b9\u03c1\u0455\u03c5\u043c \u2202\u03c3\u0142\u03c3\u044f \u0455\u03b9#",
@@ -2169,6 +2167,7 @@
"View and grade responses": "V\u00ef\u00e9w \u00e4nd gr\u00e4d\u00e9 r\u00e9sp\u00f6ns\u00e9s \u2c60'\u03c3\u044f\u0454\u043c \u03b9\u03c1\u0455\u03c5\u043c \u2202\u03c3\u0142\u03c3\u044f \u0455\u03b9\u0442 \u03b1\u043c\u0454\u0442, \u00a2\u03c3\u03b7#",
"View child items": "V\u00ef\u00e9w \u00e7h\u00efld \u00eft\u00e9ms \u2c60'\u03c3\u044f\u0454\u043c \u03b9\u03c1\u0455\u03c5\u043c \u2202\u03c3\u0142\u03c3\u044f \u0455\u03b9\u0442 \u03b1\u043c#",
"View discussion": "V\u00ef\u00e9w d\u00efs\u00e7\u00fcss\u00ef\u00f6n \u2c60'\u03c3\u044f\u0454\u043c \u03b9\u03c1\u0455\u03c5\u043c \u2202\u03c3\u0142\u03c3\u044f \u0455\u03b9\u0442 \u03b1#",
+ "View files": "V\u00ef\u00e9w f\u00efl\u00e9s \u2c60'\u03c3\u044f\u0454\u043c \u03b9\u03c1\u0455\u03c5\u043c \u2202\u03c3\u0142\u03c3#",
"View program": "V\u00ef\u00e9w pr\u00f6gr\u00e4m \u2c60'\u03c3\u044f\u0454\u043c \u03b9\u03c1\u0455\u03c5\u043c \u2202\u03c3\u0142\u03c3\u044f \u0455#",
"View your receipts or modify your subscription on the {a_start}Orders and subscriptions{a_end} page": "V\u00ef\u00e9w \u00fd\u00f6\u00fcr r\u00e9\u00e7\u00e9\u00efpts \u00f6r m\u00f6d\u00eff\u00fd \u00fd\u00f6\u00fcr s\u00fc\u00dfs\u00e7r\u00efpt\u00ef\u00f6n \u00f6n th\u00e9 {a_start}\u00d6rd\u00e9rs \u00e4nd s\u00fc\u00dfs\u00e7r\u00efpt\u00ef\u00f6ns{a_end} p\u00e4g\u00e9 \u2c60'\u03c3\u044f\u0454\u043c \u03b9\u03c1\u0455\u03c5\u043c \u2202\u03c3\u0142\u03c3\u044f \u0455\u03b9\u0442 \u03b1\u043c\u0454\u0442, \u00a2\u03c3\u03b7\u0455#",
"View {span_start} {team_name} {span_end}": "V\u00ef\u00e9w {span_start} {team_name} {span_end} \u2c60'\u03c3\u044f\u0454\u043c \u03b9\u03c1\u0455\u03c5\u043c \u2202\u03c3\u0142\u03c3\u044f \u0455\u03b9\u0442 \u03b1\u043c#",
diff --git a/lms/static/js/i18n/es-419/djangojs.js b/lms/static/js/i18n/es-419/djangojs.js
index 537a9c241844..cb094093eb11 100644
--- a/lms/static/js/i18n/es-419/djangojs.js
+++ b/lms/static/js/i18n/es-419/djangojs.js
@@ -467,6 +467,7 @@
"Cannot delete when in use by a unit": "No puede borrar cuando esta en uso por una unidad",
"Cannot delete when in use by an experiment": "No se puede borrar mientras est\u00e9 en uso por un experimento",
"Cannot join instructor managed team": "No se puede unir al equipo administrado por el instructor",
+ "Cannot submit empty response even everything is optional.": "No se puede enviar una respuesta vac\u00eda, incluso si todo es opcional.",
"Cannot update attempt review status": "No es posible actualizar el estado de revisi\u00f3n de los intentos ",
"Caption": "Leyenda",
"Caution: The last published version of this unit is live. By publishing changes you will change the student experience.": "Atenci\u00f3n: La \u00faltima versi\u00f3n publicada de esta unidad est\u00e1 en vivo. Al publicar los cambios, cambiar\u00e1 la experiencia de los estudiantes.",
@@ -736,6 +737,7 @@
"Discussion topics in the course are not divided.": "Temas de discusi\u00f3n en el curso no son divididos.",
"Discussions are unified; all learners interact with posts from other learners, regardless of the group they are in.": "Las discusiones son unificadas; todos los estudiantes interact\u00faan con publicaciones de otros estudiantes, sin considerar su grupo.",
"Discussions enabled": "Discusiones habilitadas",
+ "Dismiss": "Descartar",
"Display Name": "Nombre para mostrar:",
"Div": "Div",
"Divide the selected content-specific discussion topics": "Divide los contenidos espec\u00edficos seleccionados de los temas de la discusi\u00f3n",
@@ -1213,7 +1215,6 @@
"Loading more threads": "Cargando m\u00e1s discusiones",
"Loading posts list": "Cargando lista de publicaci\u00f3nes",
"Loading your courses": "Cargando tus cursos",
- "Loading...": "Cargando...",
"Location": "Ubicaci\u00f3n",
"Location in Course": "Ubicaci\u00f3n en el curso",
"Lock this asset": "Bloquear este recurso",
@@ -1294,7 +1295,7 @@
"New Password": "Nueva Contrase\u00f1a",
"New document": "Documento nuevo",
"New enrollment mode:": "Nuevo modo de inscripcion:",
- "New files were added to this course's Files & Uploads": "Se agregaron nuevos archivos a la secci\u00f3n Archivos y Cargas de este curso",
+ "New file(s) added to Files & Uploads.": "Nuevos archivos agregados a Archivos y cargas.",
"New window": "Nueva ventana",
"New {component_type}": "Nuevo {component_type}",
"Next": "Siguiente",
@@ -1310,6 +1311,7 @@
"No content-specific discussion topics exist.": "No existen temas de discusi\u00f3n de contenidos espec\u00edficos",
"No description available": "No hay descripci\u00f3n disponible",
"No exams in course {course_id}.": "No hay examenes en el este curso {course_id}.",
+ "No files selected for upload.": "No hay archivos seleccionados para cargar.",
"No instructor dashboard for {proctor_service}": "No instructor registrado para {proctor_service}",
"No onboarding status API for {proctor_service}": "API no disponible para el estado de inducci\u00f3n {proctor_service}",
"No posts matched your query.": "Ninguna publicaci\u00f3n coincide con los criterios dados.",
@@ -1471,12 +1473,15 @@
"Please fix the following errors:": "Por favor corrija los siguientes errores:",
"Please follow the instructions here to upload a file elsewhere and link to it: {maxFileSizeRedirectUrl}": "Por favor siga las instrucciones aqui para cargar un archivo en otro parte y enlazelo: {maxFileSizeRedirectUrl}",
"Please note: Deletion of your account and personal data is permanent and cannot be undone. {platformName} will not be able to recover your account or the data that is deleted.": "Cuidado: la eliminaci\u00f3n de su cuenta y datos personales es permanente e irreversible. {platformName} no podr\u00e1 recuperar ni su cuenta ni los datos eliminados.",
+ "Please provide a description for each file you are uploading.": "Proporcione una descripci\u00f3n para cada archivo que est\u00e1 cargando.",
"Please provide a description of the link destination.": "Por favor, provee una descripci\u00f3n de la destinaci\u00f3n del v\u00ednculo.",
+ "Please provide a response.": "Proporcione una respuesta.",
"Please provide a valid URL.": "Por favor, provee un URL v\u00e1lido.",
"Please re-enter your password.": "Por favor, introduce tu contrase\u00f1a nuevamente.",
"Please select a PDF file to upload.": "Por favor selecciona un archivo PDF para subir.",
"Please select a file in .srt format.": "Por favor seleccione un archivo en formato .srt",
"Please specify a reason.": "Por favor especifica una raz\u00f3n.",
+ "Please upload a file.": "Cargue un archivo.",
"Please verify that you have uploaded a valid image (PNG and JPEG).": "Por favor verifica que hayas cargado una imagen v\u00e1lida (PNG y JPEG)",
"Please verify that your webcam is connected and that you have allowed your browser to access it.": "Por favor, comprueba que tu webcam este conectada y que el navegador tenga habilitado el acceso a la misma.",
"Please wait": "Por favor espere",
@@ -1695,7 +1700,6 @@
"Select the course-wide discussion topics that you want to divide.": "Seleccione los temas de discusi\u00f3n del curso que desea dividir.",
"Select the time zone for displaying course dates. If you do not specify a time zone, course dates, including assignment deadlines, will be displayed in your browser's local time zone.": "Selecciona la zona horaria para exponer las fechas del curso. Si no especificas una zona horaria, las fechas del curso, incluidas las fechas l\u00edmites de tareas, ser\u00e1n expuestas en la zona horaria local de tu navegador.",
"Select turnaround": "Seleccione tiempo de entrega.",
- "Selected blocks": "Bloques seleccionados",
"Selected tab": "Opci\u00f3n seleccionada",
"Self": "Auto",
"Send to:": "Enviar a:",
@@ -1994,6 +1998,7 @@
"There is no email history for this course.": "No hay historial de correos electr\u00f3nicos para este curso.",
"There is no onboarding exam accessible to this user.": "No se registra examen de inducci\u00f3n asequible para este usuario.",
"There is no onboarding exam related to this course id.": "No se registra un examen de inducci\u00f3n relacionado a esta identificaci\u00f3n de curso.",
+ "There is still file upload in progress. Please wait until it is finished.": "Todav\u00eda hay una carga de archivos en curso. Por favor espere hasta que termine.",
"There must be at least one group.": "Debe existir al menos un grupo.",
"There must be one cohort to which students can automatically be assigned.": "Tiene que haber una cohorte a la que los estudiantes pueden ser asignados autom\u00e1ticamente.",
"There was a problem creating the report. Select \"Create Executive Summary\" to try again.": "Hubo un problema creando el reporte. Selecciona \"Crear resumen ejecutivo\" para intentarlo nuevamente.",
@@ -2163,7 +2168,6 @@
"Unable to load": "No se ha podido cargar",
"Unable to submit application": "No se pudo enviar la solicitud",
"Unable to submit request to generate report.": "No se puede enviar la solicitud para generar reporte.",
- "Unable to update settings": "No es posible modificar las configuraciones",
"Underline": "Subrayado",
"Undo": "Deshacer",
"Undo (Ctrl+Z)": "Deshacer (Ctrl+Z)",
@@ -2308,6 +2312,7 @@
"View and grade responses": "Ver y calificar las respuestas",
"View child items": "Ver items hijos",
"View discussion": "Ver discusi\u00f3n",
+ "View files": "Archivos de vista",
"View my exam": "Ver mi examen",
"View program": "Ver programa",
"View your receipts or modify your subscription on the {a_start}Orders and subscriptions{a_end} page": "Consulta tus recibos o modifica tu suscripci\u00f3n en la p\u00e1gina {a_start}Pedidos y suscripciones{a_end}",
diff --git a/lms/static/js/i18n/es-ar/djangojs.js b/lms/static/js/i18n/es-ar/djangojs.js
index 76478b97ffc8..298c573a68c5 100644
--- a/lms/static/js/i18n/es-ar/djangojs.js
+++ b/lms/static/js/i18n/es-ar/djangojs.js
@@ -158,6 +158,7 @@
"Block view is unavailable": "La vista de bloque no est\u00e1 disponible",
"Can I request additional time to complete my exam?": "\u00bfPuedo solicitar un tiempo adicional para completar mi examen?",
"Cancel": "Cancelar",
+ "Cannot submit empty response even everything is optional.": "No se puede enviar una respuesta vac\u00eda, incluso si todo es opcional.",
"Cannot update attempt review status": "No se puede actualizar el estado de revisi\u00f3n del intento",
"Changes to steps that are not selected as part of the assignment will not be saved.": "Los cambios en los pasos que no se seleccionen como parte de la tarea no se guardar\u00e1n.",
"Choose": "Seleccionar",
@@ -241,6 +242,7 @@
"Must be a Staff User to Perform this request.": "Debe ser un miembro del equipo para realizar esta petici\u00f3n.",
"Navigate to onboarding exam": "Navegar al examen de incorporaci\u00f3n",
"No exams in course {course_id}.": "No hay ex\u00e1menes en curso {course_id}.",
+ "No files selected for upload.": "No hay archivos seleccionados para cargar.",
"No instructor dashboard for {proctor_service}": "No hay panel de instructor para {proctor_service}",
"No onboarding status API for {proctor_service}": "Sin API de estado de ingreso para {proctor_service}",
"No proctored exams in course {course_id}": "No hay ex\u00e1menes supervisados en curso {course_id}",
@@ -272,6 +274,9 @@
"Peers Assessed": "Compa\u00f1eros evaluados",
"Pending Session Review": "Revisi\u00f3n de sesi\u00f3n pendiente",
"Please check your internet connection.": "Por favor, revisar la conexi\u00f3n de Internet.",
+ "Please provide a description for each file you are uploading.": "Proporcione una descripci\u00f3n para cada archivo que est\u00e1 cargando.",
+ "Please provide a response.": "Por favor, escriba una respuesta.",
+ "Please upload a file.": "Por favor, cargue un archivo.",
"Please wait": "Espere por favor",
"Practice Exam Completed": "Examen de pr\u00e1ctica completado",
"Practice Exam Failed": "Examen de pr\u00e1ctica fallido",
@@ -326,6 +331,7 @@
"There are currently {stuck_learners} learners in the waiting state, meaning they have not yet met all requirements for Peer Assessment. ": "Actualmente hay {stuck_learners} alumnos en estado de espera, lo que significa que a\u00fan no han cumplido con todos los requisitos para la evaluaci\u00f3n por pares.",
"There is no onboarding exam accessible to this user.": "No hay ning\u00fan examen de ingreso accesible para este usuario.",
"There is no onboarding exam related to this course id.": "No hay un examen de ingreso relacionado con esta identificaci\u00f3n de curso.",
+ "There is still file upload in progress. Please wait until it is finished.": "Todav\u00eda hay una carga de archivos en curso. Por favor, espere hasta que termine.",
"This ORA has already been released. Changes will only affect learners making new submissions. Existing submissions will not be modified by this change.": "Este ORA ya ha sido publicado. Los cambios solo afectar\u00e1n a los alumnos que realicen nuevos env\u00edos. Las presentaciones existentes no se ver\u00e1n modificadas por este cambio.",
"This assessment could not be submitted.": "Esta evaluaci\u00f3n no se pudo enviar.",
"This exam has a time limit associated with it.": "Este examen tiene un l\u00edmite de tiempo",
diff --git a/lms/static/js/i18n/es-es/djangojs.js b/lms/static/js/i18n/es-es/djangojs.js
index 2c0d4f535e14..92f27659fdc3 100644
--- a/lms/static/js/i18n/es-es/djangojs.js
+++ b/lms/static/js/i18n/es-es/djangojs.js
@@ -158,6 +158,7 @@
"Block view is unavailable": "La vista en bloque no est\u00e1 disponible",
"Can I request additional time to complete my exam?": "\u00bfPuedo solicitar un tiempo adicional para completar mi examen?",
"Cancel": "Cancelar",
+ "Cannot submit empty response even everything is optional.": "No se puede enviar una respuesta vac\u00eda, incluso si todo es opcional.",
"Cannot update attempt review status": "No se puede actualizar el estado de revisi\u00f3n del intento",
"Changes to steps that are not selected as part of the assignment will not be saved.": "Los cambios en los pasos que no est\u00e1n seleccionados como parte de la tarea no se guardar\u00e1n.",
"Choose": "Elegir",
@@ -241,6 +242,7 @@
"Must be a Staff User to Perform this request.": "Debes ser un miembro del equipo para realizar esta petici\u00f3n.",
"Navigate to onboarding exam": "Navegar al examen de incorporaci\u00f3n",
"No exams in course {course_id}.": "No hay ex\u00e1menes en curso {course_id}.",
+ "No files selected for upload.": "No hay archivos seleccionados para cargar.",
"No instructor dashboard for {proctor_service}": "No hay panel de instructor para {proctor_service}",
"No onboarding status API for {proctor_service}": "Sin API de estado de ingreso para {proctor_service}",
"No proctored exams in course {course_id}": "No hay ex\u00e1menes supervisados en curso {course_id}",
@@ -272,6 +274,9 @@
"Peers Assessed": "Compa\u00f1ero evaluado",
"Pending Session Review": "Revisi\u00f3n de la sesi\u00f3n pendiente",
"Please check your internet connection.": "Por favor, revisar la conexi\u00f3n de Internet.",
+ "Please provide a description for each file you are uploading.": "Proporcione una descripci\u00f3n para cada archivo que est\u00e1 cargando.",
+ "Please provide a response.": "Por favor, escriba una respuesta.",
+ "Please upload a file.": "Por favor, cargue un archivo.",
"Please wait": "Por favor, espera",
"Practice Exam Completed": "Examen pr\u00e1ctico completado",
"Practice Exam Failed": "Examen pr\u00e1ctico fallido",
@@ -326,6 +331,7 @@
"There are currently {stuck_learners} learners in the waiting state, meaning they have not yet met all requirements for Peer Assessment. ": "Actualmente se encuentran {stuck_learners} estudiantes en estado de espera, lo cual significa que a\u00fan no cumplen con todos los requisitos para la evaluaci\u00f3n por pares.",
"There is no onboarding exam accessible to this user.": "No hay ning\u00fan examen de ingreso accesible para este usuario.",
"There is no onboarding exam related to this course id.": "No hay un examen de ingreso relacionado con esta identificaci\u00f3n de curso.",
+ "There is still file upload in progress. Please wait until it is finished.": "Todav\u00eda hay una carga de archivos en curso. Por favor, espere hasta que termine.",
"This ORA has already been released. Changes will only affect learners making new submissions. Existing submissions will not be modified by this change.": "Esta tarea de respuesta abierta ya ha sido publicada. Los cambios solo afectar\u00e1n a los estudiantes que hagan nuevas entregas. Las entregas ya realizadas no se ver\u00e1n modificadas por este cambio.",
"This assessment could not be submitted.": "Esta tarea no ha podido enviarse.",
"This exam has a time limit associated with it.": "Este examen tiene un l\u00edmite de tiempo",
diff --git a/lms/static/js/i18n/eu-es/djangojs.js b/lms/static/js/i18n/eu-es/djangojs.js
index 8e9f08714f1a..cc6b5d6487c2 100644
--- a/lms/static/js/i18n/eu-es/djangojs.js
+++ b/lms/static/js/i18n/eu-es/djangojs.js
@@ -1159,7 +1159,6 @@
"This is the list of chosen %s. You may remove some by selecting them in the box below and then clicking the \"Remove\" arrow between the two boxes.": "Hau da aukeratutako %s zerrenda. Hauetako zenbait ezaba ditzakezu azpiko kutxan hautatu eta bi kutxen artean dagoen \"Ezabatu\" gezian klik eginez.",
"This is the name of the group": "Hau taldearen izena da",
"This learner is currently sharing a limited profile.": "Ikasle hau une honetan profil mugatua partekatzen ari da.",
- "This may be happening because of an error with our server or your internet connection. Try refreshing the page or making sure you are online.": "Zure zerbitzarearen edo zure interneteko konexioaren arazo batengatik gertatuko zen hau agian. Saiatu orria freskatzen eta ziurtatu on-line zaudela.",
"This post could not be closed. Refresh the page and try again.": "Mezu hau ezin da itxi. Freskatu orria eta saiatu berri",
"This post could not be flagged for abuse. Refresh the page and try again.": "Mezu hau ezin da iraintzat markatu. Freskatu orria eta saiatu berri",
"This post could not be unflagged for abuse. Refresh the page and try again.": "Mezu hau ezin da iraintzat desmarkatu. Freskatu orria eta saiatu berri",
diff --git a/lms/static/js/i18n/fa-ir/djangojs.js b/lms/static/js/i18n/fa-ir/djangojs.js
index a6fdba8dbe1c..ef7a945126da 100644
--- a/lms/static/js/i18n/fa-ir/djangojs.js
+++ b/lms/static/js/i18n/fa-ir/djangojs.js
@@ -467,6 +467,7 @@
"Cannot delete when in use by a unit": "\u0646\u0645\u06cc\u200c\u062a\u0648\u0627\u0646\u06cc\u062f \u0647\u0646\u06af\u0627\u0645 \u0627\u0633\u062a\u0641\u0627\u062f\u0647 \u062a\u0648\u0633\u0637 \u06cc\u06a9 \u0648\u0627\u062d\u062f\u060c \u0622\u0646 \u0631\u0627 \u062d\u0630\u0641 \u06a9\u0646\u06cc\u062f",
"Cannot delete when in use by an experiment": "\u0647\u0646\u06af\u0627\u0645\u06cc \u06a9\u0647 \u0627\u0632 \u0622\u0646 \u062f\u0631 \u062a\u062c\u0631\u0628\u0647\u200c\u0627\u06cc \u0627\u0633\u062a\u0641\u0627\u062f\u0647 \u0645\u06cc\u200c\u0634\u0648\u062f \u0627\u0645\u06a9\u0627\u0646 \u062d\u0630\u0641 \u0622\u0646 \u0646\u06cc\u0633\u062a",
"Cannot join instructor managed team": "\u0646\u0645\u06cc\u200c\u062a\u0648\u0627\u0646\u06cc\u062f \u0628\u0647 \u062a\u06cc\u0645\u06cc \u06a9\u0647 \u062a\u0648\u0633\u0637 \u0645\u0631\u0628\u06cc \u0645\u062f\u06cc\u0631\u06cc\u062a \u0645\u06cc\u200c\u0634\u0648\u062f \u0628\u067e\u06cc\u0648\u0646\u062f\u06cc\u062f",
+ "Cannot submit empty response even everything is optional.": "\u0646\u0645\u06cc \u062a\u0648\u0627\u0646 \u067e\u0627\u0633\u062e \u062e\u0627\u0644\u06cc \u0627\u0631\u0633\u0627\u0644 \u06a9\u0631\u062f \u062d\u062a\u06cc \u0647\u0645\u0647 \u0686\u06cc\u0632 \u0627\u062e\u062a\u06cc\u0627\u0631\u06cc \u0627\u0633\u062a.",
"Cannot update attempt review status": "\u0627\u0645\u06a9\u0627\u0646 \u0631\u0648\u0632\u0622\u0645\u062f\u0633\u0627\u0632\u06cc \u0648\u0636\u0639\u06cc\u062a \u062a\u0644\u0627\u0634 \u0628\u0631\u0631\u0633\u06cc \u0646\u06cc\u0633\u062a",
"Caption": " \u062a\u0648\u0636\u06cc\u062d",
"Caution: The last published version of this unit is live. By publishing changes you will change the student experience.": "\u0627\u062d\u062a\u06cc\u0627\u0637: \u0622\u062e\u0631\u06cc\u0646 \u0646\u0633\u062e\u06c0 \u0645\u0646\u062a\u0634\u0631\u0634\u062f\u06c0 \u0627\u06cc\u0646 \u0648\u0627\u062d\u062f \u067e\u062e\u0634 \u0632\u0646\u062f\u0647 \u0627\u0633\u062a. \u0628\u0627 \u0627\u0646\u062a\u0634\u0627\u0631 \u062a\u063a\u06cc\u06cc\u0631\u0627\u062a\u060c \u062a\u062c\u0631\u0628\u06c0 \u06cc\u0627\u062f\u06af\u06cc\u0631\u0646\u062f\u0647 \u0631\u0627 \u062a\u063a\u06cc\u06cc\u0631 \u062e\u0648\u0627\u0647\u06cc\u062f \u062f\u0627\u062f.",
@@ -757,6 +758,7 @@
"Draft (Never published)": "\u067e\u06cc\u0634\u200c\u0646\u0648\u06cc\u0633 (\u0647\u0631\u06af\u0632 \u0645\u0646\u062a\u0634\u0631\u0646\u0634\u062f\u0647)",
"Draft (Unpublished changes)": "\u067e\u06cc\u0634\u200c\u0646\u0648\u06cc\u0633 (\u062a\u063a\u06cc\u06cc\u0631\u0627\u062a \u0645\u0646\u062a\u0634\u0631\u0646\u0634\u062f\u0647)",
"Draft saved on {lastSavedStart}{editedOn}{lastSavedEnd} by {editedByStart}{editedBy}{editedByEnd}": "\u067e\u06cc\u0634\u200c\u0646\u0648\u06cc\u0633 \u0630\u062e\u06cc\u0631\u0647 \u0634\u062f\u0647 \u0627\u0633\u062a \u062f\u0631 {lastSavedStart}{editedOn}{lastSavedEnd} \u0628\u0647\u200c\u062f\u0633\u062a {editedByStart}{editedBy}{editedByEnd}",
+ "Draft saved!": "\u067e\u06cc\u0634 \u0646\u0648\u06cc\u0633 \u0630\u062e\u06cc\u0631\u0647 \u0634\u062f!",
"Drag and drop or {spanStart}browse your computer{spanEnd}.": "\u0628\u06a9\u0634 \u0648 \u0631\u0647\u0627\u06a9\u0646 \u06cc\u0627 {spanStart} \u0631\u0627\u06cc\u0627\u0646\u0647\u200c\u0627\u062a \u0631\u0627 \u0628\u0631\u0631\u0633\u06cc \u06a9\u0646 {spanEnd}.",
"Drag to reorder": "\u06a9\u0634\u06cc\u062f\u0646 \u0628\u0631\u0627\u06cc \u062a\u0631\u062a\u06cc\u0628 \u0645\u062c\u062f\u062f",
"Drop target image": "\u062a\u0635\u0648\u06cc\u0631 \u0647\u062f\u0641 \u0631\u0627 \u0631\u0647\u0627 \u06a9\u0646\u06cc\u062f",
@@ -1212,7 +1214,6 @@
"Loading more threads": "\u062f\u0631 \u062d\u0627\u0644 \u0628\u0627\u0631\u06af\u06cc\u0631\u06cc \u0645\u0648\u0636\u0648\u0639\u0627\u062a \u0628\u06cc\u0634\u062a\u0631",
"Loading posts list": "\u062f\u0631 \u062d\u0627\u0644 \u0628\u0627\u0631\u06af\u06cc\u0631\u06cc \u0641\u0647\u0631\u0633\u062a \u0645\u0637\u0627\u0644\u0628 \u0627\u0631\u0633\u0627\u0644\u06cc",
"Loading your courses": "\u062f\u0631 \u062d\u0627\u0644 \u0628\u0627\u0631\u06af\u06cc\u0631\u06cc \u062f\u0648\u0631\u0647\u200c\u0647\u0627\u06cc \u0634\u0645\u0627",
- "Loading...": "\u062f\u0631 \u062d\u0627\u0644 \u0628\u0627\u0631\u06af\u06cc\u0631\u06cc ...",
"Location": "\u0645\u06a9\u0627\u0646",
"Location in Course": "\u0645\u06a9\u0627\u0646 \u062f\u0631 \u062f\u0648\u0631\u0647 \u0622\u0645\u0648\u0632\u0634\u06cc",
"Lock this asset": "\u0642\u0641\u0644 \u0627\u06cc\u0646 \u0645\u0646\u0628\u0639",
@@ -1293,7 +1294,6 @@
"New Password": "\u06af\u0630\u0631\u0648\u0627\u0698\u06c0 \u062c\u062f\u06cc\u062f",
"New document": "\u0633\u0646\u062f \u062c\u062f\u06cc\u062f",
"New enrollment mode:": "\u0648\u0636\u0639\u06cc\u062a \u062a\u0627\u0632\u0647 \u062b\u0628\u062a\u200c\u0646\u0627\u0645:",
- "New files were added to this course's Files & Uploads": "\u0641\u0627\u06cc\u0644 \u0647\u0627\u06cc \u062c\u062f\u06cc\u062f \u0628\u0647 \"\u0641\u0627\u06cc\u0644 \u0647\u0627 \u0648 \u0622\u067e\u0644\u0648\u062f\u0647\u0627\"\u06cc \u0627\u06cc\u0646 \u062f\u0648\u0631\u0647 \u0627\u0636\u0627\u0641\u0647 \u0634\u062f",
"New window": "\u067e\u0646\u062c\u0631\u06c0 \u062c\u062f\u06cc\u062f",
"New {component_type}": "{component_type} \u062c\u062f\u06cc\u062f",
"Next": "\u0628\u0639\u062f\u06cc",
@@ -1309,6 +1309,7 @@
"No content-specific discussion topics exist.": "\u0647\u06cc\u0686 \u0645\u0628\u062d\u062b\u06cc \u0645\u0631\u0628\u0648\u0637 \u0628\u0647 \u0645\u062d\u062a\u0648\u0627\u06cc \u062e\u0627\u0635 \u0648\u062c\u0648\u062f \u0646\u062f\u0627\u0631\u062f.",
"No description available": "\u0628\u062f\u0648\u0646 \u0634\u0631\u062d",
"No exams in course {course_id}.": "\u0647\u06cc\u0686 \u0622\u0632\u0645\u0648\u0646\u06cc \u062f\u0631 \u062f\u0648\u0631\u0647 \u0622\u0645\u0648\u0632\u0634\u06cc {course_id} \u0648\u062c\u0648\u062f \u0646\u062f\u0627\u0631\u062f.",
+ "No files selected for upload.": "\u0647\u06cc\u0686 \u0641\u0627\u06cc\u0644\u06cc \u0628\u0631\u0627\u06cc \u0622\u067e\u0644\u0648\u062f \u0627\u0646\u062a\u062e\u0627\u0628 \u0646\u0634\u062f\u0647 \u0627\u0633\u062a.",
"No instructor dashboard for {proctor_service}": "\u0628\u062f\u0648\u0646 \u067e\u06cc\u0634\u062e\u0648\u0627\u0646 \u0622\u0645\u0648\u0632\u0634\u06cc \u0628\u0631\u0627\u06cc {proctor_service}",
"No onboarding status API for {proctor_service}": "API \u0648\u0636\u0639\u06cc\u062a \u0648\u0631\u0648\u062f \u0628\u0631\u0627\u06cc {proctor_service} \u0648\u062c\u0648\u062f \u0646\u062f\u0627\u0631\u062f",
"No posts matched your query.": "\u0647\u06cc\u0686 \u0645\u0637\u0644\u0628 \u0627\u0631\u0633\u0627\u0644\u06cc \u0628\u0627 \u062c\u0633\u062a\u062c\u0648\u06cc \u0634\u0645\u0627 \u0645\u0646\u0637\u0628\u0642 \u0646\u0628\u0648\u062f.",
@@ -1449,6 +1450,7 @@
"Please add the instructor's title": "\u0644\u0637\u0641\u0627\u064b \u0639\u0646\u0648\u0627\u0646 \u0645\u0631\u0628\u06cc \u0631\u0627 \u0628\u06cc\u0641\u0632\u0627\u06cc\u06cc\u062f",
"Please address the errors on this page first, and then save your progress.": "\u0644\u0637\u0641\u0627 \u0627\u0628\u062a\u062f\u0627 \u062e\u0637\u0627\u0647\u0627\u06cc \u0627\u06cc\u0646 \u0635\u0641\u062d\u0647 \u0631\u0627 \u0628\u0631\u0631\u0633\u06cc \u0648 \u0631\u0641\u0639 \u06a9\u0631\u062f\u0647 \u0633\u067e\u0633 \u0645\u06cc\u0632\u0627\u0646 \u067e\u06cc\u0634\u0631\u0641\u062a \u062e\u0648\u062f \u0631\u0627 \u0630\u062e\u06cc\u0631\u0647 \u06a9\u0646\u06cc\u062f. ",
"Please check the following validation feedbacks and reflect them in your course settings:": "\u0644\u0637\u0641\u0627\u064b \u0628\u0627\u0632\u062e\u0648\u0631\u062f\u0647\u0627\u06cc \u062a\u0623\u06cc\u06cc\u062f \u0627\u0639\u062a\u0628\u0627\u0631 \u0632\u06cc\u0631 \u0631\u0627 \u06a9\u0646\u062a\u0631\u0644 \u06a9\u0631\u062f\u0647 \u0648 \u0622\u0646\u200c\u0647\u0627 \u0631\u0627 \u062f\u0631 \u062a\u0646\u0638\u06cc\u0645\u0627\u062a \u062f\u0648\u0631\u06c0 \u0622\u0645\u0648\u0632\u0634\u06cc \u062e\u0648\u062f \u0645\u0646\u0639\u06a9\u0633 \u06a9\u0646\u06cc\u062f:",
+ "Please check your internet connection.": "\u0644\u0637\u0641\u0627 \u0627\u062a\u0635\u0627\u0644 \u0627\u06cc\u0646\u062a\u0631\u0646\u062a \u062e\u0648\u062f \u0631\u0627 \u0628\u0631\u0631\u0633\u06cc \u06a9\u0646\u06cc\u062f.",
"Please describe this image or agree that it has no contextual value by checking the checkbox.": "\u0644\u0637\u0641\u0627\u064b \u0627\u06cc\u0646 \u062a\u0635\u0648\u06cc\u0631 \u0631\u0627 \u062a\u0648\u0635\u06cc\u0641 \u06a9\u0646\u06cc\u062f \u06cc\u0627 \u0628\u0627 \u0632\u062f\u0646 \u0639\u0644\u0627\u0645\u062a \u062f\u0631 \u062e\u0627\u0646\u0647 \u06a9\u0646\u062a\u0631\u0644 \u0645\u0648\u0627\u0641\u0642\u062a \u06a9\u0646\u06cc\u062f \u06a9\u0647 \u0647\u06cc\u0686 \u0627\u0631\u0632\u0634 \u0645\u062a\u0646\u06cc \u0646\u062f\u0627\u0631\u062f. ",
"Please do not use any spaces in this field.": "\u0644\u0637\u0641\u0627 \u0627\u0632 \u0641\u0627\u0635\u0644\u0647 \u062f\u0631 \u0627\u06cc\u0646 \u0642\u0633\u0645\u062a \u0627\u0633\u062a\u0641\u0627\u062f\u0647 \u0646\u06a9\u0646\u06cc\u062f.",
"Please do not use any spaces or special characters in this field.": "\u0644\u0637\u0641\u0627 \u0627\u0632 \u0641\u0627\u0635\u0644\u0647 \u06cc\u0627 \u0646\u0648\u06cc\u0633\u0647\u200c\u0647\u0627\u06cc \u062e\u0627\u0635 \u062f\u0631 \u0627\u06cc\u0646 \u0642\u0633\u0645\u062a \u0627\u0633\u062a\u0641\u0627\u062f\u0647 \u0646\u06a9\u0646\u06cc\u062f.",
@@ -1469,12 +1471,15 @@
"Please fix the following errors:": "\u0644\u0637\u0641\u0627\u064b \u062e\u0637\u0627\u0647\u0627\u06cc \u0632\u06cc\u0631 \u0631\u0627 \u0627\u0635\u0644\u0627\u062d \u06a9\u0646\u06cc\u062f:",
"Please follow the instructions here to upload a file elsewhere and link to it: {maxFileSizeRedirectUrl}": "\u0644\u0637\u0641\u0627 \u0631\u0627\u0647\u0646\u0645\u0627\u06cc \u0632\u06cc\u0631 \u0631\u0627 \u0628\u0631\u0627\u06cc \u0686\u06af\u0648\u0646\u06af\u06cc \u0628\u0627\u0631\u06af\u0630\u0627\u0631\u06cc \u06cc\u06a9 \u0641\u0627\u06cc\u0644 \u062f\u0631 \u062c\u0627\u06cc\u06cc \u062f\u06cc\u06af\u0631 \u0648 \u06cc\u06a9 \u0627\u0631\u062a\u0628\u0627\u0637 \u0628\u0647 \u0622\u0646 \u0627\u06cc\u062c\u0627\u062f \u06a9\u0646\u06cc\u062f : {maxFileSizeRedirectUrl}",
"Please note: Deletion of your account and personal data is permanent and cannot be undone. {platformName} will not be able to recover your account or the data that is deleted.": "\u0644\u0637\u0641\u0627\u064b \u062a\u0648\u062c\u0647 \u062f\u0627\u0634\u062a\u0647 \u0628\u0627\u0634\u06cc\u062f: \u062d\u0633\u0627\u0628 \u06a9\u0627\u0631\u0628\u0631\u06cc \u0648 \u062f\u0627\u062f\u0647\u200c\u0647\u0627\u06cc \u0634\u062e\u0635\u06cc \u0634\u0645\u0627 \u0628\u0631\u0627\u06cc \u0647\u0645\u06cc\u0634\u0647 \u062d\u0630\u0641 \u062e\u0648\u0627\u0647\u062f \u0634\u062f \u0648 \u0642\u0627\u0628\u0644 \u0648\u0627\u06af\u0631\u062f \u0646\u06cc\u0633\u062a. \u067e\u0633 {platformName} \u0646\u0645\u06cc\u200c\u062a\u0648\u0627\u0646\u062f \u062d\u0633\u0627\u0628 \u06a9\u0627\u0631\u0628\u0631\u06cc \u0634\u0645\u0627 \u06cc\u0627 \u062f\u0627\u062f\u0647\u200c\u0647\u0627\u06cc \u062d\u0630\u0641\u200c\u0634\u062f\u0647 \u0631\u0627 \u0628\u0627\u0632\u06cc\u0627\u0628\u06cc \u06a9\u0646\u062f.",
+ "Please provide a description for each file you are uploading.": "\u0644\u0637\u0641\u0627\u064b \u062a\u0648\u0636\u06cc\u062d\u06cc \u0628\u0631\u0627\u06cc \u0647\u0631 \u0641\u0627\u06cc\u0644\u06cc \u06a9\u0647 \u0622\u067e\u0644\u0648\u062f \u0645\u06cc \u06a9\u0646\u06cc\u062f \u0627\u0631\u0627\u0626\u0647 \u062f\u0647\u06cc\u062f.",
"Please provide a description of the link destination.": "\u0644\u0637\u0641\u0627\u064b \u062a\u0648\u0636\u06cc\u062d\u06cc \u062f\u0631\u0628\u0627\u0631\u06c0 \u0645\u0642\u0635\u062f \u067e\u06cc\u0648\u0646\u062f \u0627\u0631\u0627\u0626\u0647 \u062f\u0647\u06cc\u062f.",
+ "Please provide a response.": "\u0644\u0637\u0641\u0627 \u067e\u0627\u0633\u062e \u062f\u0647\u06cc\u062f.",
"Please provide a valid URL.": "\u06cc\u06a9 \u0646\u0634\u0627\u0646\u06cc \u0627\u06cc\u0646\u062a\u0631\u0646\u062a\u06cc \u0645\u0639\u062a\u0628\u0631 \u0648\u0627\u0631\u062f \u06a9\u0646\u06cc\u062f.",
"Please re-enter your password.": "\u0644\u0637\u0641\u0627\u064b \u06af\u0630\u0631\u0648\u0627\u0698\u0647 \u0631\u0627 \u062f\u0648\u0628\u0627\u0631\u0647 \u0648\u0627\u0631\u062f \u06a9\u0646\u06cc\u062f.",
"Please select a PDF file to upload.": "\u0644\u0637\u0641\u0627 \u06cc\u06a9 \u067e\u0631\u0648\u0646\u062f\u0647 PDF \u0628\u0631\u0627\u06cc \u0628\u0627\u0631\u06af\u0630\u0627\u0631\u06cc \u0627\u0646\u062a\u062e\u0627\u0628 \u06a9\u0646\u06cc\u062f",
"Please select a file in .srt format.": "\u0644\u0637\u0641\u0627 \u06cc\u06a9 \u067e\u0631\u0648\u0646\u062f\u0647 \u0628\u0627 \u0642\u0627\u0644\u0628 srt. \u0628\u0631\u0627\u06cc \u0628\u0627\u0631\u06af\u0630\u0627\u0631\u06cc \u0627\u0646\u062a\u062e\u0627\u0628 \u06a9\u0646\u06cc\u062f.",
"Please specify a reason.": "\u0644\u0637\u0641\u0627\u064b \u06cc\u06a9 \u062f\u0644\u06cc\u0644 \u0630\u06a9\u0631 \u06a9\u0646\u06cc\u062f.",
+ "Please upload a file.": "\u0644\u0637\u0641\u0627 \u06cc\u06a9 \u0641\u0627\u06cc\u0644 \u0622\u067e\u0644\u0648\u062f \u06a9\u0646\u06cc\u062f",
"Please verify that you have uploaded a valid image (PNG and JPEG).": "\u0644\u0637\u0641\u0627\u064b \u062a\u0623\u06cc\u06cc\u062f \u06a9\u0646\u06cc\u062f \u06a9\u0647 \u062a\u0635\u0648\u06cc\u0631\u06cc \u0645\u0639\u062a\u0628\u0631 (PNG \u0648 JPEG) \u0628\u0627\u0631\u06af\u0630\u0627\u0631\u06cc \u06a9\u0631\u062f\u0647\u200c\u0627\u06cc\u062f.",
"Please verify that your webcam is connected and that you have allowed your browser to access it.": "\u0644\u0637\u0641\u0627\u064b \u0628\u0631\u0631\u0633\u06cc \u06a9\u0646\u06cc\u062f \u06a9\u0647 \u062f\u0648\u0631\u0628\u06cc\u0646 \u0631\u0627\u06cc\u0627\u0646\u06c0 \u0634\u0645\u0627 \u0645\u062a\u0635\u0644 \u0627\u0633\u062a \u0648 \u0628\u0647 \u0645\u0631\u0648\u0631\u06af\u0631 \u062e\u0648\u062f \u0627\u062c\u0627\u0632\u06c0 \u062f\u0633\u062a\u0631\u0633\u06cc \u0628\u0647 \u0622\u0646 \u0631\u0627 \u062f\u0627\u062f\u0647\u200c\u0627\u06cc\u062f.",
"Please wait": "\u0644\u0637\u0641\u0627 \u0634\u06a9\u06cc\u0628\u0627 \u0628\u0627\u0634\u06cc\u062f",
@@ -1650,6 +1655,8 @@
"Save changes": "\u0630\u062e\u06cc\u0631\u0647 \u062a\u063a\u06cc\u06cc\u0631\u0627\u062a",
"Saved cohort": "\u062f\u0633\u062a\u0647 \u0630\u062e\u06cc\u0631\u0647 \u0634\u062f\u0647 ",
"Saving": "\u062f\u0631 \u062d\u0627\u0644 \u0630\u062e\u06cc\u0631\u0647\u200c\u0633\u0627\u0632\u06cc",
+ "Saving draft": "\u0630\u062e\u06cc\u0631\u0647 \u067e\u06cc\u0634 \u0646\u0648\u06cc\u0633",
+ "Saving draft...": "\u062f\u0631 \u062d\u0627\u0644 \u0630\u062e\u06cc\u0631\u0647 \u067e\u06cc\u0634 \u0646\u0648\u06cc\u0633...",
"Saving your email preference": "\u062f\u0631 \u062d\u0627\u0644 \u0630\u062e\u06cc\u0631\u06c0 \u0631\u0627\u06cc\u0627\u0646\u0627\u0645\u0647 \u0645\u0631\u062c\u062d",
"Scheduled:": "\u0628\u0631\u0646\u0627\u0645\u0647\u200c\u0631\u06cc\u0632\u06cc\u200c\u0634\u062f\u0647:",
"Scope": "\u062f\u0627\u0645\u0646\u0647",
@@ -1691,7 +1698,6 @@
"Select the course-wide discussion topics that you want to divide.": "\u0645\u0628\u0627\u062d\u062b \u06af\u0641\u062a\u06af\u0648\u06cc \u0637\u0648\u0644 \u062f\u0648\u0631\u0647 \u0622\u0645\u0648\u0632\u0634\u06cc \u0631\u0627 \u0627\u0646\u062a\u062e\u0627\u0628 \u06a9\u0646\u06cc\u062f \u06a9\u0647 \u0645\u06cc\u200c\u062e\u0648\u0627\u0647\u06cc\u062f \u062a\u0642\u0633\u06cc\u0645 \u06a9\u0646\u06cc\u062f.",
"Select the time zone for displaying course dates. If you do not specify a time zone, course dates, including assignment deadlines, will be displayed in your browser's local time zone.": "\u0645\u0646\u0637\u0642\u06c0 \u0632\u0645\u0627\u0646\u06cc \u0631\u0627 \u0628\u0631\u0627\u06cc \u0646\u0645\u0627\u06cc\u0634 \u062a\u0627\u0631\u06cc\u062e \u062f\u0648\u0631\u0647 \u0622\u0645\u0648\u0632\u0634\u06cc \u0627\u0646\u062a\u062e\u0627\u0628 \u06a9\u0646\u06cc\u062f. \u0627\u06af\u0631 \u0645\u0646\u0637\u0642\u06c0 \u0632\u0645\u0627\u0646\u06cc \u0631\u0627 \u0645\u0634\u062e\u0635 \u0646\u06a9\u0646\u06cc\u062f\u060c \u062a\u0627\u0631\u06cc\u062e \u062f\u0648\u0631\u0647\u200c\u0647\u0627\u060c \u0645\u0627\u0646\u0646\u062f \u0645\u0647\u0644\u062a \u0627\u0646\u062c\u0627\u0645 \u062a\u06a9\u0644\u06cc\u0641\u060c \u062f\u0631 \u0645\u0646\u0637\u0642\u06c0 \u0632\u0645\u0627\u0646\u06cc \u0645\u062d\u0644\u06cc \u0645\u0631\u0648\u0631\u06af\u0631 \u0634\u0645\u0627 \u0646\u0645\u0627\u06cc\u0634 \u062f\u0627\u062f\u0647 \u0645\u06cc\u200c\u0634\u0648\u062f.",
"Select turnaround": "\u0627\u0646\u062a\u062e\u0627\u0628 \u0686\u0631\u062e\u0634",
- "Selected blocks": "\u0628\u0644\u0648\u06a9\u200c\u0647\u0627\u06cc \u0645\u0646\u062a\u062e\u0628",
"Selected tab": "\u0632\u0628\u0627\u0646\u06c0 \u0628\u0631\u06af\u0632\u06cc\u062f\u0647",
"Self": "\u062e\u0648\u062f",
"Send to:": "\u0627\u0631\u0633\u0627\u0644 \u0628\u0647:",
@@ -1990,6 +1996,7 @@
"There is no email history for this course.": "\u0627\u06cc\u0646 \u062f\u0648\u0631\u0647 \u0622\u0645\u0648\u0632\u0634\u06cc\u060c \u0633\u0627\u0628\u0642\u0647 \u0627\u0631\u0633\u0627\u0644 \u0631\u0627\u06cc\u0627\u0646\u0627\u0645\u0647 \u0646\u062f\u0627\u0631\u062f.",
"There is no onboarding exam accessible to this user.": "\u0647\u06cc\u0686 \u0622\u0632\u0645\u0648\u0646 \u0622\u0632\u0645\u0627\u06cc\u0634\u06cc \u0628\u0631\u0627\u06cc \u0627\u06cc\u0646 \u06a9\u0627\u0631\u0628\u0631 \u0648\u062c\u0648\u062f \u0646\u062f\u0627\u0631\u062f.",
"There is no onboarding exam related to this course id.": "\u0647\u06cc\u0686 \u0622\u0632\u0645\u0648\u0646 \u0648\u0631\u0648\u062f\u06cc \u0645\u0631\u0628\u0648\u0637 \u0628\u0647 \u0627\u06cc\u0646 \u0634\u0646\u0627\u0633\u0647 \u062f\u0648\u0631\u0647 \u0622\u0645\u0648\u0632\u0634\u06cc \u0648\u062c\u0648\u062f \u0646\u062f\u0627\u0631\u062f.",
+ "There is still file upload in progress. Please wait until it is finished.": "\u0647\u0646\u0648\u0632 \u0622\u067e\u0644\u0648\u062f \u0641\u0627\u06cc\u0644 \u062f\u0631 \u062d\u0627\u0644 \u0627\u0646\u062c\u0627\u0645 \u0627\u0633\u062a. \u0644\u0637\u0641\u0627 \u0635\u0628\u0631 \u06a9\u0646\u06cc\u062f \u062a\u0627 \u062a\u0645\u0627\u0645 \u0634\u0648\u062f.",
"There must be at least one group.": "\u062d\u062f\u0627\u0642\u0644 \u06cc\u06a9 \u06af\u0631\u0648\u0647 \u0628\u0627\u06cc\u062f \u0648\u062c\u0648\u062f \u062f\u0627\u0634\u062a\u0647 \u0628\u0627\u0634\u062f.",
"There must be one cohort to which students can automatically be assigned.": "\u0628\u0627\u06cc\u062f \u06cc\u06a9 \u0647\u0645\u200c\u06af\u0631\u0648\u0647 \u0628\u0627\u0634\u062f \u06a9\u0647 \u0628\u062a\u0648\u0627\u0646 \u0628\u0647\u200c\u0637\u0648\u0631 \u062e\u0648\u062f\u06a9\u0627\u0631 \u06cc\u0627\u062f\u06af\u06cc\u0631\u0646\u062f\u06af\u0627\u0646 \u0631\u0627 \u0628\u0647 \u0622\u0646 \u0627\u062e\u062a\u0635\u0627\u0635 \u062f\u0647\u0646\u062f",
"There was a problem creating the report. Select \"Create Executive Summary\" to try again.": "\u0645\u0634\u06a9\u0644\u06cc \u062f\u0631 \u06af\u0632\u0627\u0631\u0634\u200c\u06af\u06cc\u0631\u06cc \u0648\u062c\u0648\u062f \u062f\u0627\u0634\u062a. \u0628\u0631\u0627\u06cc \u0633\u0627\u062e\u062a \u062f\u0648\u0628\u0627\u0631\u0647 \"\u062e\u0644\u0627\u0635\u06c0 \u0627\u062c\u0631\u0627\u06cc\u06cc \u0633\u0627\u062e\u062a\" \u0631\u0627 \u0627\u0646\u062a\u062e\u0627\u0628 \u06a9\u0646\u06cc\u062f.",
@@ -2054,7 +2061,6 @@
"This learner will be removed from the team,allowing another learner to take the available spot.": "\u0627\u06cc\u0646 \u0641\u0631\u062f \u0627\u0632 \u062a\u06cc\u0645 \u062d\u0630\u0641 \u062e\u0648\u0627\u0647\u062f \u0634\u062f \u0648 \u062f\u06cc\u06af\u0631\u06cc \u0627\u062c\u0627\u0632\u0647 \u0645\u06cc\u200c\u06cc\u0627\u0628\u062f \u062a\u0627 \u062c\u0627\u06cc \u0627\u0648 \u0631\u0627 \u0628\u06af\u06cc\u0631\u062f.",
"This link will open in a modal window": "\u0627\u06cc\u0646 \u067e\u06cc\u0648\u0646\u062f \u062f\u0631 \u06cc\u06a9 \u067e\u0646\u062c\u0631\u0647 \u0645\u0648\u062f\u0627\u0644 \u0628\u0627\u0632 \u062e\u0648\u0627\u0647\u062f \u0634\u062f",
"This link will open in a new browser window/tab": "\u0627\u06cc\u0646 \u067e\u06cc\u0648\u0646\u062f \u062f\u0631 \u06cc\u06a9 \u067e\u0646\u062c\u0631\u0647/ \u0632\u0628\u0627\u0646\u0647 \u0645\u0631\u0648\u0631\u06af\u0631 \u062c\u062f\u06cc\u062f \u0628\u0627\u0632 \u062e\u0648\u0627\u0647\u062f \u0634\u062f",
- "This may be happening because of an error with our server or your internet connection. Try refreshing the page or making sure you are online.": "\u0639\u0627\u0645\u0644 \u0627\u06cc\u0646 \u0627\u062a\u0641\u0627\u0642 \u0645\u0645\u06a9\u0646 \u0627\u0633\u062a \u0633\u0631\u0648\u0631 \u0645\u0627 \u06cc\u0627 \u0627\u062a\u0635\u0627\u0644 \u0634\u0645\u0627 \u0628\u0647 \u0627\u06cc\u0646\u062a\u0631\u0646\u062a \u0628\u0627\u0634\u062f. \u0628\u0627\u0631 \u062f\u06cc\u06af\u0631 \u0635\u0641\u062d\u0647 \u0631\u0627 \u0628\u0627\u0632 \u06a9\u0646\u06cc\u062f \u0648 \u06cc\u0627 \u0627\u0632 \u0627\u062a\u0635\u0627\u0644 \u0628\u0647 \u0627\u06cc\u0646\u062a\u0631\u0646\u062a \u0627\u0637\u0645\u06cc\u0646\u0627\u0646 \u062d\u0627\u0635\u0644 \u0646\u0645\u0627\u06cc\u06cc\u062f.",
"This page contains information about orders that you have placed with {platform_name}.": "\u0627\u06cc\u0646 \u0635\u0641\u062d\u0647 \u062d\u0627\u0648\u06cc \u0627\u0637\u0644\u0627\u0639\u0627\u062a\u06cc \u062f\u0631\u0628\u0627\u0631\u06c0 \u0633\u0641\u0627\u0631\u0634\u0627\u062a\u06cc \u0627\u0633\u062a \u06a9\u0647 \u0634\u0645\u0627 \u0628\u0627 {platform_name} \u062b\u0628\u062a \u06a9\u0631\u062f\u0647\u200c\u0627\u06cc\u062f.",
"This post could not be closed. Refresh the page and try again.": "\u0627\u06cc\u0646 \u0645\u0637\u0644\u0628 \u0627\u0631\u0633\u0627\u0644\u06cc \u0631\u0627 \u0646\u0645\u06cc\u200c\u062a\u0648\u0627\u0646 \u0628\u0633\u062a. \u0635\u0641\u062d\u0647 \u0631\u0627 \u062f\u0648\u0628\u0627\u0631\u0647 \u0628\u0627\u0631\u06af\u06cc\u0631\u06cc \u06a9\u0631\u062f\u0647 \u0648 \u0645\u062c\u062f\u062f \u062a\u0644\u0627\u0634 \u06a9\u0646\u06cc\u062f.",
"This post could not be flagged for abuse. Refresh the page and try again.": "\u0627\u06cc\u0646 \u0645\u0637\u0644\u0628 \u0627\u0631\u0633\u0627\u0644\u06cc \u0631\u0627 \u0646\u0645\u06cc\u200c\u062a\u0648\u0627\u0646 \u0628\u0647 \u062f\u0644\u06cc\u0644 \u0633\u0648\u0621\u0627\u0633\u062a\u0641\u0627\u062f\u0647 \u067e\u0631\u0686\u0645\u200c\u0622\u0630\u06cc\u0646 \u06a9\u0631\u062f. \u0635\u0641\u062d\u0647 \u0631\u0627 \u0631\u0648\u0632\u0622\u0645\u062f \u06a9\u0631\u062f\u0647 \u0648 \u062f\u0648\u0628\u0627\u0631\u0647 \u062a\u0644\u0627\u0634 \u06a9\u0646\u06cc\u062f.",
@@ -2159,7 +2165,6 @@
"Unable to load": "\u0642\u0627\u062f\u0631 \u0628\u0647 \u0628\u0627\u0631\u06af\u0630\u0627\u0631\u06cc \u0646\u06cc\u0633\u062a.",
"Unable to submit application": "\u0627\u0631\u0633\u0627\u0644 \u0628\u0631\u0646\u0627\u0645\u0647 \u0627\u0645\u06a9\u0627\u0646\u200c\u067e\u0630\u06cc\u0631 \u0646\u06cc\u0633\u062a",
"Unable to submit request to generate report.": "\u0627\u0631\u0633\u0627\u0644 \u062f\u0631\u062e\u0648\u0627\u0633\u062a \u0628\u0631\u0627\u06cc \u06af\u0632\u0627\u0631\u0634\u200c\u06af\u06cc\u0631\u06cc \u0627\u0645\u06a9\u0627\u0646\u200c\u067e\u0630\u06cc\u0631 \u0646\u06cc\u0633\u062a.",
- "Unable to update settings": "\u062a\u0646\u0638\u06cc\u0645\u0627\u062a \u0631\u0648\u0632\u0622\u0645\u062f \u0646\u0634\u062f",
"Underline": "\u062e\u0637 \u0632\u06cc\u0631",
"Undo": "\u0648\u0627\u06af\u0631\u062f",
"Undo (Ctrl+Z)": "\u0648\u0627\u06af\u0631\u062f (Ctrl+Z)",
diff --git a/lms/static/js/i18n/fa/djangojs.js b/lms/static/js/i18n/fa/djangojs.js
index a6fdba8dbe1c..ef7a945126da 100644
--- a/lms/static/js/i18n/fa/djangojs.js
+++ b/lms/static/js/i18n/fa/djangojs.js
@@ -467,6 +467,7 @@
"Cannot delete when in use by a unit": "\u0646\u0645\u06cc\u200c\u062a\u0648\u0627\u0646\u06cc\u062f \u0647\u0646\u06af\u0627\u0645 \u0627\u0633\u062a\u0641\u0627\u062f\u0647 \u062a\u0648\u0633\u0637 \u06cc\u06a9 \u0648\u0627\u062d\u062f\u060c \u0622\u0646 \u0631\u0627 \u062d\u0630\u0641 \u06a9\u0646\u06cc\u062f",
"Cannot delete when in use by an experiment": "\u0647\u0646\u06af\u0627\u0645\u06cc \u06a9\u0647 \u0627\u0632 \u0622\u0646 \u062f\u0631 \u062a\u062c\u0631\u0628\u0647\u200c\u0627\u06cc \u0627\u0633\u062a\u0641\u0627\u062f\u0647 \u0645\u06cc\u200c\u0634\u0648\u062f \u0627\u0645\u06a9\u0627\u0646 \u062d\u0630\u0641 \u0622\u0646 \u0646\u06cc\u0633\u062a",
"Cannot join instructor managed team": "\u0646\u0645\u06cc\u200c\u062a\u0648\u0627\u0646\u06cc\u062f \u0628\u0647 \u062a\u06cc\u0645\u06cc \u06a9\u0647 \u062a\u0648\u0633\u0637 \u0645\u0631\u0628\u06cc \u0645\u062f\u06cc\u0631\u06cc\u062a \u0645\u06cc\u200c\u0634\u0648\u062f \u0628\u067e\u06cc\u0648\u0646\u062f\u06cc\u062f",
+ "Cannot submit empty response even everything is optional.": "\u0646\u0645\u06cc \u062a\u0648\u0627\u0646 \u067e\u0627\u0633\u062e \u062e\u0627\u0644\u06cc \u0627\u0631\u0633\u0627\u0644 \u06a9\u0631\u062f \u062d\u062a\u06cc \u0647\u0645\u0647 \u0686\u06cc\u0632 \u0627\u062e\u062a\u06cc\u0627\u0631\u06cc \u0627\u0633\u062a.",
"Cannot update attempt review status": "\u0627\u0645\u06a9\u0627\u0646 \u0631\u0648\u0632\u0622\u0645\u062f\u0633\u0627\u0632\u06cc \u0648\u0636\u0639\u06cc\u062a \u062a\u0644\u0627\u0634 \u0628\u0631\u0631\u0633\u06cc \u0646\u06cc\u0633\u062a",
"Caption": " \u062a\u0648\u0636\u06cc\u062d",
"Caution: The last published version of this unit is live. By publishing changes you will change the student experience.": "\u0627\u062d\u062a\u06cc\u0627\u0637: \u0622\u062e\u0631\u06cc\u0646 \u0646\u0633\u062e\u06c0 \u0645\u0646\u062a\u0634\u0631\u0634\u062f\u06c0 \u0627\u06cc\u0646 \u0648\u0627\u062d\u062f \u067e\u062e\u0634 \u0632\u0646\u062f\u0647 \u0627\u0633\u062a. \u0628\u0627 \u0627\u0646\u062a\u0634\u0627\u0631 \u062a\u063a\u06cc\u06cc\u0631\u0627\u062a\u060c \u062a\u062c\u0631\u0628\u06c0 \u06cc\u0627\u062f\u06af\u06cc\u0631\u0646\u062f\u0647 \u0631\u0627 \u062a\u063a\u06cc\u06cc\u0631 \u062e\u0648\u0627\u0647\u06cc\u062f \u062f\u0627\u062f.",
@@ -757,6 +758,7 @@
"Draft (Never published)": "\u067e\u06cc\u0634\u200c\u0646\u0648\u06cc\u0633 (\u0647\u0631\u06af\u0632 \u0645\u0646\u062a\u0634\u0631\u0646\u0634\u062f\u0647)",
"Draft (Unpublished changes)": "\u067e\u06cc\u0634\u200c\u0646\u0648\u06cc\u0633 (\u062a\u063a\u06cc\u06cc\u0631\u0627\u062a \u0645\u0646\u062a\u0634\u0631\u0646\u0634\u062f\u0647)",
"Draft saved on {lastSavedStart}{editedOn}{lastSavedEnd} by {editedByStart}{editedBy}{editedByEnd}": "\u067e\u06cc\u0634\u200c\u0646\u0648\u06cc\u0633 \u0630\u062e\u06cc\u0631\u0647 \u0634\u062f\u0647 \u0627\u0633\u062a \u062f\u0631 {lastSavedStart}{editedOn}{lastSavedEnd} \u0628\u0647\u200c\u062f\u0633\u062a {editedByStart}{editedBy}{editedByEnd}",
+ "Draft saved!": "\u067e\u06cc\u0634 \u0646\u0648\u06cc\u0633 \u0630\u062e\u06cc\u0631\u0647 \u0634\u062f!",
"Drag and drop or {spanStart}browse your computer{spanEnd}.": "\u0628\u06a9\u0634 \u0648 \u0631\u0647\u0627\u06a9\u0646 \u06cc\u0627 {spanStart} \u0631\u0627\u06cc\u0627\u0646\u0647\u200c\u0627\u062a \u0631\u0627 \u0628\u0631\u0631\u0633\u06cc \u06a9\u0646 {spanEnd}.",
"Drag to reorder": "\u06a9\u0634\u06cc\u062f\u0646 \u0628\u0631\u0627\u06cc \u062a\u0631\u062a\u06cc\u0628 \u0645\u062c\u062f\u062f",
"Drop target image": "\u062a\u0635\u0648\u06cc\u0631 \u0647\u062f\u0641 \u0631\u0627 \u0631\u0647\u0627 \u06a9\u0646\u06cc\u062f",
@@ -1212,7 +1214,6 @@
"Loading more threads": "\u062f\u0631 \u062d\u0627\u0644 \u0628\u0627\u0631\u06af\u06cc\u0631\u06cc \u0645\u0648\u0636\u0648\u0639\u0627\u062a \u0628\u06cc\u0634\u062a\u0631",
"Loading posts list": "\u062f\u0631 \u062d\u0627\u0644 \u0628\u0627\u0631\u06af\u06cc\u0631\u06cc \u0641\u0647\u0631\u0633\u062a \u0645\u0637\u0627\u0644\u0628 \u0627\u0631\u0633\u0627\u0644\u06cc",
"Loading your courses": "\u062f\u0631 \u062d\u0627\u0644 \u0628\u0627\u0631\u06af\u06cc\u0631\u06cc \u062f\u0648\u0631\u0647\u200c\u0647\u0627\u06cc \u0634\u0645\u0627",
- "Loading...": "\u062f\u0631 \u062d\u0627\u0644 \u0628\u0627\u0631\u06af\u06cc\u0631\u06cc ...",
"Location": "\u0645\u06a9\u0627\u0646",
"Location in Course": "\u0645\u06a9\u0627\u0646 \u062f\u0631 \u062f\u0648\u0631\u0647 \u0622\u0645\u0648\u0632\u0634\u06cc",
"Lock this asset": "\u0642\u0641\u0644 \u0627\u06cc\u0646 \u0645\u0646\u0628\u0639",
@@ -1293,7 +1294,6 @@
"New Password": "\u06af\u0630\u0631\u0648\u0627\u0698\u06c0 \u062c\u062f\u06cc\u062f",
"New document": "\u0633\u0646\u062f \u062c\u062f\u06cc\u062f",
"New enrollment mode:": "\u0648\u0636\u0639\u06cc\u062a \u062a\u0627\u0632\u0647 \u062b\u0628\u062a\u200c\u0646\u0627\u0645:",
- "New files were added to this course's Files & Uploads": "\u0641\u0627\u06cc\u0644 \u0647\u0627\u06cc \u062c\u062f\u06cc\u062f \u0628\u0647 \"\u0641\u0627\u06cc\u0644 \u0647\u0627 \u0648 \u0622\u067e\u0644\u0648\u062f\u0647\u0627\"\u06cc \u0627\u06cc\u0646 \u062f\u0648\u0631\u0647 \u0627\u0636\u0627\u0641\u0647 \u0634\u062f",
"New window": "\u067e\u0646\u062c\u0631\u06c0 \u062c\u062f\u06cc\u062f",
"New {component_type}": "{component_type} \u062c\u062f\u06cc\u062f",
"Next": "\u0628\u0639\u062f\u06cc",
@@ -1309,6 +1309,7 @@
"No content-specific discussion topics exist.": "\u0647\u06cc\u0686 \u0645\u0628\u062d\u062b\u06cc \u0645\u0631\u0628\u0648\u0637 \u0628\u0647 \u0645\u062d\u062a\u0648\u0627\u06cc \u062e\u0627\u0635 \u0648\u062c\u0648\u062f \u0646\u062f\u0627\u0631\u062f.",
"No description available": "\u0628\u062f\u0648\u0646 \u0634\u0631\u062d",
"No exams in course {course_id}.": "\u0647\u06cc\u0686 \u0622\u0632\u0645\u0648\u0646\u06cc \u062f\u0631 \u062f\u0648\u0631\u0647 \u0622\u0645\u0648\u0632\u0634\u06cc {course_id} \u0648\u062c\u0648\u062f \u0646\u062f\u0627\u0631\u062f.",
+ "No files selected for upload.": "\u0647\u06cc\u0686 \u0641\u0627\u06cc\u0644\u06cc \u0628\u0631\u0627\u06cc \u0622\u067e\u0644\u0648\u062f \u0627\u0646\u062a\u062e\u0627\u0628 \u0646\u0634\u062f\u0647 \u0627\u0633\u062a.",
"No instructor dashboard for {proctor_service}": "\u0628\u062f\u0648\u0646 \u067e\u06cc\u0634\u062e\u0648\u0627\u0646 \u0622\u0645\u0648\u0632\u0634\u06cc \u0628\u0631\u0627\u06cc {proctor_service}",
"No onboarding status API for {proctor_service}": "API \u0648\u0636\u0639\u06cc\u062a \u0648\u0631\u0648\u062f \u0628\u0631\u0627\u06cc {proctor_service} \u0648\u062c\u0648\u062f \u0646\u062f\u0627\u0631\u062f",
"No posts matched your query.": "\u0647\u06cc\u0686 \u0645\u0637\u0644\u0628 \u0627\u0631\u0633\u0627\u0644\u06cc \u0628\u0627 \u062c\u0633\u062a\u062c\u0648\u06cc \u0634\u0645\u0627 \u0645\u0646\u0637\u0628\u0642 \u0646\u0628\u0648\u062f.",
@@ -1449,6 +1450,7 @@
"Please add the instructor's title": "\u0644\u0637\u0641\u0627\u064b \u0639\u0646\u0648\u0627\u0646 \u0645\u0631\u0628\u06cc \u0631\u0627 \u0628\u06cc\u0641\u0632\u0627\u06cc\u06cc\u062f",
"Please address the errors on this page first, and then save your progress.": "\u0644\u0637\u0641\u0627 \u0627\u0628\u062a\u062f\u0627 \u062e\u0637\u0627\u0647\u0627\u06cc \u0627\u06cc\u0646 \u0635\u0641\u062d\u0647 \u0631\u0627 \u0628\u0631\u0631\u0633\u06cc \u0648 \u0631\u0641\u0639 \u06a9\u0631\u062f\u0647 \u0633\u067e\u0633 \u0645\u06cc\u0632\u0627\u0646 \u067e\u06cc\u0634\u0631\u0641\u062a \u062e\u0648\u062f \u0631\u0627 \u0630\u062e\u06cc\u0631\u0647 \u06a9\u0646\u06cc\u062f. ",
"Please check the following validation feedbacks and reflect them in your course settings:": "\u0644\u0637\u0641\u0627\u064b \u0628\u0627\u0632\u062e\u0648\u0631\u062f\u0647\u0627\u06cc \u062a\u0623\u06cc\u06cc\u062f \u0627\u0639\u062a\u0628\u0627\u0631 \u0632\u06cc\u0631 \u0631\u0627 \u06a9\u0646\u062a\u0631\u0644 \u06a9\u0631\u062f\u0647 \u0648 \u0622\u0646\u200c\u0647\u0627 \u0631\u0627 \u062f\u0631 \u062a\u0646\u0638\u06cc\u0645\u0627\u062a \u062f\u0648\u0631\u06c0 \u0622\u0645\u0648\u0632\u0634\u06cc \u062e\u0648\u062f \u0645\u0646\u0639\u06a9\u0633 \u06a9\u0646\u06cc\u062f:",
+ "Please check your internet connection.": "\u0644\u0637\u0641\u0627 \u0627\u062a\u0635\u0627\u0644 \u0627\u06cc\u0646\u062a\u0631\u0646\u062a \u062e\u0648\u062f \u0631\u0627 \u0628\u0631\u0631\u0633\u06cc \u06a9\u0646\u06cc\u062f.",
"Please describe this image or agree that it has no contextual value by checking the checkbox.": "\u0644\u0637\u0641\u0627\u064b \u0627\u06cc\u0646 \u062a\u0635\u0648\u06cc\u0631 \u0631\u0627 \u062a\u0648\u0635\u06cc\u0641 \u06a9\u0646\u06cc\u062f \u06cc\u0627 \u0628\u0627 \u0632\u062f\u0646 \u0639\u0644\u0627\u0645\u062a \u062f\u0631 \u062e\u0627\u0646\u0647 \u06a9\u0646\u062a\u0631\u0644 \u0645\u0648\u0627\u0641\u0642\u062a \u06a9\u0646\u06cc\u062f \u06a9\u0647 \u0647\u06cc\u0686 \u0627\u0631\u0632\u0634 \u0645\u062a\u0646\u06cc \u0646\u062f\u0627\u0631\u062f. ",
"Please do not use any spaces in this field.": "\u0644\u0637\u0641\u0627 \u0627\u0632 \u0641\u0627\u0635\u0644\u0647 \u062f\u0631 \u0627\u06cc\u0646 \u0642\u0633\u0645\u062a \u0627\u0633\u062a\u0641\u0627\u062f\u0647 \u0646\u06a9\u0646\u06cc\u062f.",
"Please do not use any spaces or special characters in this field.": "\u0644\u0637\u0641\u0627 \u0627\u0632 \u0641\u0627\u0635\u0644\u0647 \u06cc\u0627 \u0646\u0648\u06cc\u0633\u0647\u200c\u0647\u0627\u06cc \u062e\u0627\u0635 \u062f\u0631 \u0627\u06cc\u0646 \u0642\u0633\u0645\u062a \u0627\u0633\u062a\u0641\u0627\u062f\u0647 \u0646\u06a9\u0646\u06cc\u062f.",
@@ -1469,12 +1471,15 @@
"Please fix the following errors:": "\u0644\u0637\u0641\u0627\u064b \u062e\u0637\u0627\u0647\u0627\u06cc \u0632\u06cc\u0631 \u0631\u0627 \u0627\u0635\u0644\u0627\u062d \u06a9\u0646\u06cc\u062f:",
"Please follow the instructions here to upload a file elsewhere and link to it: {maxFileSizeRedirectUrl}": "\u0644\u0637\u0641\u0627 \u0631\u0627\u0647\u0646\u0645\u0627\u06cc \u0632\u06cc\u0631 \u0631\u0627 \u0628\u0631\u0627\u06cc \u0686\u06af\u0648\u0646\u06af\u06cc \u0628\u0627\u0631\u06af\u0630\u0627\u0631\u06cc \u06cc\u06a9 \u0641\u0627\u06cc\u0644 \u062f\u0631 \u062c\u0627\u06cc\u06cc \u062f\u06cc\u06af\u0631 \u0648 \u06cc\u06a9 \u0627\u0631\u062a\u0628\u0627\u0637 \u0628\u0647 \u0622\u0646 \u0627\u06cc\u062c\u0627\u062f \u06a9\u0646\u06cc\u062f : {maxFileSizeRedirectUrl}",
"Please note: Deletion of your account and personal data is permanent and cannot be undone. {platformName} will not be able to recover your account or the data that is deleted.": "\u0644\u0637\u0641\u0627\u064b \u062a\u0648\u062c\u0647 \u062f\u0627\u0634\u062a\u0647 \u0628\u0627\u0634\u06cc\u062f: \u062d\u0633\u0627\u0628 \u06a9\u0627\u0631\u0628\u0631\u06cc \u0648 \u062f\u0627\u062f\u0647\u200c\u0647\u0627\u06cc \u0634\u062e\u0635\u06cc \u0634\u0645\u0627 \u0628\u0631\u0627\u06cc \u0647\u0645\u06cc\u0634\u0647 \u062d\u0630\u0641 \u062e\u0648\u0627\u0647\u062f \u0634\u062f \u0648 \u0642\u0627\u0628\u0644 \u0648\u0627\u06af\u0631\u062f \u0646\u06cc\u0633\u062a. \u067e\u0633 {platformName} \u0646\u0645\u06cc\u200c\u062a\u0648\u0627\u0646\u062f \u062d\u0633\u0627\u0628 \u06a9\u0627\u0631\u0628\u0631\u06cc \u0634\u0645\u0627 \u06cc\u0627 \u062f\u0627\u062f\u0647\u200c\u0647\u0627\u06cc \u062d\u0630\u0641\u200c\u0634\u062f\u0647 \u0631\u0627 \u0628\u0627\u0632\u06cc\u0627\u0628\u06cc \u06a9\u0646\u062f.",
+ "Please provide a description for each file you are uploading.": "\u0644\u0637\u0641\u0627\u064b \u062a\u0648\u0636\u06cc\u062d\u06cc \u0628\u0631\u0627\u06cc \u0647\u0631 \u0641\u0627\u06cc\u0644\u06cc \u06a9\u0647 \u0622\u067e\u0644\u0648\u062f \u0645\u06cc \u06a9\u0646\u06cc\u062f \u0627\u0631\u0627\u0626\u0647 \u062f\u0647\u06cc\u062f.",
"Please provide a description of the link destination.": "\u0644\u0637\u0641\u0627\u064b \u062a\u0648\u0636\u06cc\u062d\u06cc \u062f\u0631\u0628\u0627\u0631\u06c0 \u0645\u0642\u0635\u062f \u067e\u06cc\u0648\u0646\u062f \u0627\u0631\u0627\u0626\u0647 \u062f\u0647\u06cc\u062f.",
+ "Please provide a response.": "\u0644\u0637\u0641\u0627 \u067e\u0627\u0633\u062e \u062f\u0647\u06cc\u062f.",
"Please provide a valid URL.": "\u06cc\u06a9 \u0646\u0634\u0627\u0646\u06cc \u0627\u06cc\u0646\u062a\u0631\u0646\u062a\u06cc \u0645\u0639\u062a\u0628\u0631 \u0648\u0627\u0631\u062f \u06a9\u0646\u06cc\u062f.",
"Please re-enter your password.": "\u0644\u0637\u0641\u0627\u064b \u06af\u0630\u0631\u0648\u0627\u0698\u0647 \u0631\u0627 \u062f\u0648\u0628\u0627\u0631\u0647 \u0648\u0627\u0631\u062f \u06a9\u0646\u06cc\u062f.",
"Please select a PDF file to upload.": "\u0644\u0637\u0641\u0627 \u06cc\u06a9 \u067e\u0631\u0648\u0646\u062f\u0647 PDF \u0628\u0631\u0627\u06cc \u0628\u0627\u0631\u06af\u0630\u0627\u0631\u06cc \u0627\u0646\u062a\u062e\u0627\u0628 \u06a9\u0646\u06cc\u062f",
"Please select a file in .srt format.": "\u0644\u0637\u0641\u0627 \u06cc\u06a9 \u067e\u0631\u0648\u0646\u062f\u0647 \u0628\u0627 \u0642\u0627\u0644\u0628 srt. \u0628\u0631\u0627\u06cc \u0628\u0627\u0631\u06af\u0630\u0627\u0631\u06cc \u0627\u0646\u062a\u062e\u0627\u0628 \u06a9\u0646\u06cc\u062f.",
"Please specify a reason.": "\u0644\u0637\u0641\u0627\u064b \u06cc\u06a9 \u062f\u0644\u06cc\u0644 \u0630\u06a9\u0631 \u06a9\u0646\u06cc\u062f.",
+ "Please upload a file.": "\u0644\u0637\u0641\u0627 \u06cc\u06a9 \u0641\u0627\u06cc\u0644 \u0622\u067e\u0644\u0648\u062f \u06a9\u0646\u06cc\u062f",
"Please verify that you have uploaded a valid image (PNG and JPEG).": "\u0644\u0637\u0641\u0627\u064b \u062a\u0623\u06cc\u06cc\u062f \u06a9\u0646\u06cc\u062f \u06a9\u0647 \u062a\u0635\u0648\u06cc\u0631\u06cc \u0645\u0639\u062a\u0628\u0631 (PNG \u0648 JPEG) \u0628\u0627\u0631\u06af\u0630\u0627\u0631\u06cc \u06a9\u0631\u062f\u0647\u200c\u0627\u06cc\u062f.",
"Please verify that your webcam is connected and that you have allowed your browser to access it.": "\u0644\u0637\u0641\u0627\u064b \u0628\u0631\u0631\u0633\u06cc \u06a9\u0646\u06cc\u062f \u06a9\u0647 \u062f\u0648\u0631\u0628\u06cc\u0646 \u0631\u0627\u06cc\u0627\u0646\u06c0 \u0634\u0645\u0627 \u0645\u062a\u0635\u0644 \u0627\u0633\u062a \u0648 \u0628\u0647 \u0645\u0631\u0648\u0631\u06af\u0631 \u062e\u0648\u062f \u0627\u062c\u0627\u0632\u06c0 \u062f\u0633\u062a\u0631\u0633\u06cc \u0628\u0647 \u0622\u0646 \u0631\u0627 \u062f\u0627\u062f\u0647\u200c\u0627\u06cc\u062f.",
"Please wait": "\u0644\u0637\u0641\u0627 \u0634\u06a9\u06cc\u0628\u0627 \u0628\u0627\u0634\u06cc\u062f",
@@ -1650,6 +1655,8 @@
"Save changes": "\u0630\u062e\u06cc\u0631\u0647 \u062a\u063a\u06cc\u06cc\u0631\u0627\u062a",
"Saved cohort": "\u062f\u0633\u062a\u0647 \u0630\u062e\u06cc\u0631\u0647 \u0634\u062f\u0647 ",
"Saving": "\u062f\u0631 \u062d\u0627\u0644 \u0630\u062e\u06cc\u0631\u0647\u200c\u0633\u0627\u0632\u06cc",
+ "Saving draft": "\u0630\u062e\u06cc\u0631\u0647 \u067e\u06cc\u0634 \u0646\u0648\u06cc\u0633",
+ "Saving draft...": "\u062f\u0631 \u062d\u0627\u0644 \u0630\u062e\u06cc\u0631\u0647 \u067e\u06cc\u0634 \u0646\u0648\u06cc\u0633...",
"Saving your email preference": "\u062f\u0631 \u062d\u0627\u0644 \u0630\u062e\u06cc\u0631\u06c0 \u0631\u0627\u06cc\u0627\u0646\u0627\u0645\u0647 \u0645\u0631\u062c\u062d",
"Scheduled:": "\u0628\u0631\u0646\u0627\u0645\u0647\u200c\u0631\u06cc\u0632\u06cc\u200c\u0634\u062f\u0647:",
"Scope": "\u062f\u0627\u0645\u0646\u0647",
@@ -1691,7 +1698,6 @@
"Select the course-wide discussion topics that you want to divide.": "\u0645\u0628\u0627\u062d\u062b \u06af\u0641\u062a\u06af\u0648\u06cc \u0637\u0648\u0644 \u062f\u0648\u0631\u0647 \u0622\u0645\u0648\u0632\u0634\u06cc \u0631\u0627 \u0627\u0646\u062a\u062e\u0627\u0628 \u06a9\u0646\u06cc\u062f \u06a9\u0647 \u0645\u06cc\u200c\u062e\u0648\u0627\u0647\u06cc\u062f \u062a\u0642\u0633\u06cc\u0645 \u06a9\u0646\u06cc\u062f.",
"Select the time zone for displaying course dates. If you do not specify a time zone, course dates, including assignment deadlines, will be displayed in your browser's local time zone.": "\u0645\u0646\u0637\u0642\u06c0 \u0632\u0645\u0627\u0646\u06cc \u0631\u0627 \u0628\u0631\u0627\u06cc \u0646\u0645\u0627\u06cc\u0634 \u062a\u0627\u0631\u06cc\u062e \u062f\u0648\u0631\u0647 \u0622\u0645\u0648\u0632\u0634\u06cc \u0627\u0646\u062a\u062e\u0627\u0628 \u06a9\u0646\u06cc\u062f. \u0627\u06af\u0631 \u0645\u0646\u0637\u0642\u06c0 \u0632\u0645\u0627\u0646\u06cc \u0631\u0627 \u0645\u0634\u062e\u0635 \u0646\u06a9\u0646\u06cc\u062f\u060c \u062a\u0627\u0631\u06cc\u062e \u062f\u0648\u0631\u0647\u200c\u0647\u0627\u060c \u0645\u0627\u0646\u0646\u062f \u0645\u0647\u0644\u062a \u0627\u0646\u062c\u0627\u0645 \u062a\u06a9\u0644\u06cc\u0641\u060c \u062f\u0631 \u0645\u0646\u0637\u0642\u06c0 \u0632\u0645\u0627\u0646\u06cc \u0645\u062d\u0644\u06cc \u0645\u0631\u0648\u0631\u06af\u0631 \u0634\u0645\u0627 \u0646\u0645\u0627\u06cc\u0634 \u062f\u0627\u062f\u0647 \u0645\u06cc\u200c\u0634\u0648\u062f.",
"Select turnaround": "\u0627\u0646\u062a\u062e\u0627\u0628 \u0686\u0631\u062e\u0634",
- "Selected blocks": "\u0628\u0644\u0648\u06a9\u200c\u0647\u0627\u06cc \u0645\u0646\u062a\u062e\u0628",
"Selected tab": "\u0632\u0628\u0627\u0646\u06c0 \u0628\u0631\u06af\u0632\u06cc\u062f\u0647",
"Self": "\u062e\u0648\u062f",
"Send to:": "\u0627\u0631\u0633\u0627\u0644 \u0628\u0647:",
@@ -1990,6 +1996,7 @@
"There is no email history for this course.": "\u0627\u06cc\u0646 \u062f\u0648\u0631\u0647 \u0622\u0645\u0648\u0632\u0634\u06cc\u060c \u0633\u0627\u0628\u0642\u0647 \u0627\u0631\u0633\u0627\u0644 \u0631\u0627\u06cc\u0627\u0646\u0627\u0645\u0647 \u0646\u062f\u0627\u0631\u062f.",
"There is no onboarding exam accessible to this user.": "\u0647\u06cc\u0686 \u0622\u0632\u0645\u0648\u0646 \u0622\u0632\u0645\u0627\u06cc\u0634\u06cc \u0628\u0631\u0627\u06cc \u0627\u06cc\u0646 \u06a9\u0627\u0631\u0628\u0631 \u0648\u062c\u0648\u062f \u0646\u062f\u0627\u0631\u062f.",
"There is no onboarding exam related to this course id.": "\u0647\u06cc\u0686 \u0622\u0632\u0645\u0648\u0646 \u0648\u0631\u0648\u062f\u06cc \u0645\u0631\u0628\u0648\u0637 \u0628\u0647 \u0627\u06cc\u0646 \u0634\u0646\u0627\u0633\u0647 \u062f\u0648\u0631\u0647 \u0622\u0645\u0648\u0632\u0634\u06cc \u0648\u062c\u0648\u062f \u0646\u062f\u0627\u0631\u062f.",
+ "There is still file upload in progress. Please wait until it is finished.": "\u0647\u0646\u0648\u0632 \u0622\u067e\u0644\u0648\u062f \u0641\u0627\u06cc\u0644 \u062f\u0631 \u062d\u0627\u0644 \u0627\u0646\u062c\u0627\u0645 \u0627\u0633\u062a. \u0644\u0637\u0641\u0627 \u0635\u0628\u0631 \u06a9\u0646\u06cc\u062f \u062a\u0627 \u062a\u0645\u0627\u0645 \u0634\u0648\u062f.",
"There must be at least one group.": "\u062d\u062f\u0627\u0642\u0644 \u06cc\u06a9 \u06af\u0631\u0648\u0647 \u0628\u0627\u06cc\u062f \u0648\u062c\u0648\u062f \u062f\u0627\u0634\u062a\u0647 \u0628\u0627\u0634\u062f.",
"There must be one cohort to which students can automatically be assigned.": "\u0628\u0627\u06cc\u062f \u06cc\u06a9 \u0647\u0645\u200c\u06af\u0631\u0648\u0647 \u0628\u0627\u0634\u062f \u06a9\u0647 \u0628\u062a\u0648\u0627\u0646 \u0628\u0647\u200c\u0637\u0648\u0631 \u062e\u0648\u062f\u06a9\u0627\u0631 \u06cc\u0627\u062f\u06af\u06cc\u0631\u0646\u062f\u06af\u0627\u0646 \u0631\u0627 \u0628\u0647 \u0622\u0646 \u0627\u062e\u062a\u0635\u0627\u0635 \u062f\u0647\u0646\u062f",
"There was a problem creating the report. Select \"Create Executive Summary\" to try again.": "\u0645\u0634\u06a9\u0644\u06cc \u062f\u0631 \u06af\u0632\u0627\u0631\u0634\u200c\u06af\u06cc\u0631\u06cc \u0648\u062c\u0648\u062f \u062f\u0627\u0634\u062a. \u0628\u0631\u0627\u06cc \u0633\u0627\u062e\u062a \u062f\u0648\u0628\u0627\u0631\u0647 \"\u062e\u0644\u0627\u0635\u06c0 \u0627\u062c\u0631\u0627\u06cc\u06cc \u0633\u0627\u062e\u062a\" \u0631\u0627 \u0627\u0646\u062a\u062e\u0627\u0628 \u06a9\u0646\u06cc\u062f.",
@@ -2054,7 +2061,6 @@
"This learner will be removed from the team,allowing another learner to take the available spot.": "\u0627\u06cc\u0646 \u0641\u0631\u062f \u0627\u0632 \u062a\u06cc\u0645 \u062d\u0630\u0641 \u062e\u0648\u0627\u0647\u062f \u0634\u062f \u0648 \u062f\u06cc\u06af\u0631\u06cc \u0627\u062c\u0627\u0632\u0647 \u0645\u06cc\u200c\u06cc\u0627\u0628\u062f \u062a\u0627 \u062c\u0627\u06cc \u0627\u0648 \u0631\u0627 \u0628\u06af\u06cc\u0631\u062f.",
"This link will open in a modal window": "\u0627\u06cc\u0646 \u067e\u06cc\u0648\u0646\u062f \u062f\u0631 \u06cc\u06a9 \u067e\u0646\u062c\u0631\u0647 \u0645\u0648\u062f\u0627\u0644 \u0628\u0627\u0632 \u062e\u0648\u0627\u0647\u062f \u0634\u062f",
"This link will open in a new browser window/tab": "\u0627\u06cc\u0646 \u067e\u06cc\u0648\u0646\u062f \u062f\u0631 \u06cc\u06a9 \u067e\u0646\u062c\u0631\u0647/ \u0632\u0628\u0627\u0646\u0647 \u0645\u0631\u0648\u0631\u06af\u0631 \u062c\u062f\u06cc\u062f \u0628\u0627\u0632 \u062e\u0648\u0627\u0647\u062f \u0634\u062f",
- "This may be happening because of an error with our server or your internet connection. Try refreshing the page or making sure you are online.": "\u0639\u0627\u0645\u0644 \u0627\u06cc\u0646 \u0627\u062a\u0641\u0627\u0642 \u0645\u0645\u06a9\u0646 \u0627\u0633\u062a \u0633\u0631\u0648\u0631 \u0645\u0627 \u06cc\u0627 \u0627\u062a\u0635\u0627\u0644 \u0634\u0645\u0627 \u0628\u0647 \u0627\u06cc\u0646\u062a\u0631\u0646\u062a \u0628\u0627\u0634\u062f. \u0628\u0627\u0631 \u062f\u06cc\u06af\u0631 \u0635\u0641\u062d\u0647 \u0631\u0627 \u0628\u0627\u0632 \u06a9\u0646\u06cc\u062f \u0648 \u06cc\u0627 \u0627\u0632 \u0627\u062a\u0635\u0627\u0644 \u0628\u0647 \u0627\u06cc\u0646\u062a\u0631\u0646\u062a \u0627\u0637\u0645\u06cc\u0646\u0627\u0646 \u062d\u0627\u0635\u0644 \u0646\u0645\u0627\u06cc\u06cc\u062f.",
"This page contains information about orders that you have placed with {platform_name}.": "\u0627\u06cc\u0646 \u0635\u0641\u062d\u0647 \u062d\u0627\u0648\u06cc \u0627\u0637\u0644\u0627\u0639\u0627\u062a\u06cc \u062f\u0631\u0628\u0627\u0631\u06c0 \u0633\u0641\u0627\u0631\u0634\u0627\u062a\u06cc \u0627\u0633\u062a \u06a9\u0647 \u0634\u0645\u0627 \u0628\u0627 {platform_name} \u062b\u0628\u062a \u06a9\u0631\u062f\u0647\u200c\u0627\u06cc\u062f.",
"This post could not be closed. Refresh the page and try again.": "\u0627\u06cc\u0646 \u0645\u0637\u0644\u0628 \u0627\u0631\u0633\u0627\u0644\u06cc \u0631\u0627 \u0646\u0645\u06cc\u200c\u062a\u0648\u0627\u0646 \u0628\u0633\u062a. \u0635\u0641\u062d\u0647 \u0631\u0627 \u062f\u0648\u0628\u0627\u0631\u0647 \u0628\u0627\u0631\u06af\u06cc\u0631\u06cc \u06a9\u0631\u062f\u0647 \u0648 \u0645\u062c\u062f\u062f \u062a\u0644\u0627\u0634 \u06a9\u0646\u06cc\u062f.",
"This post could not be flagged for abuse. Refresh the page and try again.": "\u0627\u06cc\u0646 \u0645\u0637\u0644\u0628 \u0627\u0631\u0633\u0627\u0644\u06cc \u0631\u0627 \u0646\u0645\u06cc\u200c\u062a\u0648\u0627\u0646 \u0628\u0647 \u062f\u0644\u06cc\u0644 \u0633\u0648\u0621\u0627\u0633\u062a\u0641\u0627\u062f\u0647 \u067e\u0631\u0686\u0645\u200c\u0622\u0630\u06cc\u0646 \u06a9\u0631\u062f. \u0635\u0641\u062d\u0647 \u0631\u0627 \u0631\u0648\u0632\u0622\u0645\u062f \u06a9\u0631\u062f\u0647 \u0648 \u062f\u0648\u0628\u0627\u0631\u0647 \u062a\u0644\u0627\u0634 \u06a9\u0646\u06cc\u062f.",
@@ -2159,7 +2165,6 @@
"Unable to load": "\u0642\u0627\u062f\u0631 \u0628\u0647 \u0628\u0627\u0631\u06af\u0630\u0627\u0631\u06cc \u0646\u06cc\u0633\u062a.",
"Unable to submit application": "\u0627\u0631\u0633\u0627\u0644 \u0628\u0631\u0646\u0627\u0645\u0647 \u0627\u0645\u06a9\u0627\u0646\u200c\u067e\u0630\u06cc\u0631 \u0646\u06cc\u0633\u062a",
"Unable to submit request to generate report.": "\u0627\u0631\u0633\u0627\u0644 \u062f\u0631\u062e\u0648\u0627\u0633\u062a \u0628\u0631\u0627\u06cc \u06af\u0632\u0627\u0631\u0634\u200c\u06af\u06cc\u0631\u06cc \u0627\u0645\u06a9\u0627\u0646\u200c\u067e\u0630\u06cc\u0631 \u0646\u06cc\u0633\u062a.",
- "Unable to update settings": "\u062a\u0646\u0638\u06cc\u0645\u0627\u062a \u0631\u0648\u0632\u0622\u0645\u062f \u0646\u0634\u062f",
"Underline": "\u062e\u0637 \u0632\u06cc\u0631",
"Undo": "\u0648\u0627\u06af\u0631\u062f",
"Undo (Ctrl+Z)": "\u0648\u0627\u06af\u0631\u062f (Ctrl+Z)",
diff --git a/lms/static/js/i18n/fr/djangojs.js b/lms/static/js/i18n/fr/djangojs.js
index ce83d52a883b..07e5c92aa490 100644
--- a/lms/static/js/i18n/fr/djangojs.js
+++ b/lms/static/js/i18n/fr/djangojs.js
@@ -1981,7 +1981,6 @@
"This learner will be removed from the team,allowing another learner to take the available spot.": "Cet apprenant sera retir\u00e9 de l'\u00e9quipe, permettant \u00e0 un autre apprenant de prendre la place vacante.",
"This link will open in a modal window": "Ce lien s'ouvrira dans une nouvelle fen\u00eatre contextuelle",
"This link will open in a new browser window/tab": "Ce lien s'ouvrira dans une nouvelle fen\u00eatre ou onglet de votre navigateur",
- "This may be happening because of an error with our server or your internet connection. Try refreshing the page or making sure you are online.": "Cet incident vous affecte \u00e0 cause d'une erreur sur notre serveur ou d'un probl\u00e8me de votre connexion internet. Essayez de rafra\u00eechir la page ou v\u00e9rifiez que votre connexion est bien active.",
"This page contains information about orders that you have placed with {platform_name}.": "Cette page contient des informations \u00e0 propos des commandes que vous avez pass\u00e9s avec {platform_name}.",
"This post could not be closed. Refresh the page and try again.": "Ce message ne peut \u00eatre ferm\u00e9. Veuillez actualiser la page et essayer \u00e0 nouveau.",
"This post could not be flagged for abuse. Refresh the page and try again.": "Ce message ne peut pas \u00eatre d\u00e9nonc\u00e9 pour abus. Veuillez actualiser la page et essayer \u00e0 nouveau.",
@@ -2079,7 +2078,6 @@
"Unable to load": "Chargement impossible",
"Unable to submit application": "Impossible de soumettre votre demande",
"Unable to submit request to generate report.": "Impossible de soumettre la requ\u00eate de g\u00e9n\u00e9ration de rapport.",
- "Unable to update settings": "Impossible de mettre \u00e0 jours les param\u00e8tres",
"Underline": "Souligner",
"Undo": "Annule",
"Undo (Ctrl+Z)": "Annuler (Ctrl+Z)",
diff --git a/lms/static/js/i18n/it-it/djangojs.js b/lms/static/js/i18n/it-it/djangojs.js
index f5380a01817c..593a272bb9ff 100644
--- a/lms/static/js/i18n/it-it/djangojs.js
+++ b/lms/static/js/i18n/it-it/djangojs.js
@@ -1193,7 +1193,6 @@
"Loading more threads": "Carica ulteriori discussioni",
"Loading posts list": "Caricamento dell'elenco dei post ",
"Loading your courses": "Caricamento dei tuoi corsi",
- "Loading...": "Caricamento...",
"Location": "Posizione",
"Location in Course": "Posizione in corso",
"Lock this asset": "Blocca questa attivit\u00e0",
@@ -1652,7 +1651,6 @@
"Select the course-wide discussion topics that you want to divide.": "Selezionare gli argomenti di discussione a livello del corso che si desidera dividere. ",
"Select the time zone for displaying course dates. If you do not specify a time zone, course dates, including assignment deadlines, will be displayed in your browser's local time zone.": "Seleziona il fuso orario per la visualizzazione delle date dei corsi. Se non specifichi un fuso orario, le date dei corsi, comprese le scadenze dei compiti, verranno visualizzate nel fuso orario locale del tuo browser. ",
"Select turnaround": "Seleziona soluzione temporaneo",
- "Selected blocks": "Blocchi selezionati",
"Selected tab": "Tab selezionata",
"Self": "Autonomo ",
"Send to:": "Manda a:",
@@ -1999,7 +1997,6 @@
"This learner will be removed from the team,allowing another learner to take the available spot.": "Questo studente verr\u00e0 rimosso dal team, consentendo a un altro studente di prendere il posto disponibile. ",
"This link will open in a modal window": "Questo link verr\u00e0 aperto in una finestra modale",
"This link will open in a new browser window/tab": "Questo link verr\u00e0 aperto in una nuova finestra/tab del browser",
- "This may be happening because of an error with our server or your internet connection. Try refreshing the page or making sure you are online.": "L'errore pu\u00f2 essere conseguenza di un errore nei nostri server o nella tua connessione Internet. Prova a ricaricare la pagina e assicurati di essere online.",
"This page contains information about orders that you have placed with {platform_name}.": "Questa pagina contiene informazioni sugli ordini che hai effettuato con {platform_name}. ",
"This post could not be closed. Refresh the page and try again.": "Questo post non pu\u00f2 essere chiuso. Aggiorna la pagina e riprova. ",
"This post could not be flagged for abuse. Refresh the page and try again.": "Questo post non pu\u00f2 essere contrassegnato come abuso. Aggiorna la pagina e riprova. ",
@@ -2097,7 +2094,6 @@
"Unable to load": "Impossibile caricare ",
"Unable to submit application": "Impossibile inviare la domanda",
"Unable to submit request to generate report.": "Impossibile inviare la richiesta per generare il report. ",
- "Unable to update settings": "Impossibile aggiornare le impostazioni",
"Underline": "Sottolineato",
"Undo": "Annulla",
"Undo (Ctrl+Z)": "Annulla (Ctrl+Z)",
diff --git a/lms/static/js/i18n/pt-pt/djangojs.js b/lms/static/js/i18n/pt-pt/djangojs.js
index 53824407cca6..94101bc295e5 100644
--- a/lms/static/js/i18n/pt-pt/djangojs.js
+++ b/lms/static/js/i18n/pt-pt/djangojs.js
@@ -1196,7 +1196,6 @@
"Loading more threads": "A carregar mais t\u00f3picos",
"Loading posts list": "A carregar lista de publica\u00e7\u00f5es",
"Loading your courses": "Carregando os seus cursos",
- "Loading...": "A carregar...",
"Location": "Local",
"Location in Course": "Localiza\u00e7\u00e3o no Curso",
"Lock this asset": "Bloquear este ficheiro",
@@ -1657,7 +1656,6 @@
"Select the course-wide discussion topics that you want to divide.": "Selecionar os t\u00f3picos de debate de todo o curso que pretende dividir.",
"Select the time zone for displaying course dates. If you do not specify a time zone, course dates, including assignment deadlines, will be displayed in your browser's local time zone.": "Selecione o fuso hor\u00e1rio para exibir as datas do curso. Se n\u00e3o for especificado um fuso hor\u00e1rio, as datas do curso, incluindo os prazos de atribui\u00e7\u00e3o, ser\u00e3o exibidos no fuso hor\u00e1rio local do seu navegador.",
"Select turnaround": "Selecione uma alernativa",
- "Selected blocks": "Blocos selecionados",
"Selected tab": "Separador selecionado",
"Self": "Auto",
"Send to:": "Enviar para:",
@@ -2004,7 +2002,6 @@
"This learner will be removed from the team,allowing another learner to take the available spot.": "Este aluno ser\u00e1 removido da equipa, permitindo que outro aluno assuma a vaga dispon\u00edvel.",
"This link will open in a modal window": "Esta liga\u00e7\u00e3o abrir-se-\u00e1 numa janela modal",
"This link will open in a new browser window/tab": "Este link ir\u00e1 abrir numa nova janela/separador do navegador",
- "This may be happening because of an error with our server or your internet connection. Try refreshing the page or making sure you are online.": "Ocorreu este problema provavelmente devido a um erro com o nosso servidor ou com a sua liga\u00e7\u00e3o \u00e0 Internet. Atualize a p\u00e1gina ou certifique-se que est\u00e1 online.",
"This page contains information about orders that you have placed with {platform_name}.": "Esta p\u00e1gina cont\u00e9m informa\u00e7\u00f5es sobre os pedidos que efetuou com {platform_name}.",
"This post could not be closed. Refresh the page and try again.": "N\u00e3o foi poss\u00edvel fechar esta publica\u00e7\u00e3o. Atualize a p\u00e1gina e tente de novo.",
"This post could not be flagged for abuse. Refresh the page and try again.": "N\u00e3o foi poss\u00edvel marcar esta publica\u00e7\u00e3o como abusiva. Atualize a p\u00e1gina e tente de novo.",
@@ -2103,7 +2100,6 @@
"Unable to load": "N\u00e3o foi poss\u00edvel carregar",
"Unable to submit application": "Imposs\u00edvel apresentar a candidatura.",
"Unable to submit request to generate report.": "N\u00e3o \u00e9 poss\u00edvel submeter o pedido de cria\u00e7\u00e3o de relat\u00f3rio.",
- "Unable to update settings": "N\u00e3o \u00e9 poss\u00edvel atualizar configura\u00e7\u00f5es",
"Underline": "Sublinhar",
"Undo": "Desfazer",
"Undo (Ctrl+Z)": "Desfazer (Ctrl + Z)",
diff --git a/lms/static/js/i18n/rtl/djangojs.js b/lms/static/js/i18n/rtl/djangojs.js
index a14efcf87dbf..6917e187da01 100644
--- a/lms/static/js/i18n/rtl/djangojs.js
+++ b/lms/static/js/i18n/rtl/djangojs.js
@@ -571,6 +571,7 @@
"Discussion topics in the course are not divided.": "\u0110\u1d09s\u0254nss\u1d09\u00f8n \u0287\u00f8d\u1d09\u0254s \u1d09n \u0287\u0265\u01dd \u0254\u00f8n\u0279s\u01dd \u0250\u0279\u01dd n\u00f8\u0287 d\u1d09\u028c\u1d09d\u01ddd.",
"Discussions are unified; all learners interact with posts from other learners, regardless of the group they are in.": "\u0110\u1d09s\u0254nss\u1d09\u00f8ns \u0250\u0279\u01dd nn\u1d09\u025f\u1d09\u01ddd; \u0250ll l\u01dd\u0250\u0279n\u01dd\u0279s \u1d09n\u0287\u01dd\u0279\u0250\u0254\u0287 \u028d\u1d09\u0287\u0265 d\u00f8s\u0287s \u025f\u0279\u00f8\u026f \u00f8\u0287\u0265\u01dd\u0279 l\u01dd\u0250\u0279n\u01dd\u0279s, \u0279\u01dd\u0183\u0250\u0279dl\u01ddss \u00f8\u025f \u0287\u0265\u01dd \u0183\u0279\u00f8nd \u0287\u0265\u01dd\u028e \u0250\u0279\u01dd \u1d09n.",
"Discussions enabled": "\u0110\u1d09s\u0254nss\u1d09\u00f8ns \u01ddn\u0250bl\u01ddd",
+ "Dismiss": "\u0110\u1d09s\u026f\u1d09ss",
"Display Name": "\u0110\u1d09sdl\u0250\u028e N\u0250\u026f\u01dd",
"Div": "\u0110\u1d09\u028c",
"Divide the selected content-specific discussion topics": "\u0110\u1d09\u028c\u1d09d\u01dd \u0287\u0265\u01dd s\u01ddl\u01dd\u0254\u0287\u01ddd \u0254\u00f8n\u0287\u01ddn\u0287-sd\u01dd\u0254\u1d09\u025f\u1d09\u0254 d\u1d09s\u0254nss\u1d09\u00f8n \u0287\u00f8d\u1d09\u0254s",
@@ -1014,7 +1015,6 @@
"Loading more threads": "\u0141\u00f8\u0250d\u1d09n\u0183 \u026f\u00f8\u0279\u01dd \u0287\u0265\u0279\u01dd\u0250ds",
"Loading posts list": "\u0141\u00f8\u0250d\u1d09n\u0183 d\u00f8s\u0287s l\u1d09s\u0287",
"Loading your courses": "\u0141\u00f8\u0250d\u1d09n\u0183 \u028e\u00f8n\u0279 \u0254\u00f8n\u0279s\u01dds",
- "Loading...": "\u0141\u00f8\u0250d\u1d09n\u0183...",
"Location": "\u0141\u00f8\u0254\u0250\u0287\u1d09\u00f8n",
"Location in Course": "\u0141\u00f8\u0254\u0250\u0287\u1d09\u00f8n \u1d09n \u023b\u00f8n\u0279s\u01dd",
"Lock this asset": "\u0141\u00f8\u0254\u029e \u0287\u0265\u1d09s \u0250ss\u01dd\u0287",
@@ -1088,7 +1088,7 @@
"New Password": "N\u01dd\u028d \u2c63\u0250ss\u028d\u00f8\u0279d",
"New document": "N\u01dd\u028d d\u00f8\u0254n\u026f\u01ddn\u0287",
"New enrollment mode:": "N\u01dd\u028d \u01ddn\u0279\u00f8ll\u026f\u01ddn\u0287 \u026f\u00f8d\u01dd:",
- "New files were added to this course's Files & Uploads": "N\u01dd\u028d \u025f\u1d09l\u01dds \u028d\u01dd\u0279\u01dd \u0250dd\u01ddd \u0287\u00f8 \u0287\u0265\u1d09s \u0254\u00f8n\u0279s\u01dd's F\u1d09l\u01dds & \u0244dl\u00f8\u0250ds",
+ "New file(s) added to Files & Uploads.": "N\u01dd\u028d \u025f\u1d09l\u01dd(s) \u0250dd\u01ddd \u0287\u00f8 F\u1d09l\u01dds & \u0244dl\u00f8\u0250ds.",
"New window": "N\u01dd\u028d \u028d\u1d09nd\u00f8\u028d",
"New {component_type}": "N\u01dd\u028d {component_type}",
"Next": "N\u01ddx\u0287",
@@ -1435,7 +1435,6 @@
"Select the course-wide discussion topics that you want to divide.": "S\u01ddl\u01dd\u0254\u0287 \u0287\u0265\u01dd \u0254\u00f8n\u0279s\u01dd-\u028d\u1d09d\u01dd d\u1d09s\u0254nss\u1d09\u00f8n \u0287\u00f8d\u1d09\u0254s \u0287\u0265\u0250\u0287 \u028e\u00f8n \u028d\u0250n\u0287 \u0287\u00f8 d\u1d09\u028c\u1d09d\u01dd.",
"Select the time zone for displaying course dates. If you do not specify a time zone, course dates, including assignment deadlines, will be displayed in your browser's local time zone.": "S\u01ddl\u01dd\u0254\u0287 \u0287\u0265\u01dd \u0287\u1d09\u026f\u01dd z\u00f8n\u01dd \u025f\u00f8\u0279 d\u1d09sdl\u0250\u028e\u1d09n\u0183 \u0254\u00f8n\u0279s\u01dd d\u0250\u0287\u01dds. \u0197\u025f \u028e\u00f8n d\u00f8 n\u00f8\u0287 sd\u01dd\u0254\u1d09\u025f\u028e \u0250 \u0287\u1d09\u026f\u01dd z\u00f8n\u01dd, \u0254\u00f8n\u0279s\u01dd d\u0250\u0287\u01dds, \u1d09n\u0254lnd\u1d09n\u0183 \u0250ss\u1d09\u0183n\u026f\u01ddn\u0287 d\u01dd\u0250dl\u1d09n\u01dds, \u028d\u1d09ll b\u01dd d\u1d09sdl\u0250\u028e\u01ddd \u1d09n \u028e\u00f8n\u0279 b\u0279\u00f8\u028ds\u01dd\u0279's l\u00f8\u0254\u0250l \u0287\u1d09\u026f\u01dd z\u00f8n\u01dd.",
"Select turnaround": "S\u01ddl\u01dd\u0254\u0287 \u0287n\u0279n\u0250\u0279\u00f8nnd",
- "Selected blocks": "S\u01ddl\u01dd\u0254\u0287\u01ddd bl\u00f8\u0254\u029es",
"Selected tab": "S\u01ddl\u01dd\u0254\u0287\u01ddd \u0287\u0250b",
"Send to:": "S\u01ddnd \u0287\u00f8:",
"Sent By": "S\u01ddn\u0287 \u0243\u028e",
@@ -1859,7 +1858,6 @@
"Unable to get report generation status.": "\u0244n\u0250bl\u01dd \u0287\u00f8 \u0183\u01dd\u0287 \u0279\u01ddd\u00f8\u0279\u0287 \u0183\u01ddn\u01dd\u0279\u0250\u0287\u1d09\u00f8n s\u0287\u0250\u0287ns.",
"Unable to submit application": "\u0244n\u0250bl\u01dd \u0287\u00f8 snb\u026f\u1d09\u0287 \u0250ddl\u1d09\u0254\u0250\u0287\u1d09\u00f8n",
"Unable to submit request to generate report.": "\u0244n\u0250bl\u01dd \u0287\u00f8 snb\u026f\u1d09\u0287 \u0279\u01ddbn\u01dds\u0287 \u0287\u00f8 \u0183\u01ddn\u01dd\u0279\u0250\u0287\u01dd \u0279\u01ddd\u00f8\u0279\u0287.",
- "Unable to update settings": "\u0244n\u0250bl\u01dd \u0287\u00f8 ndd\u0250\u0287\u01dd s\u01dd\u0287\u0287\u1d09n\u0183s",
"Underline": "\u0244nd\u01dd\u0279l\u1d09n\u01dd",
"Undo": "\u0244nd\u00f8",
"Undo (Ctrl+Z)": "\u0244nd\u00f8 (\u023b\u0287\u0279l+\u01b5)",
@@ -2000,6 +1998,7 @@
"View all errors": "V\u1d09\u01dd\u028d \u0250ll \u01dd\u0279\u0279\u00f8\u0279s",
"View child items": "V\u1d09\u01dd\u028d \u0254\u0265\u1d09ld \u1d09\u0287\u01dd\u026fs",
"View discussion": "V\u1d09\u01dd\u028d d\u1d09s\u0254nss\u1d09\u00f8n",
+ "View files": "V\u1d09\u01dd\u028d \u025f\u1d09l\u01dds",
"View program": "V\u1d09\u01dd\u028d d\u0279\u00f8\u0183\u0279\u0250\u026f",
"View your receipts or modify your subscription on the {a_start}Orders and subscriptions{a_end} page": "V\u1d09\u01dd\u028d \u028e\u00f8n\u0279 \u0279\u01dd\u0254\u01dd\u1d09d\u0287s \u00f8\u0279 \u026f\u00f8d\u1d09\u025f\u028e \u028e\u00f8n\u0279 snbs\u0254\u0279\u1d09d\u0287\u1d09\u00f8n \u00f8n \u0287\u0265\u01dd {a_start}\u00d8\u0279d\u01dd\u0279s \u0250nd snbs\u0254\u0279\u1d09d\u0287\u1d09\u00f8ns{a_end} d\u0250\u0183\u01dd",
"View {span_start} {team_name} {span_end}": "V\u1d09\u01dd\u028d {span_start} {team_name} {span_end}",
diff --git a/lms/static/js/i18n/tr-tr/djangojs.js b/lms/static/js/i18n/tr-tr/djangojs.js
index f42eaa3300cd..2e3ec4546acb 100644
--- a/lms/static/js/i18n/tr-tr/djangojs.js
+++ b/lms/static/js/i18n/tr-tr/djangojs.js
@@ -1123,7 +1123,6 @@
"Loading more threads": "Daha fazla ileti dizisi y\u00fckl\u00fcyor",
"Loading posts list": "\u0130leti listesi y\u00fckleniyor",
"Loading your courses": "Dersleriniz y\u00fckleniyor",
- "Loading...": "Y\u00fckl\u00fcyor...",
"Location": "Yer",
"Location in Course": "Dersteki Konum",
"Lock this asset": "Bu veriyi kitle",
@@ -1578,7 +1577,6 @@
"Select prospective industry": "Hedef sekt\u00f6r\u00fc se\u00e7in",
"Select the course-wide discussion topics that you want to divide.": "B\u00f6lmek istedi\u011finiz ders-geneli tart\u0131\u015fma konular\u0131n\u0131 se\u00e7in.",
"Select the time zone for displaying course dates. If you do not specify a time zone, course dates, including assignment deadlines, will be displayed in your browser's local time zone.": "Ders tarihleri g\u00f6sterimi i\u00e7in saat dilimini se\u00e7in. Herhangi bir saat dilimini se\u00e7memeniz durumunda, g\u00f6rev teslimleri d\u00e2hil olmak \u00fczere t\u00fcm ders tarihleri, web taray\u0131c\u0131n\u0131z\u0131n yerel zaman\u0131na g\u00f6re g\u00f6sterilecektir. ",
- "Selected blocks": "Se\u00e7ili blocklar",
"Selected tab": "Se\u00e7ili sekme",
"Self": "Kendin",
"Send to:": "G\u00f6nderilecek ki\u015fi:",
@@ -1926,7 +1924,6 @@
"This learner will be removed from the team,allowing another learner to take the available spot.": "Bu \u00f6\u011frenci tak\u0131mdan \u00e7\u0131kar\u0131lacak ve ba\u015fka bir \u00f6\u011frencinin uygun yeri almas\u0131na izin verilecektir.",
"This link will open in a modal window": "Bu ba\u011flant\u0131 yeni bir kip penceresinde a\u00e7\u0131lacak",
"This link will open in a new browser window/tab": "Bu ba\u011flant\u0131 taray\u0131c\u0131da yeni bir pencere veya sekmede a\u00e7\u0131lacak",
- "This may be happening because of an error with our server or your internet connection. Try refreshing the page or making sure you are online.": "Bu durum sunucudaki bir hatadan veya \u0130nternet ba\u011flant\u0131n\u0131zdan kaynaklanm\u0131\u015f olabilir. Sayfay\u0131 yeniden y\u00fcklemeyi deneyin veya \u00e7evrimi\u00e7i oldu\u011funuza emin olun.",
"This page contains information about orders that you have placed with {platform_name}.": "Bu sayfa {platform_name} i\u00e7inde verdi\u011finiz sipari\u015fleriniz hakk\u0131nda bilgileri i\u00e7erir.",
"This post could not be closed. Refresh the page and try again.": "Bu g\u00f6nderi kapat\u0131lamaz. Sayfay\u0131 yenileyin ve tekrar deneyin.",
"This post could not be flagged for abuse. Refresh the page and try again.": "Bu g\u00f6nderiye taciz i\u015faretlemesi yap\u0131lamaz. Sayfay\u0131 yenileyin ve tekrar deneyin.",
@@ -2024,7 +2021,6 @@
"Unable to load": "Y\u00fcklenemedi",
"Unable to submit application": "Ba\u015fvuru g\u00f6nderilemedi",
"Unable to submit request to generate report.": "Rapor olu\u015fturma iste\u011fi g\u00f6nderilemedi.",
- "Unable to update settings": "Ayarlar g\u00fcncellenemedi",
"Underline": "Alt \u00e7izgi",
"Undo": "Geri",
"Undo (Ctrl+Z)": "Geri al (Ctrl-Z)",
diff --git a/lms/static/js/i18n/zh-cn/djangojs.js b/lms/static/js/i18n/zh-cn/djangojs.js
index 3d5621e10f00..57038f3be2f7 100644
--- a/lms/static/js/i18n/zh-cn/djangojs.js
+++ b/lms/static/js/i18n/zh-cn/djangojs.js
@@ -969,7 +969,6 @@
"Loading more threads": "\u8f7d\u5165\u66f4\u591a\u7684\u4e3b\u9898",
"Loading posts list": "\u6b63\u5728\u52a0\u8f7d\u5e16\u5b50\u5217\u8868",
"Loading your courses": "\u6b63\u5728\u52a0\u8f7d\u60a8\u7684\u8bfe\u7a0b",
- "Loading...": "\u8f7d\u5165\u4e2d...",
"Location": "\u4f4d\u7f6e",
"Location in Course": "\u8bfe\u7a0b\u4e2d\u7684\u4f4d\u7f6e",
"Lock this asset": "\u9501\u5b9a\u8be5\u8d44\u6e90",
@@ -1361,7 +1360,6 @@
"Select the course-wide discussion topics that you want to divide.": "\u9009\u62e9\u60a8\u60f3\u8981\u533a\u5206\u7684\u8bfe\u7a0b\u8303\u56f4\u5185\u7684\u8ba8\u8bba\u4e3b\u9898\u3002",
"Select the time zone for displaying course dates. If you do not specify a time zone, course dates, including assignment deadlines, will be displayed in your browser's local time zone.": "\u8bf7\u9009\u62e9\u7528\u4e8e\u663e\u793a\u8bfe\u7a0b\u65e5\u671f\u7684\u65f6\u533a\u3002\u5982\u679c\u60a8\u4e0d\u8bbe\u7f6e\u65f6\u533a\uff0c\u90a3\u4e48\u5982\u4f5c\u4e1a\u622a\u6b62\u65e5\u671f\u7b49\u8bfe\u7a0b\u65e5\u671f\u4fe1\u606f\u5c06\u6839\u636e\u60a8\u6d4f\u89c8\u5668\u7684\u672c\u5730\u65f6\u533a\u663e\u793a\u3002",
"Select turnaround": "\u9009\u62e9\u8f6c\u6362",
- "Selected blocks": "\u9009\u4e2d\u7684\u5757",
"Selected tab": "\u9009\u4e2d\u7684\u6807\u7b7e",
"Self": "\u81ea\u5df1",
"Send to:": "\u53d1\u81f3\uff1a",
@@ -1677,7 +1675,6 @@
"This learner will be removed from the team,allowing another learner to take the available spot.": "\u6b64\u6210\u5458\u5c06\u4f1a\u4ece\u8fd9\u4e2a\u961f\u4f0d\u79fb\u9664\u4ee5\u4fbf\u4e3a\u5176\u4ed6\u6210\u5458\u63d0\u4f9b\u7a7a\u4f59\u540d\u989d\u3002",
"This link will open in a modal window": "\u8be5\u94fe\u63a5\u5c06\u5728\u6a21\u5f0f\u7a97\u53e3\u4e2d\u6253\u5f00",
"This link will open in a new browser window/tab": "\u8be5\u94fe\u63a5\u5c06\u5728\u65b0\u6d4f\u89c8\u5668\u7a97\u53e3/\u6807\u7b7e\u9875\u4e2d\u6253\u5f00",
- "This may be happening because of an error with our server or your internet connection. Try refreshing the page or making sure you are online.": "\u6b64\u60c5\u51b5\u53ef\u80fd\u7531\u4e8e\u670d\u52a1\u5668\u9519\u8bef\u6216\u8005\u60a8\u7684\u7f51\u7edc\u8fde\u63a5\u9519\u8bef\u5bfc\u81f4\u3002\u5c1d\u8bd5\u5237\u65b0\u9875\u9762\u6216\u8005\u786e\u4fdd\u7f51\u7edc\u7545\u901a\u3002",
"This page contains information about orders that you have placed with {platform_name}.": "\u6b64\u9875\u9762\u5305\u542b\u60a8\u5728{platform_name}\u6240\u4e0b\u7684\u8ba2\u5355\u4fe1\u606f\u3002",
"This post could not be closed. Refresh the page and try again.": "\u65e0\u6cd5\u5173\u95ed\u6b64\u5e16\u5b50\uff0c\u8bf7\u5237\u65b0\u9875\u9762\u5e76\u91cd\u8bd5\u3002",
"This post could not be flagged for abuse. Refresh the page and try again.": "\u65e0\u6cd5\u5c06\u6b64\u5e16\u5b50\u4e3e\u62a5\u4e3a\u6ee5\u7528\uff0c\u8bf7\u5237\u65b0\u9875\u9762\u5e76\u91cd\u8bd5\u3002",
@@ -1759,7 +1756,6 @@
"Unable to determine whether we should give you a refund because of System Error. Please try again later.": "\u7cfb\u7edf\u53d1\u751f\u9519\u8bef\uff0c\u65e0\u6cd5\u5224\u65ad\u662f\u5426\u5e94\u7ed9\u60a8\u9000\u6b3e\uff0c\u8bf7\u7a0d\u540e\u91cd\u8bd5\u3002",
"Unable to load": "\u4e0d\u80fd\u52a0\u8f7d",
"Unable to submit application": "\u65e0\u6cd5\u63d0\u4ea4\u7533\u8bf7",
- "Unable to update settings": "\u65e0\u6cd5\u66f4\u65b0\u8bbe\u7f6e",
"Underline": "\u4e0b\u5212\u7ebf",
"Undo": "\u64a4\u9500",
"Undo (Ctrl+Z)": "\u64a4\u9500(Ctrl+Z)",
diff --git a/lms/static/lms/js/require-config.js b/lms/static/lms/js/require-config.js
index c385d2cba329..f6a807bc57f6 100644
--- a/lms/static/lms/js/require-config.js
+++ b/lms/static/lms/js/require-config.js
@@ -226,6 +226,11 @@
'hls': {
exports: 'Hls'
}
+ },
+ config: {
+ text: {
+ useXhr: () => true
+ }
}
});
}).call(this, require || RequireJS.require, define || RequireJS.define);
diff --git a/openedx/core/djangoapps/content/learning_sequences/api/outlines.py b/openedx/core/djangoapps/content/learning_sequences/api/outlines.py
index 800b085e5000..9af14d6140ef 100644
--- a/openedx/core/djangoapps/content/learning_sequences/api/outlines.py
+++ b/openedx/core/djangoapps/content/learning_sequences/api/outlines.py
@@ -40,6 +40,7 @@
UserPartitionGroup
)
from .permissions import can_see_all_content
+from .processors.cohort_partition_groups import CohortPartitionGroupsOutlineProcessor
from .processors.content_gating import ContentGatingOutlineProcessor
from .processors.enrollment import EnrollmentOutlineProcessor
from .processors.enrollment_track_partition_groups import EnrollmentTrackPartitionGroupsOutlineProcessor
@@ -328,6 +329,7 @@ def _get_user_course_outline_and_processors(course_key: CourseKey, # lint-amnes
('visibility', VisibilityOutlineProcessor),
('enrollment', EnrollmentOutlineProcessor),
('enrollment_track_partitions', EnrollmentTrackPartitionGroupsOutlineProcessor),
+ ('cohorts_partitions', CohortPartitionGroupsOutlineProcessor),
]
# Run each OutlineProcessor in order to figure out what items we have to
diff --git a/openedx/core/djangoapps/content/learning_sequences/api/processors/cohort_partition_groups.py b/openedx/core/djangoapps/content/learning_sequences/api/processors/cohort_partition_groups.py
new file mode 100644
index 000000000000..fa921902c833
--- /dev/null
+++ b/openedx/core/djangoapps/content/learning_sequences/api/processors/cohort_partition_groups.py
@@ -0,0 +1,88 @@
+# lint-amnesty, pylint: disable=missing-module-docstring
+import logging
+from datetime import datetime
+from typing import Union
+
+from opaque_keys.edx.keys import CourseKey
+
+from openedx.core import types
+from openedx.core.djangoapps.course_groups.cohorts import (
+ get_cohort,
+ get_cohorted_user_partition_id,
+ get_group_info_for_cohort,
+)
+
+from .base import OutlineProcessor
+
+log = logging.getLogger(__name__)
+
+
+class CohortPartitionGroupsOutlineProcessor(OutlineProcessor):
+ """
+ Processor for applying cohort user partition groups.
+
+ """
+ def __init__(self, course_key: CourseKey, user: types.User, at_time: datetime):
+ super().__init__(course_key, user, at_time)
+ self.user_cohort_group_id: Union[int, None] = None
+ self.cohorted_partition_id: Union[int, None] = None
+
+ def load_data(self, full_course_outline) -> None:
+ """
+ Load the cohorted partition id and the user's group id.
+ """
+
+ # It is possible that a cohort is not linked to any content group/partition.
+ # This is why the cohorted_partition_id needs to be set independently
+ # of a particular user's cohort.
+ self.cohorted_partition_id = get_cohorted_user_partition_id(self.course_key)
+
+ if self.cohorted_partition_id:
+ user_cohort = get_cohort(self.user, self.course_key)
+
+ if user_cohort:
+ self.user_cohort_group_id, _ = get_group_info_for_cohort(user_cohort)
+
+ def _is_user_excluded_by_partition_group(self, user_partition_groups) -> bool:
+ """
+ Is the user part of the group to which the block is restricting content?
+ """
+ if not user_partition_groups:
+ return False
+
+ groups = user_partition_groups.get(self.cohorted_partition_id)
+ if not groups:
+ return False
+
+ if self.user_cohort_group_id not in groups:
+ # If the user's group (cohort) does not belong
+ # to the partition of the block or the user's cohort
+ # is not linked to a content group (user_cohort_group_id is None),
+ # the block should be removed
+ return True
+ return False
+
+ def usage_keys_to_remove(self, full_course_outline):
+ """
+ Content group exclusions remove the content entirely.
+
+ Remove sections and sequences inacessible by the user's
+ cohort.
+ """
+ if not self.cohorted_partition_id:
+ return frozenset()
+
+ removed_usage_keys = set()
+ for section in full_course_outline.sections:
+ remove_all_children = False
+ if self._is_user_excluded_by_partition_group(
+ section.user_partition_groups
+ ):
+ removed_usage_keys.add(section.usage_key)
+ remove_all_children = True
+ for seq in section.sequences:
+ if remove_all_children or self._is_user_excluded_by_partition_group(
+ seq.user_partition_groups
+ ):
+ removed_usage_keys.add(seq.usage_key)
+ return removed_usage_keys
diff --git a/openedx/core/djangoapps/content/learning_sequences/api/tests/test_outlines.py b/openedx/core/djangoapps/content/learning_sequences/api/tests/test_outlines.py
index 805066d1d6db..61ba39954b30 100644
--- a/openedx/core/djangoapps/content/learning_sequences/api/tests/test_outlines.py
+++ b/openedx/core/djangoapps/content/learning_sequences/api/tests/test_outlines.py
@@ -19,6 +19,8 @@
import pytest
from openedx.core.djangoapps.course_apps.toggles import EXAMS_IDA
+from openedx.core.djangoapps.course_groups.models import CourseCohortsSettings, CourseUserGroupPartitionGroup
+from openedx.core.djangoapps.course_groups.tests.helpers import CohortFactory
from openedx.core.djangolib.testing.utils import CacheIsolationTestCase
from openedx.features.course_experience import COURSE_ENABLE_UNENROLLED_ACCESS_FLAG
from common.djangoapps.course_modes.models import CourseMode
@@ -1717,6 +1719,190 @@ def test_processor_only(
assert len(removed_usage_keys) == expected_values_dict[learner_to_verify.username]
+@ddt.ddt
+class CohortPartitionGroupsTestCase(OutlineProcessorTestCase):
+ """Tests for cohort partitions outline processor that affects outlines"""
+
+ @classmethod
+ def setUpTestData(cls):
+ super().setUpTestData()
+ cls.visibility = VisibilityData(
+ hide_from_toc=False,
+ visible_to_staff_only=False
+ )
+
+ def _create_and_enroll_learner(self, username, is_staff=False):
+ """
+ Helper function to create the learner based on the username,
+ then enroll the learner into the test course with VERIFIED
+ mode.
+ Returns the created learner
+ """
+ learner = UserFactory.create(
+ username=username, email='{}@example.com'.format(username), is_staff=is_staff
+ )
+ learner.courseenrollment_set.create(course_id=self.course_key, is_active=True, mode=CourseMode.VERIFIED)
+ return learner
+
+ def _setup_course_outline_with_sections(
+ self,
+ course_sections,
+ course_start_date=datetime(2021, 3, 26, tzinfo=timezone.utc)
+ ):
+ """
+ Helper function to update the course outline under test with
+ the course sections passed in.
+ Returns the newly constructed course outline
+ """
+ set_dates_for_course(
+ self.course_key,
+ [
+ (
+ self.course_key.make_usage_key('course', 'course'),
+ {'start': course_start_date}
+ )
+ ]
+ )
+
+ new_outline = CourseOutlineData(
+ course_key=self.course_key,
+ title="Cohort User Partition Test Course",
+ published_at=course_start_date,
+ published_version="8ebece4b69dd593d82fe2023",
+ sections=course_sections,
+ self_paced=False,
+ days_early_for_beta=None,
+ entrance_exam_id=None,
+ course_visibility=CourseVisibility.PRIVATE,
+ )
+
+ replace_course_outline(new_outline)
+
+ return new_outline
+
+ @ddt.data(
+ (
+ None,
+ None,
+ ['student1', 'student2'],
+ {'student1': 1, 'student2': 1}
+ ),
+ (
+ set([1001]),
+ None,
+ ['student1', 'student2'],
+ {'student1': 1, 'student2': 0}
+ ),
+ (
+ set([1002]),
+ None,
+ ['student1', 'student2'],
+ {'student1': 0, 'student2': 1}
+ ),
+ (
+ set([1001, 1002]),
+ None,
+ ['student1', 'student2'],
+ {'student1': 1, 'student2': 1}
+ ),
+ (
+ None,
+ set([1001]),
+ ['student1', 'student2'],
+ {'student1': 1, 'student2': 0}
+ ),
+ (
+ None,
+ set([1002]),
+ ['student1', 'student2'],
+ {'student1': 0, 'student2': 1}
+ ),
+ (
+ None,
+ set([1001, 1002]),
+ ['student1', 'student2'],
+ {'student1': 1, 'student2': 1}
+ ),
+ )
+ @ddt.unpack
+ def test_cohort_partition_on_outline(
+ self,
+ section_visible_groups,
+ sequence_visible_groups,
+ learners,
+ expected_values_dict
+ ):
+
+ section_user_partition_groups = None
+ sequence_user_partition_groups = None
+ if section_visible_groups:
+ section_user_partition_groups = {
+ 1000: frozenset(section_visible_groups)
+ }
+ if sequence_visible_groups:
+ sequence_user_partition_groups = {
+ 1000: frozenset(sequence_visible_groups)
+ }
+
+ CourseCohortsSettings.objects.create(course_id=self.course_key, is_cohorted=True)
+
+ # Enroll students in the course
+ learners_to_verify = []
+ for username in learners:
+ learners_to_verify.append(
+ self._create_and_enroll_learner(username)
+ )
+
+ # Create cohorts and corresponding GroupPartitions
+ cohort_1 = CohortFactory(
+ course_id=self.course_key,
+ name='Test Cohort 1',
+ users=[learners_to_verify[0]]
+ )
+
+ CourseUserGroupPartitionGroup(
+ course_user_group=cohort_1,
+ partition_id=1000,
+ group_id=1001
+ ).save()
+
+ cohort_2 = CohortFactory(
+ course_id=self.course_key,
+ name='Test Cohort 2',
+ users=[learners_to_verify[1]]
+ )
+
+ CourseUserGroupPartitionGroup(
+ course_user_group=cohort_2,
+ partition_id=1000,
+ group_id=1002
+ ).save()
+
+ self._setup_course_outline_with_sections(
+ [
+ CourseSectionData(
+ usage_key=self.course_key.make_usage_key('chapter', '0'),
+ title="Section 0",
+ user_partition_groups=section_user_partition_groups,
+ sequences=[
+ CourseLearningSequenceData(
+ usage_key=self.course_key.make_usage_key('subsection', '0'),
+ title='Subsection 0',
+ visibility=self.visibility,
+ user_partition_groups=sequence_user_partition_groups,
+ ),
+ ]
+ )
+ ]
+ )
+
+ check_date = datetime(2021, 3, 27, tzinfo=timezone.utc)
+
+ for learner_to_verify in learners_to_verify:
+ learner_details = get_user_course_outline_details(self.course_key, learner_to_verify, check_date)
+ assert len(learner_details.outline.accessible_sequences) == expected_values_dict[learner_to_verify.username]
+
+
class ContentErrorTestCase(CacheIsolationTestCase):
"""Test error collection and reporting."""
diff --git a/openedx/core/djangoapps/content/learning_sequences/data.py b/openedx/core/djangoapps/content/learning_sequences/data.py
index d7b706bb431a..c13b451490ab 100644
--- a/openedx/core/djangoapps/content/learning_sequences/data.py
+++ b/openedx/core/djangoapps/content/learning_sequences/data.py
@@ -250,10 +250,16 @@ def remove(self, usage_keys):
"""
keys_to_remove = set(usage_keys)
- # If we remove a Section, we also remove all Sequences in that Section.
for section in self.sections:
+ section_sequences_keys = {seq.usage_key for seq in section.sequences}
+
+ # If we remove a Section, we also remove all Sequences in that Section.
if section.usage_key in keys_to_remove:
- keys_to_remove |= {seq.usage_key for seq in section.sequences}
+ keys_to_remove |= section_sequences_keys
+
+ # If a Section is empty or about to be, we remove it.
+ elif section_sequences_keys.issubset(keys_to_remove):
+ keys_to_remove.add(section.usage_key)
return attr.evolve(
self,
diff --git a/openedx/core/djangoapps/content_libraries/tests/test_content_libraries.py b/openedx/core/djangoapps/content_libraries/tests/test_content_libraries.py
index 693082c35a6b..42d5bccf3442 100644
--- a/openedx/core/djangoapps/content_libraries/tests/test_content_libraries.py
+++ b/openedx/core/djangoapps/content_libraries/tests/test_content_libraries.py
@@ -313,7 +313,7 @@ def test_library_blocks(self):
block_data = self._add_block_to_library(lib_id, "problem", "problem1")
self.assertDictContainsEntries(block_data, {
"id": "lb:CL-TEST:testlib1:problem:problem1",
- "display_name": "Blank Advanced Problem",
+ "display_name": "Blank Problem",
"block_type": "problem",
"has_unpublished_changes": True,
})
diff --git a/openedx/core/djangoapps/content_staging/tasks.py b/openedx/core/djangoapps/content_staging/tasks.py
index 9df79a9a7e87..951a6f0a645d 100644
--- a/openedx/core/djangoapps/content_staging/tasks.py
+++ b/openedx/core/djangoapps/content_staging/tasks.py
@@ -6,6 +6,7 @@
from celery import shared_task
from celery_utils.logged_task import LoggedTask
+from edx_django_utils.monitoring import set_code_owner_attribute
from .data import CLIPBOARD_PURPOSE
from .models import StagedContent
@@ -14,6 +15,7 @@
@shared_task(base=LoggedTask)
+@set_code_owner_attribute
def delete_expired_clipboards(staged_content_ids: list[int]):
"""
A Celery task to delete StagedContent clipboard entries that are no longer
diff --git a/openedx/features/content_tagging/__init__.py b/openedx/core/djangoapps/content_tagging/__init__.py
similarity index 100%
rename from openedx/features/content_tagging/__init__.py
rename to openedx/core/djangoapps/content_tagging/__init__.py
diff --git a/openedx/features/content_tagging/admin.py b/openedx/core/djangoapps/content_tagging/admin.py
similarity index 100%
rename from openedx/features/content_tagging/admin.py
rename to openedx/core/djangoapps/content_tagging/admin.py
diff --git a/openedx/features/content_tagging/api.py b/openedx/core/djangoapps/content_tagging/api.py
similarity index 100%
rename from openedx/features/content_tagging/api.py
rename to openedx/core/djangoapps/content_tagging/api.py
diff --git a/openedx/features/content_tagging/apps.py b/openedx/core/djangoapps/content_tagging/apps.py
similarity index 86%
rename from openedx/features/content_tagging/apps.py
rename to openedx/core/djangoapps/content_tagging/apps.py
index 29952b7bc33d..de52da36780b 100644
--- a/openedx/features/content_tagging/apps.py
+++ b/openedx/core/djangoapps/content_tagging/apps.py
@@ -9,7 +9,7 @@ class ContentTaggingConfig(AppConfig):
"""App config for the content tagging feature"""
default_auto_field = "django.db.models.BigAutoField"
- name = "openedx.features.content_tagging"
+ name = "openedx.core.djangoapps.content_tagging"
def ready(self):
# Connect signal handlers
diff --git a/openedx/features/content_tagging/handlers.py b/openedx/core/djangoapps/content_tagging/handlers.py
similarity index 100%
rename from openedx/features/content_tagging/handlers.py
rename to openedx/core/djangoapps/content_tagging/handlers.py
diff --git a/openedx/features/content_tagging/migrations/0001_initial.py b/openedx/core/djangoapps/content_tagging/migrations/0001_initial.py
similarity index 100%
rename from openedx/features/content_tagging/migrations/0001_initial.py
rename to openedx/core/djangoapps/content_tagging/migrations/0001_initial.py
diff --git a/openedx/features/content_tagging/migrations/0002_system_defined_taxonomies.py b/openedx/core/djangoapps/content_tagging/migrations/0002_system_defined_taxonomies.py
similarity index 74%
rename from openedx/features/content_tagging/migrations/0002_system_defined_taxonomies.py
rename to openedx/core/djangoapps/content_tagging/migrations/0002_system_defined_taxonomies.py
index c743a70ce24c..78b0baa9496b 100644
--- a/openedx/features/content_tagging/migrations/0002_system_defined_taxonomies.py
+++ b/openedx/core/djangoapps/content_tagging/migrations/0002_system_defined_taxonomies.py
@@ -1,7 +1,7 @@
# Generated by Django 3.2.20 on 2023-07-31 21:07
from django.db import migrations
-import openedx.features.content_tagging.models.base
+import openedx.core.djangoapps.content_tagging.models.base
class Migration(migrations.Migration):
@@ -21,7 +21,7 @@ class Migration(migrations.Migration):
'indexes': [],
'constraints': [],
},
- bases=(openedx.features.content_tagging.models.base.ContentTaxonomyMixin, 'oel_tagging.usersystemdefinedtaxonomy'),
+ bases=(openedx.core.djangoapps.content_tagging.models.base.ContentTaxonomyMixin, 'oel_tagging.usersystemdefinedtaxonomy'),
),
migrations.CreateModel(
name='ContentLanguageTaxonomy',
@@ -32,7 +32,7 @@ class Migration(migrations.Migration):
'indexes': [],
'constraints': [],
},
- bases=(openedx.features.content_tagging.models.base.ContentTaxonomyMixin, 'oel_tagging.languagetaxonomy'),
+ bases=(openedx.core.djangoapps.content_tagging.models.base.ContentTaxonomyMixin, 'oel_tagging.languagetaxonomy'),
),
migrations.CreateModel(
name='ContentOrganizationTaxonomy',
@@ -43,7 +43,7 @@ class Migration(migrations.Migration):
'indexes': [],
'constraints': [],
},
- bases=(openedx.features.content_tagging.models.base.ContentTaxonomyMixin, 'oel_tagging.modelsystemdefinedtaxonomy'),
+ bases=(openedx.core.djangoapps.content_tagging.models.base.ContentTaxonomyMixin, 'oel_tagging.modelsystemdefinedtaxonomy'),
),
migrations.CreateModel(
name='OrganizationModelObjectTag',
diff --git a/openedx/features/content_tagging/migrations/0003_system_defined_fixture.py b/openedx/core/djangoapps/content_tagging/migrations/0003_system_defined_fixture.py
similarity index 100%
rename from openedx/features/content_tagging/migrations/0003_system_defined_fixture.py
rename to openedx/core/djangoapps/content_tagging/migrations/0003_system_defined_fixture.py
diff --git a/openedx/features/content_tagging/migrations/0004_system_defined_org.py b/openedx/core/djangoapps/content_tagging/migrations/0004_system_defined_org.py
similarity index 100%
rename from openedx/features/content_tagging/migrations/0004_system_defined_org.py
rename to openedx/core/djangoapps/content_tagging/migrations/0004_system_defined_org.py
diff --git a/openedx/features/content_tagging/migrations/0005_auto_20230830_1517.py b/openedx/core/djangoapps/content_tagging/migrations/0005_auto_20230830_1517.py
similarity index 100%
rename from openedx/features/content_tagging/migrations/0005_auto_20230830_1517.py
rename to openedx/core/djangoapps/content_tagging/migrations/0005_auto_20230830_1517.py
diff --git a/openedx/features/content_tagging/migrations/__init__.py b/openedx/core/djangoapps/content_tagging/migrations/__init__.py
similarity index 100%
rename from openedx/features/content_tagging/migrations/__init__.py
rename to openedx/core/djangoapps/content_tagging/migrations/__init__.py
diff --git a/openedx/features/content_tagging/models/__init__.py b/openedx/core/djangoapps/content_tagging/models/__init__.py
similarity index 100%
rename from openedx/features/content_tagging/models/__init__.py
rename to openedx/core/djangoapps/content_tagging/models/__init__.py
diff --git a/openedx/features/content_tagging/models/base.py b/openedx/core/djangoapps/content_tagging/models/base.py
similarity index 100%
rename from openedx/features/content_tagging/models/base.py
rename to openedx/core/djangoapps/content_tagging/models/base.py
diff --git a/openedx/features/content_tagging/models/system_defined.py b/openedx/core/djangoapps/content_tagging/models/system_defined.py
similarity index 100%
rename from openedx/features/content_tagging/models/system_defined.py
rename to openedx/core/djangoapps/content_tagging/models/system_defined.py
diff --git a/openedx/features/content_tagging/rest_api/__init__.py b/openedx/core/djangoapps/content_tagging/rest_api/__init__.py
similarity index 100%
rename from openedx/features/content_tagging/rest_api/__init__.py
rename to openedx/core/djangoapps/content_tagging/rest_api/__init__.py
diff --git a/openedx/features/content_tagging/rest_api/urls.py b/openedx/core/djangoapps/content_tagging/rest_api/urls.py
similarity index 100%
rename from openedx/features/content_tagging/rest_api/urls.py
rename to openedx/core/djangoapps/content_tagging/rest_api/urls.py
diff --git a/openedx/features/content_tagging/rest_api/v1/__init__.py b/openedx/core/djangoapps/content_tagging/rest_api/v1/__init__.py
similarity index 100%
rename from openedx/features/content_tagging/rest_api/v1/__init__.py
rename to openedx/core/djangoapps/content_tagging/rest_api/v1/__init__.py
diff --git a/openedx/features/content_tagging/rest_api/v1/filters.py b/openedx/core/djangoapps/content_tagging/rest_api/v1/filters.py
similarity index 77%
rename from openedx/features/content_tagging/rest_api/v1/filters.py
rename to openedx/core/djangoapps/content_tagging/rest_api/v1/filters.py
index ee8771d17ee8..9ad192f545de 100644
--- a/openedx/features/content_tagging/rest_api/v1/filters.py
+++ b/openedx/core/djangoapps/content_tagging/rest_api/v1/filters.py
@@ -4,7 +4,7 @@
from rest_framework.filters import BaseFilterBackend
-from ...rules import is_taxonomy_admin
+import openedx_tagging.core.tagging.rules as oel_tagging
class UserOrgFilterBackend(BaseFilterBackend):
@@ -15,7 +15,7 @@ class UserOrgFilterBackend(BaseFilterBackend):
"""
def filter_queryset(self, request, queryset, _):
- if is_taxonomy_admin(request.user):
+ if oel_tagging.is_taxonomy_admin(request.user):
return queryset
return queryset.filter(enabled=True)
diff --git a/openedx/features/content_tagging/rest_api/v1/serializers.py b/openedx/core/djangoapps/content_tagging/rest_api/v1/serializers.py
similarity index 100%
rename from openedx/features/content_tagging/rest_api/v1/serializers.py
rename to openedx/core/djangoapps/content_tagging/rest_api/v1/serializers.py
diff --git a/openedx/features/content_tagging/rest_api/v1/tests/__init__.py b/openedx/core/djangoapps/content_tagging/rest_api/v1/tests/__init__.py
similarity index 100%
rename from openedx/features/content_tagging/rest_api/v1/tests/__init__.py
rename to openedx/core/djangoapps/content_tagging/rest_api/v1/tests/__init__.py
diff --git a/openedx/features/content_tagging/rest_api/v1/tests/test_views.py b/openedx/core/djangoapps/content_tagging/rest_api/v1/tests/test_views.py
similarity index 71%
rename from openedx/features/content_tagging/rest_api/v1/tests/test_views.py
rename to openedx/core/djangoapps/content_tagging/rest_api/v1/tests/test_views.py
index a8177426eb4a..f816436e2c25 100644
--- a/openedx/features/content_tagging/rest_api/v1/tests/test_views.py
+++ b/openedx/core/djangoapps/content_tagging/rest_api/v1/tests/test_views.py
@@ -7,22 +7,24 @@
import ddt
from django.contrib.auth import get_user_model
from django.test.testcases import override_settings
-from openedx_tagging.core.tagging.models import Taxonomy
+from opaque_keys.edx.locator import BlockUsageLocator, CourseLocator
+from openedx_tagging.core.tagging.models import Tag, Taxonomy
from openedx_tagging.core.tagging.models.system_defined import SystemDefinedTaxonomy
from openedx_tagging.core.tagging.rest_api.v1.serializers import TaxonomySerializer
from organizations.models import Organization
from rest_framework import status
from rest_framework.test import APITestCase
-from common.djangoapps.student.auth import update_org_role
-from common.djangoapps.student.roles import OrgContentCreatorRole
+from common.djangoapps.student.auth import add_users, update_org_role
+from common.djangoapps.student.roles import CourseStaffRole, OrgContentCreatorRole
+from openedx.core.djangoapps.content_tagging.models import TaxonomyOrg
from openedx.core.djangolib.testing.utils import skip_unless_cms
-from openedx.features.content_tagging.models import TaxonomyOrg
User = get_user_model()
TAXONOMY_ORG_LIST_URL = "/api/content_tagging/v1/taxonomies/"
TAXONOMY_ORG_DETAIL_URL = "/api/content_tagging/v1/taxonomies/{pk}/"
+OBJECT_TAG_UPDATE_URL = "/api/content_tagging/v1/object_tags/{object_id}/?taxonomy={taxonomy_id}"
def check_taxonomy(
@@ -52,7 +54,7 @@ def check_taxonomy(
assert data["visible_to_authors"] == visible_to_authors
-class TestTaxonomyViewSetMixin:
+class TestTaxonomyObjectsMixin:
"""
Sets up data for testing Content Taxonomies.
"""
@@ -168,7 +170,7 @@ def setUp(self):
@skip_unless_cms
@ddt.ddt
@override_settings(FEATURES={"ENABLE_CREATOR_GROUP": True})
-class TestTaxonomyViewSet(TestTaxonomyViewSetMixin, APITestCase):
+class TestTaxonomyViewSet(TestTaxonomyObjectsMixin, APITestCase):
"""
Test cases for TaxonomyViewSet when ENABLE_CREATOR_GROUP is True
"""
@@ -639,3 +641,211 @@ class TestTaxonomyViewSetNoCreatorGroup(TestTaxonomyViewSet): # pylint: disable
The permissions are the same for when ENABLED_CREATOR_GRUP is True
"""
+
+
+@skip_unless_cms
+@ddt.ddt
+class TestObjectTagViewSet(TestTaxonomyObjectsMixin, APITestCase):
+ """
+ Testing various cases for the ObjectTagView.
+ """
+ def setUp(self):
+ """
+ Setup the test cases
+ """
+ super().setUp()
+ self.courseA = CourseLocator("orgA", "101", "test")
+ self.xblockA = BlockUsageLocator(
+ course_key=self.courseA,
+ block_type='problem',
+ block_id='block_id'
+ )
+ self.courseB = CourseLocator("orgB", "101", "test")
+ self.xblockB = BlockUsageLocator(
+ course_key=self.courseB,
+ block_type='problem',
+ block_id='block_id'
+ )
+
+ self.multiple_taxonomy = Taxonomy.objects.create(name="Multiple Taxonomy", allow_multiple=True)
+ self.required_taxonomy = Taxonomy.objects.create(name="Required Taxonomy", required=True)
+ for i in range(20):
+ # Valid ObjectTags
+ Tag.objects.create(taxonomy=self.tA1, value=f"Tag {i}")
+ Tag.objects.create(taxonomy=self.tA2, value=f"Tag {i}")
+ Tag.objects.create(taxonomy=self.multiple_taxonomy, value=f"Tag {i}")
+ Tag.objects.create(taxonomy=self.required_taxonomy, value=f"Tag {i}")
+
+ self.open_taxonomy = Taxonomy.objects.create(name="Enabled Free-Text Taxonomy", allow_free_text=True)
+
+ # Add org permissions to taxonomy
+ TaxonomyOrg.objects.create(
+ taxonomy=self.multiple_taxonomy,
+ org=self.orgA,
+ rel_type=TaxonomyOrg.RelType.OWNER,
+ )
+ TaxonomyOrg.objects.create(
+ taxonomy=self.required_taxonomy,
+ org=self.orgA,
+ rel_type=TaxonomyOrg.RelType.OWNER,
+ )
+ TaxonomyOrg.objects.create(
+ taxonomy=self.open_taxonomy,
+ org=self.orgA,
+ rel_type=TaxonomyOrg.RelType.OWNER,
+ )
+
+ add_users(self.userS, CourseStaffRole(self.courseA), self.userA)
+
+ @ddt.data(
+ # userA and userS are staff in courseA and can tag using enabled taxonomies
+ (None, "tA1", ["Tag 1"], status.HTTP_403_FORBIDDEN),
+ ("user", "tA1", ["Tag 1"], status.HTTP_403_FORBIDDEN),
+ ("userA", "tA1", ["Tag 1"], status.HTTP_200_OK),
+ ("userS", "tA1", ["Tag 1"], status.HTTP_200_OK),
+ (None, "tA1", [], status.HTTP_403_FORBIDDEN),
+ ("user", "tA1", [], status.HTTP_403_FORBIDDEN),
+ ("userA", "tA1", [], status.HTTP_200_OK),
+ ("userS", "tA1", [], status.HTTP_200_OK),
+ (None, "multiple_taxonomy", ["Tag 1", "Tag 2"], status.HTTP_403_FORBIDDEN),
+ ("user", "multiple_taxonomy", ["Tag 1", "Tag 2"], status.HTTP_403_FORBIDDEN),
+ ("userA", "multiple_taxonomy", ["Tag 1", "Tag 2"], status.HTTP_200_OK),
+ ("userS", "multiple_taxonomy", ["Tag 1", "Tag 2"], status.HTTP_200_OK),
+ (None, "open_taxonomy", ["tag1"], status.HTTP_403_FORBIDDEN),
+ ("user", "open_taxonomy", ["tag1"], status.HTTP_403_FORBIDDEN),
+ ("userA", "open_taxonomy", ["tag1"], status.HTTP_200_OK),
+ ("userS", "open_taxonomy", ["tag1"], status.HTTP_200_OK),
+ # Only userS is Tagging Admin and can tag objects using disabled taxonomies
+ (None, "tA2", ["Tag 1"], status.HTTP_403_FORBIDDEN),
+ ("user", "tA2", ["Tag 1"], status.HTTP_403_FORBIDDEN),
+ ("userA", "tA2", ["Tag 1"], status.HTTP_403_FORBIDDEN),
+ ("userS", "tA2", ["Tag 1"], status.HTTP_200_OK),
+ )
+ @ddt.unpack
+ def test_tag_course(self, user_attr, taxonomy_attr, tag_values, expected_status):
+ if user_attr:
+ user = getattr(self, user_attr)
+ self.client.force_authenticate(user=user)
+
+ taxonomy = getattr(self, taxonomy_attr)
+
+ url = OBJECT_TAG_UPDATE_URL.format(object_id=self.courseA, taxonomy_id=taxonomy.pk)
+
+ response = self.client.put(url, {"tags": tag_values}, format="json")
+
+ assert response.status_code == expected_status
+ if status.is_success(expected_status):
+ assert len(response.data.get("results")) == len(tag_values)
+ assert set(t["value"] for t in response.data["results"]) == set(tag_values)
+
+ @ddt.data(
+ # Can't add invalid tags to a object using a closed taxonomy
+ (None, "tA1", ["invalid"], status.HTTP_403_FORBIDDEN),
+ ("user", "tA1", ["invalid"], status.HTTP_403_FORBIDDEN),
+ ("userA", "tA1", ["invalid"], status.HTTP_400_BAD_REQUEST),
+ ("userS", "tA1", ["invalid"], status.HTTP_400_BAD_REQUEST),
+ (None, "multiple_taxonomy", ["invalid"], status.HTTP_403_FORBIDDEN),
+ ("user", "multiple_taxonomy", ["invalid"], status.HTTP_403_FORBIDDEN),
+ ("userA", "multiple_taxonomy", ["invalid"], status.HTTP_400_BAD_REQUEST),
+ ("userS", "multiple_taxonomy", ["invalid"], status.HTTP_400_BAD_REQUEST),
+ # Staff can't add invalid tags to a object using a closed taxonomy
+ ("userS", "tA2", ["invalid"], status.HTTP_400_BAD_REQUEST),
+ )
+ @ddt.unpack
+ def test_tag_course_invalid(self, user_attr, taxonomy_attr, tag_values, expected_status):
+ if user_attr:
+ user = getattr(self, user_attr)
+ self.client.force_authenticate(user=user)
+
+ taxonomy = getattr(self, taxonomy_attr)
+
+ url = OBJECT_TAG_UPDATE_URL.format(object_id=self.courseA, taxonomy_id=taxonomy.pk)
+
+ response = self.client.put(url, {"tags": tag_values}, format="json")
+ assert response.status_code == expected_status
+ assert not status.is_success(expected_status) # No success cases here
+
+ @ddt.data(
+ # userA and userS are staff in courseA (owner of xblockA) and can tag using enabled taxonomies
+ (None, "tA1", ["Tag 1"], status.HTTP_403_FORBIDDEN),
+ ("user", "tA1", ["Tag 1"], status.HTTP_403_FORBIDDEN),
+ ("userA", "tA1", ["Tag 1"], status.HTTP_200_OK),
+ ("userS", "tA1", ["Tag 1"], status.HTTP_200_OK),
+ (None, "tA1", [], status.HTTP_403_FORBIDDEN),
+ ("user", "tA1", [], status.HTTP_403_FORBIDDEN),
+ ("userA", "tA1", [], status.HTTP_200_OK),
+ ("userS", "tA1", [], status.HTTP_200_OK),
+ (None, "multiple_taxonomy", ["Tag 1", "Tag 2"], status.HTTP_403_FORBIDDEN),
+ ("user", "multiple_taxonomy", ["Tag 1", "Tag 2"], status.HTTP_403_FORBIDDEN),
+ ("userA", "multiple_taxonomy", ["Tag 1", "Tag 2"], status.HTTP_200_OK),
+ ("userS", "multiple_taxonomy", ["Tag 1", "Tag 2"], status.HTTP_200_OK),
+ (None, "open_taxonomy", ["tag1"], status.HTTP_403_FORBIDDEN),
+ ("user", "open_taxonomy", ["tag1"], status.HTTP_403_FORBIDDEN),
+ ("userA", "open_taxonomy", ["tag1"], status.HTTP_200_OK),
+ ("userS", "open_taxonomy", ["tag1"], status.HTTP_200_OK),
+ # Only userS is Tagging Admin and can tag objects using disabled taxonomies
+ (None, "tA2", ["Tag 1"], status.HTTP_403_FORBIDDEN),
+ ("user", "tA2", ["Tag 1"], status.HTTP_403_FORBIDDEN),
+ ("userA", "tA2", ["Tag 1"], status.HTTP_403_FORBIDDEN),
+ ("userS", "tA2", ["Tag 1"], status.HTTP_200_OK),
+ )
+ @ddt.unpack
+ def test_tag_xblock(self, user_attr, taxonomy_attr, tag_values, expected_status):
+ if user_attr:
+ user = getattr(self, user_attr)
+ self.client.force_authenticate(user=user)
+
+ taxonomy = getattr(self, taxonomy_attr)
+
+ url = OBJECT_TAG_UPDATE_URL.format(object_id=self.xblockA, taxonomy_id=taxonomy.pk)
+
+ response = self.client.put(url, {"tags": tag_values}, format="json")
+
+ assert response.status_code == expected_status
+ if status.is_success(expected_status):
+ assert len(response.data.get("results")) == len(tag_values)
+ assert set(t["value"] for t in response.data["results"]) == set(tag_values)
+
+ @ddt.data(
+ # Can't add invalid tags to a object using a closed taxonomy
+ (None, "tA1", ["invalid"], status.HTTP_403_FORBIDDEN),
+ ("user", "tA1", ["invalid"], status.HTTP_403_FORBIDDEN),
+ ("userA", "tA1", ["invalid"], status.HTTP_400_BAD_REQUEST),
+ ("userS", "tA1", ["invalid"], status.HTTP_400_BAD_REQUEST),
+ (None, "multiple_taxonomy", ["invalid"], status.HTTP_403_FORBIDDEN),
+ ("user", "multiple_taxonomy", ["invalid"], status.HTTP_403_FORBIDDEN),
+ ("userA", "multiple_taxonomy", ["invalid"], status.HTTP_400_BAD_REQUEST),
+ ("userS", "multiple_taxonomy", ["invalid"], status.HTTP_400_BAD_REQUEST),
+ # Staff can't add invalid tags to a object using a closed taxonomy
+ ("userS", "tA2", ["invalid"], status.HTTP_400_BAD_REQUEST),
+ )
+ @ddt.unpack
+ def test_tag_xblock_invalid(self, user_attr, taxonomy_attr, tag_values, expected_status):
+ if user_attr:
+ user = getattr(self, user_attr)
+ self.client.force_authenticate(user=user)
+
+ taxonomy = getattr(self, taxonomy_attr)
+
+ url = OBJECT_TAG_UPDATE_URL.format(object_id=self.xblockA, taxonomy_id=taxonomy.pk)
+
+ response = self.client.put(url, {"tags": tag_values}, format="json")
+ assert response.status_code == expected_status
+ assert not status.is_success(expected_status) # No success cases here
+
+ @ddt.data(
+ "courseB",
+ "xblockB",
+ )
+ def test_tag_unauthorized(self, objectid_attr):
+ """
+ Test that a user without access to courseB can't apply tags to it
+ """
+ self.client.force_authenticate(user=self.userA)
+ object_id = getattr(self, objectid_attr)
+
+ url = OBJECT_TAG_UPDATE_URL.format(object_id=object_id, taxonomy_id=self.tA1.pk)
+
+ response = self.client.put(url, {"tags": ["Tag 1"]}, format="json")
+
+ assert response.status_code == status.HTTP_403_FORBIDDEN
diff --git a/openedx/features/content_tagging/rest_api/v1/urls.py b/openedx/core/djangoapps/content_tagging/rest_api/v1/urls.py
similarity index 100%
rename from openedx/features/content_tagging/rest_api/v1/urls.py
rename to openedx/core/djangoapps/content_tagging/rest_api/v1/urls.py
diff --git a/openedx/features/content_tagging/rest_api/v1/views.py b/openedx/core/djangoapps/content_tagging/rest_api/v1/views.py
similarity index 100%
rename from openedx/features/content_tagging/rest_api/v1/views.py
rename to openedx/core/djangoapps/content_tagging/rest_api/v1/views.py
diff --git a/openedx/core/djangoapps/content_tagging/rules.py b/openedx/core/djangoapps/content_tagging/rules.py
new file mode 100644
index 000000000000..bad38019ce51
--- /dev/null
+++ b/openedx/core/djangoapps/content_tagging/rules.py
@@ -0,0 +1,105 @@
+"""Django rules-based permissions for tagging"""
+
+from __future__ import annotations
+
+from typing import Union
+
+import django.contrib.auth.models
+import openedx_tagging.core.tagging.rules as oel_tagging
+import rules
+from opaque_keys import InvalidKeyError
+from opaque_keys.edx.keys import CourseKey, UsageKey
+
+from common.djangoapps.student.auth import is_content_creator, has_studio_write_access
+
+from .models import TaxonomyOrg
+
+UserType = Union[django.contrib.auth.models.User, django.contrib.auth.models.AnonymousUser]
+
+
+def is_taxonomy_user(user: UserType, taxonomy: oel_tagging.Taxonomy) -> bool:
+ """
+ Returns True if the given user is a Taxonomy User for the given content taxonomy.
+
+ Taxonomy users include global staff and superusers, plus course creators who can create courses for any org.
+ Otherwise, we need to check taxonomy provided to determine if the user is an org-level course creator for one of
+ the orgs allowed to use this taxonomy. Only global staff and superusers can use disabled system taxonomies.
+ """
+ if oel_tagging.is_taxonomy_admin(user):
+ return True
+
+ taxonomy_orgs = TaxonomyOrg.get_organizations(
+ taxonomy=taxonomy,
+ rel_type=TaxonomyOrg.RelType.OWNER,
+ )
+ for org in taxonomy_orgs:
+ if is_content_creator(user, org.short_name):
+ return True
+ return False
+
+
+@rules.predicate
+def can_change_object_tag_objectid(user: UserType, object_id: str) -> bool:
+ """
+ Everyone that has permission to edit the object should be able to tag it.
+ """
+ if not object_id:
+ raise ValueError("object_id must be provided")
+ try:
+ usage_key = UsageKey.from_string(object_id)
+ if not usage_key.course_key.is_course:
+ raise ValueError("object_id must be from a block or a course")
+ course_key = usage_key.course_key
+ except InvalidKeyError:
+ course_key = CourseKey.from_string(object_id)
+
+ return has_studio_write_access(user, course_key)
+
+
+@rules.predicate
+def can_change_object_tag_taxonomy(user: UserType, taxonomy: oel_tagging.Taxonomy) -> bool:
+ """
+ Taxonomy users can tag objects using tags from any taxonomy that they have permission to view. Only taxonomy admins
+ can tag objects using tags from disabled taxonomies.
+ """
+ return oel_tagging.is_taxonomy_admin(user) or (taxonomy.cast().enabled and is_taxonomy_user(user, taxonomy))
+
+
+@rules.predicate
+def can_change_taxonomy_tag(user: UserType, tag: oel_tagging.Tag | None = None) -> bool:
+ """
+ Even taxonomy admins cannot add tags to system taxonomies (their tags are system-defined), or free-text taxonomies
+ (these don't have predefined tags).
+ """
+ taxonomy = tag.taxonomy if tag else None
+ if taxonomy:
+ taxonomy = taxonomy.cast()
+ return oel_tagging.is_taxonomy_admin(user) and (
+ not tag
+ or not taxonomy
+ or (taxonomy and not taxonomy.allow_free_text and not taxonomy.system_defined)
+ )
+
+
+# Taxonomy
+rules.set_perm("oel_tagging.add_taxonomy", oel_tagging.is_taxonomy_admin)
+rules.set_perm("oel_tagging.change_taxonomy", oel_tagging.can_change_taxonomy)
+rules.set_perm("oel_tagging.delete_taxonomy", oel_tagging.can_change_taxonomy)
+rules.set_perm("oel_tagging.view_taxonomy", oel_tagging.can_view_taxonomy)
+
+# Tag
+rules.set_perm("oel_tagging.add_tag", can_change_taxonomy_tag)
+rules.set_perm("oel_tagging.change_tag", can_change_taxonomy_tag)
+rules.set_perm("oel_tagging.delete_tag", can_change_taxonomy_tag)
+rules.set_perm("oel_tagging.view_tag", rules.always_allow)
+
+# ObjectTag
+rules.set_perm("oel_tagging.add_object_tag", oel_tagging.can_change_object_tag)
+rules.set_perm("oel_tagging.change_object_tag", oel_tagging.can_change_object_tag)
+rules.set_perm("oel_tagging.delete_object_tag", oel_tagging.can_change_object_tag)
+rules.set_perm("oel_tagging.view_object_tag", rules.always_allow)
+
+# This perms are used in the tagging rest api from openedx_tagging that is exposed in the CMS. They are overridden here
+# to include Organization and objects permissions.
+rules.set_perm("oel_tagging.change_objecttag_taxonomy", can_change_object_tag_taxonomy)
+rules.set_perm("oel_tagging.change_objecttag_objectid", can_change_object_tag_objectid)
diff --git a/openedx/features/content_tagging/tasks.py b/openedx/core/djangoapps/content_tagging/tasks.py
similarity index 96%
rename from openedx/features/content_tagging/tasks.py
rename to openedx/core/djangoapps/content_tagging/tasks.py
index a328634f0735..3ffa6c29f107 100644
--- a/openedx/features/content_tagging/tasks.py
+++ b/openedx/core/djangoapps/content_tagging/tasks.py
@@ -9,6 +9,7 @@
from celery_utils.logged_task import LoggedTask
from django.conf import settings
from django.contrib.auth import get_user_model
+from edx_django_utils.monitoring import set_code_owner_attribute
from opaque_keys.edx.keys import CourseKey, UsageKey
from openedx_tagging.core.tagging.models import Taxonomy
@@ -73,6 +74,7 @@ def _delete_tags(content_object: CourseKey | UsageKey) -> None:
@shared_task(base=LoggedTask)
+@set_code_owner_attribute
def update_course_tags(course_key_str: str) -> bool:
"""
Updates the automatically-managed tags for a course
@@ -98,6 +100,7 @@ def update_course_tags(course_key_str: str) -> bool:
@shared_task(base=LoggedTask)
+@set_code_owner_attribute
def delete_course_tags(course_key_str: str) -> bool:
"""
Delete the tags for a Course (when the course itself has been deleted).
@@ -119,6 +122,7 @@ def delete_course_tags(course_key_str: str) -> bool:
@shared_task(base=LoggedTask)
+@set_code_owner_attribute
def update_xblock_tags(usage_key_str: str) -> bool:
"""
Updates the automatically-managed tags for a XBlock
@@ -149,6 +153,7 @@ def update_xblock_tags(usage_key_str: str) -> bool:
@shared_task(base=LoggedTask)
+@set_code_owner_attribute
def delete_xblock_tags(usage_key_str: str) -> bool:
"""
Delete the tags for a XBlock (when the XBlock itself is deleted).
diff --git a/openedx/features/content_tagging/tests/__init__.py b/openedx/core/djangoapps/content_tagging/tests/__init__.py
similarity index 100%
rename from openedx/features/content_tagging/tests/__init__.py
rename to openedx/core/djangoapps/content_tagging/tests/__init__.py
diff --git a/openedx/features/content_tagging/tests/test_api.py b/openedx/core/djangoapps/content_tagging/tests/test_api.py
similarity index 100%
rename from openedx/features/content_tagging/tests/test_api.py
rename to openedx/core/djangoapps/content_tagging/tests/test_api.py
diff --git a/openedx/features/content_tagging/tests/test_models.py b/openedx/core/djangoapps/content_tagging/tests/test_models.py
similarity index 100%
rename from openedx/features/content_tagging/tests/test_models.py
rename to openedx/core/djangoapps/content_tagging/tests/test_models.py
diff --git a/openedx/features/content_tagging/tests/test_rules.py b/openedx/core/djangoapps/content_tagging/tests/test_rules.py
similarity index 69%
rename from openedx/features/content_tagging/tests/test_rules.py
rename to openedx/core/djangoapps/content_tagging/tests/test_rules.py
index 0bb0e538156c..442fda5a71bd 100644
--- a/openedx/features/content_tagging/tests/test_rules.py
+++ b/openedx/core/djangoapps/content_tagging/tests/test_rules.py
@@ -3,15 +3,17 @@
import ddt
from django.contrib.auth import get_user_model
from django.test.testcases import TestCase, override_settings
+from opaque_keys import InvalidKeyError
+from opaque_keys.edx.locator import BlockUsageLocator, CourseLocator
from openedx_tagging.core.tagging.models import (
- ObjectTag,
Tag,
UserSystemDefinedTaxonomy,
)
+from openedx_tagging.core.tagging.rules import ChangeObjectTagPermissionItem
from organizations.models import Organization
from common.djangoapps.student.auth import add_users, update_org_role
-from common.djangoapps.student.roles import CourseCreatorRole, OrgContentCreatorRole
+from common.djangoapps.student.roles import CourseCreatorRole, CourseStaffRole, OrgContentCreatorRole
from .. import api
from .test_api import TestTaxonomyMixin
@@ -74,6 +76,115 @@ def setUp(self):
email="learner@example.com",
)
+ self.course1 = CourseLocator(self.org1.short_name, "DemoX", "Demo_Course")
+ self.course2 = CourseLocator(self.org2.short_name, "DemoX", "Demo_Course")
+ self.courseC = CourseLocator("orgC", "DemoX", "Demo_Course")
+
+ self.xblock1 = BlockUsageLocator(
+ course_key=self.course1,
+ block_type='problem',
+ block_id='block_id'
+ )
+ self.xblock2 = BlockUsageLocator(
+ course_key=self.course2,
+ block_type='problem',
+ block_id='block_id'
+ )
+ self.xblockC = BlockUsageLocator(
+ course_key=self.courseC,
+ block_type='problem',
+ block_id='block_id'
+ )
+
+ add_users(self.staff, CourseStaffRole(self.course1), self.user_all_orgs)
+ add_users(self.staff, CourseStaffRole(self.course1), self.user_both_orgs)
+ add_users(self.staff, CourseStaffRole(self.course2), self.user_all_orgs)
+ add_users(self.staff, CourseStaffRole(self.course2), self.user_both_orgs)
+ add_users(self.staff, CourseStaffRole(self.course2), self.user_org2)
+ add_users(self.staff, CourseStaffRole(self.course2), self.user_org2)
+
+ self.tax_all_course1 = ChangeObjectTagPermissionItem(
+ taxonomy=self.taxonomy_all_orgs,
+ object_id=str(self.course1),
+ )
+ self.tax_all_course2 = ChangeObjectTagPermissionItem(
+ taxonomy=self.taxonomy_all_orgs,
+ object_id=str(self.course2),
+ )
+ self.tax_all_xblock1 = ChangeObjectTagPermissionItem(
+ taxonomy=self.taxonomy_all_orgs,
+ object_id=str(self.xblock1),
+ )
+ self.tax_all_xblock2 = ChangeObjectTagPermissionItem(
+ taxonomy=self.taxonomy_all_orgs,
+ object_id=str(self.xblock2),
+ )
+
+ self.tax_both_course1 = ChangeObjectTagPermissionItem(
+ taxonomy=self.taxonomy_both_orgs,
+ object_id=str(self.course1),
+ )
+ self.tax_both_course2 = ChangeObjectTagPermissionItem(
+ taxonomy=self.taxonomy_both_orgs,
+ object_id=str(self.course2),
+ )
+ self.tax_both_xblock1 = ChangeObjectTagPermissionItem(
+ taxonomy=self.taxonomy_both_orgs,
+ object_id=str(self.xblock1),
+ )
+ self.tax_both_xblock2 = ChangeObjectTagPermissionItem(
+ taxonomy=self.taxonomy_both_orgs,
+ object_id=str(self.xblock2),
+ )
+
+ self.tax1_course1 = ChangeObjectTagPermissionItem(
+ taxonomy=self.taxonomy_one_org,
+ object_id=str(self.course1),
+ )
+ self.tax1_xblock1 = ChangeObjectTagPermissionItem(
+ taxonomy=self.taxonomy_one_org,
+ object_id=str(self.xblock1),
+ )
+
+ self.tax_no_org_course1 = ChangeObjectTagPermissionItem(
+ taxonomy=self.taxonomy_no_orgs,
+ object_id=str(self.course1),
+ )
+
+ self.tax_no_org_xblock1 = ChangeObjectTagPermissionItem(
+ taxonomy=self.taxonomy_no_orgs,
+ object_id=str(self.xblock1),
+ )
+
+ self.disabled_course_tag_perm = ChangeObjectTagPermissionItem(
+ taxonomy=self.taxonomy_disabled,
+ object_id=str(self.course2),
+ )
+
+ self.all_orgs_invalid_tag_perm = ChangeObjectTagPermissionItem(
+ taxonomy=self.taxonomy_all_orgs,
+ object_id="course-v1_OpenedX_DemoX_Demo_Course",
+ )
+ self.one_org_invalid_org_tag_perm = ChangeObjectTagPermissionItem(
+ taxonomy=self.taxonomy_one_org,
+ object_id="block-v1_OeX_DemoX_Demo_Course_type_html_block@abcde",
+ )
+ self.no_orgs_invalid_tag_perm = ChangeObjectTagPermissionItem(
+ taxonomy=self.taxonomy_no_orgs,
+ object_id=str(self.course1),
+ )
+
+ self.all_org_perms = (
+ self.tax_all_course1,
+ self.tax_all_course2,
+ self.tax_all_xblock1,
+ self.tax_all_xblock2,
+ self.tax_both_course1,
+ self.tax_both_course2,
+ self.tax_both_xblock1,
+ self.tax_both_xblock2,
+ )
+
def _expected_users_have_perm(
self, perm, obj, learner_perm=False, learner_obj=False, user_org2=True
):
@@ -362,25 +473,28 @@ def test_view_tag(self, tag_attr):
# ObjectTag
@ddt.data(
- ("oel_tagging.add_object_tag", "disabled_course_tag"),
- ("oel_tagging.change_object_tag", "disabled_course_tag"),
- ("oel_tagging.delete_object_tag", "disabled_course_tag"),
+ ("oel_tagging.add_object_tag", "disabled_course_tag_perm"),
+ ("oel_tagging.change_object_tag", "disabled_course_tag_perm"),
+ ("oel_tagging.delete_object_tag", "disabled_course_tag_perm"),
)
@ddt.unpack
def test_object_tag_disabled_taxonomy(self, perm, tag_attr):
- """Taxonomy administrators cannot create/edit an ObjectTag with a disabled Taxonomy"""
- object_tag = getattr(self, tag_attr)
- assert self.superuser.has_perm(perm, object_tag)
- assert not self.staff.has_perm(perm, object_tag)
- assert not self.user_all_orgs.has_perm(perm, object_tag)
- assert not self.user_both_orgs.has_perm(perm, object_tag)
- assert not self.user_org2.has_perm(perm, object_tag)
- assert not self.learner.has_perm(perm, object_tag)
+ """Only taxonomy administrators can create/edit an ObjectTag using a disabled Taxonomy"""
+ object_tag_perm = getattr(self, tag_attr)
+ assert self.superuser.has_perm(perm, object_tag_perm)
+ assert self.staff.has_perm(perm, object_tag_perm)
+ assert not self.user_all_orgs.has_perm(perm, object_tag_perm)
+ assert not self.user_both_orgs.has_perm(perm, object_tag_perm)
+ assert not self.user_org2.has_perm(perm, object_tag_perm)
+ assert not self.learner.has_perm(perm, object_tag_perm)
@ddt.data(
- ("oel_tagging.add_object_tag", "no_orgs_invalid_tag"),
- ("oel_tagging.change_object_tag", "no_orgs_invalid_tag"),
- ("oel_tagging.delete_object_tag", "no_orgs_invalid_tag"),
+ ("oel_tagging.add_object_tag", "tax_no_org_course1"),
+ ("oel_tagging.add_object_tag", "tax_no_org_xblock1"),
+ ("oel_tagging.change_object_tag", "tax_no_org_course1"),
+ ("oel_tagging.change_object_tag", "tax_no_org_xblock1"),
+ ("oel_tagging.delete_object_tag", "tax_no_org_xblock1"),
+ ("oel_tagging.delete_object_tag", "tax_no_org_course1"),
)
@ddt.unpack
def test_object_tag_no_orgs(self, perm, tag_attr):
@@ -394,61 +508,56 @@ def test_object_tag_no_orgs(self, perm, tag_attr):
assert not self.learner.has_perm(perm, object_tag)
@ddt.data(
- ("oel_tagging.add_object_tag", "all_orgs_course_tag"),
- ("oel_tagging.add_object_tag", "all_orgs_block_tag"),
- ("oel_tagging.add_object_tag", "both_orgs_course_tag"),
- ("oel_tagging.add_object_tag", "both_orgs_block_tag"),
- ("oel_tagging.add_object_tag", "all_orgs_invalid_tag"),
- ("oel_tagging.change_object_tag", "all_orgs_course_tag"),
- ("oel_tagging.change_object_tag", "all_orgs_block_tag"),
- ("oel_tagging.change_object_tag", "both_orgs_course_tag"),
- ("oel_tagging.change_object_tag", "both_orgs_block_tag"),
- ("oel_tagging.change_object_tag", "all_orgs_invalid_tag"),
- ("oel_tagging.delete_object_tag", "all_orgs_course_tag"),
- ("oel_tagging.delete_object_tag", "all_orgs_block_tag"),
- ("oel_tagging.delete_object_tag", "both_orgs_course_tag"),
- ("oel_tagging.delete_object_tag", "both_orgs_block_tag"),
- ("oel_tagging.delete_object_tag", "all_orgs_invalid_tag"),
+ "oel_tagging.add_object_tag",
+ "oel_tagging.change_object_tag",
+ "oel_tagging.delete_object_tag",
)
- @ddt.unpack
- def test_change_object_tag_all_orgs(self, perm, tag_attr):
- """Taxonomy administrators can create/edit an ObjectTag on taxonomies in their org."""
- object_tag = getattr(self, tag_attr)
- self._expected_users_have_perm(perm, object_tag)
+ def test_change_object_tag_all_orgs(self, perm):
+ """
+ Taxonomy administrators can create/edit an ObjectTag using taxonomies in their org,
+ but only on objects they have write access to.
+ """
+ for perm_item in self.all_org_perms:
+ assert self.superuser.has_perm(perm, perm_item)
+ assert self.staff.has_perm(perm, perm_item)
+ assert self.user_all_orgs.has_perm(perm, perm_item)
+ assert self.user_both_orgs.has_perm(perm, perm_item)
+ assert self.user_org2.has_perm(perm, perm_item) == (self.org2.short_name in perm_item.object_id)
+ assert not self.learner.has_perm(perm, perm_item)
@ddt.data(
- ("oel_tagging.add_object_tag", "one_org_block_tag"),
- ("oel_tagging.add_object_tag", "one_org_invalid_org_tag"),
- ("oel_tagging.change_object_tag", "one_org_block_tag"),
- ("oel_tagging.change_object_tag", "one_org_invalid_org_tag"),
- ("oel_tagging.delete_object_tag", "one_org_block_tag"),
- ("oel_tagging.delete_object_tag", "one_org_invalid_org_tag"),
+ ("oel_tagging.add_object_tag", "tax1_course1"),
+ ("oel_tagging.add_object_tag", "tax1_xblock1"),
+ ("oel_tagging.change_object_tag", "tax1_course1"),
+ ("oel_tagging.change_object_tag", "tax1_xblock1"),
+ ("oel_tagging.delete_object_tag", "tax1_course1"),
+ ("oel_tagging.delete_object_tag", "tax1_xblock1"),
)
@ddt.unpack
def test_change_object_tag_org1(self, perm, tag_attr):
"""Taxonomy administrators can create/edit an ObjectTag on taxonomies in their org."""
- object_tag = getattr(self, tag_attr)
- self._expected_users_have_perm(perm, object_tag, user_org2=False)
+ perm_item = getattr(self, tag_attr)
+ assert self.superuser.has_perm(perm, perm_item)
+ assert self.staff.has_perm(perm, perm_item)
+ assert self.user_all_orgs.has_perm(perm, perm_item)
+ assert self.user_both_orgs.has_perm(perm, perm_item)
+ assert not self.user_org2.has_perm(perm, perm_item)
+ assert not self.learner.has_perm(perm, perm_item)
@ddt.data(
- "oel_tagging.add_object_tag",
- "oel_tagging.change_object_tag",
- "oel_tagging.delete_object_tag",
- )
- def test_object_tag_no_taxonomy(self, perm):
- """Taxonomy administrators can modify an ObjectTag with no Taxonomy"""
- object_tag = ObjectTag()
-
- # Global Taxonomy Admins can do pretty much anything
- assert self.superuser.has_perm(perm, object_tag)
- assert self.staff.has_perm(perm, object_tag)
- assert self.user_all_orgs.has_perm(perm, object_tag)
- # Org content creators are bound by a taxonomy's org restrictions,
- # so if there's no taxonomy, they can't do anything to it.
- assert not self.user_both_orgs.has_perm(perm, object_tag)
- assert not self.user_org2.has_perm(perm, object_tag)
- assert not self.learner.has_perm(perm, object_tag)
+ ("oel_tagging.add_object_tag", "one_org_invalid_org_tag_perm"),
+ ("oel_tagging.add_object_tag", "all_orgs_invalid_tag_perm"),
+ ("oel_tagging.change_object_tag", "one_org_invalid_org_tag_perm"),
+ ("oel_tagging.change_object_tag", "all_orgs_invalid_tag_perm"),
+ ("oel_tagging.delete_object_tag", "one_org_invalid_org_tag_perm"),
+ ("oel_tagging.delete_object_tag", "all_orgs_invalid_tag_perm"),
+ )
+ @ddt.unpack
+ def test_change_object_tag_invalid_key(self, perm, tag_attr):
+ perm_item = getattr(self, tag_attr)
+ with self.assertRaises(InvalidKeyError):
+ assert self.staff.has_perm(perm, perm_item)
@ddt.data(
"all_orgs_course_tag",
@@ -493,31 +602,11 @@ def _expected_users_have_perm(
super()._expected_users_have_perm(
perm=perm,
obj=obj,
- learner_perm=True,
- learner_obj=True,
- user_org2=True,
+ learner_perm=learner_perm,
+ learner_obj=learner_obj,
+ user_org2=user_org2,
)
- @ddt.data(
- "oel_tagging.add_object_tag",
- "oel_tagging.change_object_tag",
- "oel_tagging.delete_object_tag",
- )
- def test_object_tag_no_taxonomy(self, perm):
- """Taxonomy administrators can modify an ObjectTag with no Taxonomy"""
- object_tag = ObjectTag()
-
- # Global Taxonomy Admins can do pretty much anything
- assert self.superuser.has_perm(perm, object_tag)
- assert self.staff.has_perm(perm, object_tag)
- assert self.user_all_orgs.has_perm(perm, object_tag)
-
- # Org content creators are bound by a taxonomy's org restrictions,
- # but since there's no org restrictions enabled, anyone has these permissions.
- assert self.user_both_orgs.has_perm(perm, object_tag)
- assert self.user_org2.has_perm(perm, object_tag)
- assert self.learner.has_perm(perm, object_tag)
-
# Taxonomy
@ddt.data(
diff --git a/openedx/features/content_tagging/tests/test_tasks.py b/openedx/core/djangoapps/content_tagging/tests/test_tasks.py
similarity index 96%
rename from openedx/features/content_tagging/tests/test_tasks.py
rename to openedx/core/djangoapps/content_tagging/tests/test_tasks.py
index 47bf864951f6..c1c45e944962 100644
--- a/openedx/features/content_tagging/tests/test_tasks.py
+++ b/openedx/core/djangoapps/content_tagging/tests/test_tasks.py
@@ -13,7 +13,7 @@
from common.djangoapps.student.tests.factories import UserFactory
from openedx.core.djangolib.testing.utils import skip_unless_cms
-from xmodule.modulestore.tests.django_utils import TEST_DATA_MIXED_MODULESTORE, ModuleStoreTestCase
+from xmodule.modulestore.tests.django_utils import TEST_DATA_SPLIT_MODULESTORE, ModuleStoreTestCase
from .. import api
from ..models import ContentLanguageTaxonomy, TaxonomyOrg
@@ -29,7 +29,7 @@ class TestAutoTagging(ModuleStoreTestCase):
Test if the Course and XBlock tags are automatically created
"""
- MODULESTORE = TEST_DATA_MIXED_MODULESTORE
+ MODULESTORE = TEST_DATA_SPLIT_MODULESTORE
def _check_tag(self, object_id: str, taxonomy_id: int, value: str | None):
"""
@@ -69,7 +69,7 @@ def setUp(self):
self.user_id = self.user.id
self.orgA = Organization.objects.create(name="Organization A", short_name="orgA")
- self.patcher = patch("openedx.features.content_tagging.tasks.modulestore", return_value=self.store)
+ self.patcher = patch("openedx.core.djangoapps.content_tagging.tasks.modulestore", return_value=self.store)
self.addCleanup(self.patcher.stop)
self.patcher.start()
diff --git a/openedx/features/content_tagging/toggles.py b/openedx/core/djangoapps/content_tagging/toggles.py
similarity index 100%
rename from openedx/features/content_tagging/toggles.py
rename to openedx/core/djangoapps/content_tagging/toggles.py
diff --git a/openedx/features/content_tagging/urls.py b/openedx/core/djangoapps/content_tagging/urls.py
similarity index 100%
rename from openedx/features/content_tagging/urls.py
rename to openedx/core/djangoapps/content_tagging/urls.py
diff --git a/openedx/core/djangoapps/cors_csrf/middleware.py b/openedx/core/djangoapps/cors_csrf/middleware.py
index 072a333c452d..8122231e32ef 100644
--- a/openedx/core/djangoapps/cors_csrf/middleware.py
+++ b/openedx/core/djangoapps/cors_csrf/middleware.py
@@ -120,12 +120,18 @@ def process_response(self, request, response):
log.debug("Could not set cross-domain CSRF cookie.")
return response
- # Check whether (a) the CSRF middleware has already set a cookie, and
- # (b) this is a view decorated with `@ensure_cross_domain_csrf_cookie`
- # If so, we can send the cross-domain CSRF cookie.
+ # Send the cross-domain CSRF cookie if this is a view decorated with
+ # `@ensure_cross_domain_csrf_cookie` and the same-domain CSRF cookie
+ # value is available.
+ #
+ # Because CSRF_COOKIE can be set either by an inbound CSRF token or
+ # by the middleware generating a new one or echoing the old one for
+ # the response, this might result in sending the cookie more often
+ # than the CSRF value actually changes, but as of Django 4.0 we no
+ # longer have a good way of finding out when the csrf middleware has
+ # updated the value.
should_set_cookie = (
request.META.get('CROSS_DOMAIN_CSRF_COOKIE_USED', False) and
- request.META.get('CSRF_COOKIE_USED', False) and
request.META.get('CSRF_COOKIE') is not None
)
diff --git a/openedx/core/djangoapps/cors_csrf/tests/test_decorators.py b/openedx/core/djangoapps/cors_csrf/tests/test_decorators.py
index 64da1a5639b2..917b62e0e531 100644
--- a/openedx/core/djangoapps/cors_csrf/tests/test_decorators.py
+++ b/openedx/core/djangoapps/cors_csrf/tests/test_decorators.py
@@ -3,6 +3,8 @@
import json
from unittest import mock
+
+import django
from django.http import HttpResponse
from django.test import TestCase
@@ -25,4 +27,7 @@ def test_ensure_csrf_cookie_cross_domain(self):
response = wrapped_view(request)
response_meta = json.loads(response.content.decode('utf-8'))
assert response_meta['CROSS_DOMAIN_CSRF_COOKIE_USED'] is True
- assert response_meta['CSRF_COOKIE_USED'] is True
+ if django.VERSION < (4, 0):
+ assert response_meta['CSRF_COOKIE_USED'] is True
+ else:
+ assert response_meta['CSRF_COOKIE_NEEDS_UPDATE'] is True
diff --git a/openedx/core/djangoapps/cors_csrf/tests/test_middleware.py b/openedx/core/djangoapps/cors_csrf/tests/test_middleware.py
index 71be51ce7f50..a546cbbcd4bb 100644
--- a/openedx/core/djangoapps/cors_csrf/tests/test_middleware.py
+++ b/openedx/core/djangoapps/cors_csrf/tests/test_middleware.py
@@ -258,7 +258,6 @@ def _get_response(self,
del request.META['HTTP_REFERER']
if csrf_cookie_used:
- request.META['CSRF_COOKIE_USED'] = True
request.META['CSRF_COOKIE'] = self.COOKIE_VALUE
if cross_domain_decorator:
diff --git a/openedx/core/djangoapps/course_groups/cohorts.py b/openedx/core/djangoapps/course_groups/cohorts.py
index a7298161f2fe..cb3dfc5b9e88 100644
--- a/openedx/core/djangoapps/course_groups/cohorts.py
+++ b/openedx/core/djangoapps/course_groups/cohorts.py
@@ -619,3 +619,17 @@ def _get_cohort_settings_from_modulestore(course):
'cohorted_discussions': list(course.cohorted_discussions),
'always_cohort_inline_discussions': course.always_cohort_inline_discussions
}
+
+
+def get_cohorted_user_partition_id(course_key):
+ """
+ Returns the partition id to which cohorts are linked or None if there is no cohort linked
+ to a content group.
+ """
+ course_user_group_partition_group = CourseUserGroupPartitionGroup.objects.filter(
+ course_user_group__course_id=course_key
+ ).first()
+
+ if course_user_group_partition_group:
+ return course_user_group_partition_group.partition_id
+ return None
diff --git a/openedx/core/djangoapps/courseware_api/views.py b/openedx/core/djangoapps/courseware_api/views.py
index 8ee882abe3e2..704abdfc2df5 100644
--- a/openedx/core/djangoapps/courseware_api/views.py
+++ b/openedx/core/djangoapps/courseware_api/views.py
@@ -4,6 +4,8 @@
from completion.exceptions import UnavailableCompletionData
from completion.utilities import get_key_to_last_completed_block
from django.conf import settings
+from django.db import transaction
+from django.utils.decorators import method_decorator
from django.utils.functional import cached_property
from edx_django_utils.cache import TieredCache
from edx_rest_framework_extensions.auth.jwt.authentication import JwtAuthentication
@@ -368,6 +370,7 @@ def learning_assistant_enabled(self):
return learning_assistant_is_active(self.course_key)
+@method_decorator(transaction.non_atomic_requests, name='dispatch')
class CoursewareInformation(RetrieveAPIView):
"""
**Use Cases**
diff --git a/openedx/core/djangoapps/enrollments/forms.py b/openedx/core/djangoapps/enrollments/forms.py
index 5285792890fd..4c691ae70452 100644
--- a/openedx/core/djangoapps/enrollments/forms.py
+++ b/openedx/core/djangoapps/enrollments/forms.py
@@ -15,9 +15,10 @@ class CourseEnrollmentsApiListForm(Form):
"""
A form that validates the query string parameters for the CourseEnrollmentsApiListView.
"""
- MAX_USERNAME_COUNT = 100
+ MAX_INPUT_COUNT = 100
username = CharField(required=False)
course_id = CharField(required=False)
+ email = CharField(required=False)
def clean_course_id(self):
"""
@@ -38,14 +39,31 @@ def clean_username(self):
usernames_csv_string = self.cleaned_data.get('username')
if usernames_csv_string:
usernames = usernames_csv_string.split(',')
- if len(usernames) > self.MAX_USERNAME_COUNT:
+ if len(usernames) > self.MAX_INPUT_COUNT:
raise ValidationError(
"Too many usernames in a single request - {}. A maximum of {} is allowed".format(
len(usernames),
- self.MAX_USERNAME_COUNT,
+ self.MAX_INPUT_COUNT,
)
)
for username in usernames:
validate_username(username)
return usernames
return usernames_csv_string
+
+ def clean_email(self):
+ """
+ Validate a string of comma-separated emails and return a list of emails.
+ """
+ emails_csv_string = self.cleaned_data.get('email')
+ if emails_csv_string:
+ emails = emails_csv_string.split(',')
+ if len(emails) > self.MAX_INPUT_COUNT:
+ raise ValidationError(
+ "Too many emails in a single request - {}. A maximum of {} is allowed".format(
+ len(emails),
+ self.MAX_INPUT_COUNT,
+ )
+ )
+ return emails
+ return emails_csv_string
diff --git a/openedx/core/djangoapps/enrollments/serializers.py b/openedx/core/djangoapps/enrollments/serializers.py
index 00cf1a8c21e3..44a1a5619404 100644
--- a/openedx/core/djangoapps/enrollments/serializers.py
+++ b/openedx/core/djangoapps/enrollments/serializers.py
@@ -8,7 +8,8 @@
from rest_framework import serializers
from common.djangoapps.course_modes.models import CourseMode
-from common.djangoapps.student.models import CourseEnrollment
+from common.djangoapps.student.models import (CourseEnrollment,
+ CourseEnrollmentAllowed)
log = logging.getLogger(__name__)
@@ -127,3 +128,16 @@ class ModeSerializer(serializers.Serializer): # pylint: disable=abstract-method
description = serializers.CharField()
sku = serializers.CharField()
bulk_sku = serializers.CharField()
+
+
+class CourseEnrollmentAllowedSerializer(serializers.ModelSerializer):
+ """
+ Serializes CourseEnrollmentAllowed model
+
+ Aggregates all data from the CourseEnrollmentAllowed table, and pulls in the serialization
+ to give a complete representation of course enrollment allowed.
+ """
+ class Meta:
+ model = CourseEnrollmentAllowed
+ exclude = ['id']
+ lookup_field = 'user'
diff --git a/openedx/core/djangoapps/enrollments/tests/fixtures/course-enrollments-api-list-valid-data.json b/openedx/core/djangoapps/enrollments/tests/fixtures/course-enrollments-api-list-valid-data.json
index 7822ad562626..6108d92efdf1 100644
--- a/openedx/core/djangoapps/enrollments/tests/fixtures/course-enrollments-api-list-valid-data.json
+++ b/openedx/core/djangoapps/enrollments/tests/fixtures/course-enrollments-api-list-valid-data.json
@@ -114,6 +114,63 @@
]
],
+ [
+ {
+ "email": "student1@example.com"
+ },
+ [
+ {
+ "course_id": "course-v1:e+d+X",
+ "is_active": true,
+ "mode": "honor",
+ "user": "student1",
+ "created": "2018-01-01T00:00:01Z"
+ }
+ ]
+ ],
+ [
+ {
+ "email": "student1@example.com,student2@example.com"
+ },
+ [
+ {
+ "course_id": "course-v1:e+d+X",
+ "is_active": true,
+ "mode": "honor",
+ "user": "student1",
+ "created": "2018-01-01T00:00:01Z"
+ },
+ {
+ "course_id": "course-v1:e+d+X",
+ "is_active": true,
+ "mode": "honor",
+ "user": "student2",
+ "created": "2018-01-01T00:00:01Z"
+ },
+ {
+ "course_id": "course-v1:x+y+Z",
+ "is_active": true,
+ "mode": "honor",
+ "user": "student2",
+ "created": "2018-01-01T00:00:01Z"
+ }
+ ]
+ ],
+ [
+ {
+ "email": "student2@example.com",
+ "course_id": "course-v1:e+d+X"
+ },
+ [
+ {
+ "course_id": "course-v1:e+d+X",
+ "is_active": true,
+ "mode": "honor",
+ "user": "student2",
+ "created": "2018-01-01T00:00:01Z"
+ }
+ ]
+ ],
[
null,
[
diff --git a/openedx/core/djangoapps/enrollments/tests/test_views.py b/openedx/core/djangoapps/enrollments/tests/test_views.py
index a49987ad79af..2318904baf65 100644
--- a/openedx/core/djangoapps/enrollments/tests/test_views.py
+++ b/openedx/core/djangoapps/enrollments/tests/test_views.py
@@ -9,9 +9,9 @@
from unittest.mock import patch
from urllib.parse import quote
-import pytest
import ddt
import httpretty
+import pytest
import pytz
from django.conf import settings
from django.core.cache import cache
@@ -20,14 +20,18 @@
from django.test import Client
from django.test.utils import override_settings
from django.urls import reverse
+from edx_toggles.toggles.testutils import override_waffle_flag
from freezegun import freeze_time
from rest_framework import status
from rest_framework.test import APITestCase
-from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase
-from xmodule.modulestore.tests.factories import CourseFactory, check_mongo_calls_range
from common.djangoapps.course_modes.models import CourseMode
from common.djangoapps.course_modes.tests.factories import CourseModeFactory
+from common.djangoapps.student.models import CourseEnrollment
+from common.djangoapps.student.roles import CourseStaffRole
+from common.djangoapps.student.tests.factories import AdminFactory, SuperuserFactory, UserFactory
+from common.djangoapps.util.models import RateLimitConfiguration
+from common.djangoapps.util.testing import UrlResetMixin
from openedx.core.djangoapps.content.course_overviews.models import CourseOverview
from openedx.core.djangoapps.course_groups import cohorts
from openedx.core.djangoapps.embargo.models import Country, CountryAccessRule, RestrictedCourse
@@ -35,17 +39,16 @@
from openedx.core.djangoapps.enrollments import api, data
from openedx.core.djangoapps.enrollments.errors import CourseEnrollmentError
from openedx.core.djangoapps.enrollments.views import EnrollmentUserThrottle
+from openedx.core.djangoapps.notifications.handlers import ENABLE_NOTIFICATIONS
+from openedx.core.djangoapps.notifications.models import CourseNotificationPreference
from openedx.core.djangoapps.oauth_dispatch.jwt import create_jwt_for_user
from openedx.core.djangoapps.user_api.models import RetirementState, UserOrgTag, UserRetirementStatus
from openedx.core.djangolib.testing.utils import skip_unless_lms
from openedx.core.lib.django_test_client_utils import get_absolute_url
from openedx.features.enterprise_support.tests import FAKE_ENTERPRISE_CUSTOMER
from openedx.features.enterprise_support.tests.mixins.enterprise import EnterpriseServiceMockMixin
-from common.djangoapps.student.models import CourseEnrollment
-from common.djangoapps.student.roles import CourseStaffRole
-from common.djangoapps.student.tests.factories import AdminFactory, SuperuserFactory, UserFactory
-from common.djangoapps.util.models import RateLimitConfiguration
-from common.djangoapps.util.testing import UrlResetMixin
+from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase
+from xmodule.modulestore.tests.factories import CourseFactory, check_mongo_calls_range
class EnrollmentTestMixin:
@@ -153,6 +156,7 @@ def _get_enrollments(self):
@override_settings(EDX_API_KEY="i am a key")
+@override_waffle_flag(ENABLE_NOTIFICATIONS, True)
@ddt.ddt
@skip_unless_lms
class EnrollmentTest(EnrollmentTestMixin, ModuleStoreTestCase, APITestCase, EnterpriseServiceMockMixin):
@@ -195,6 +199,10 @@ def setUp(self):
password=self.PASSWORD,
)
self.client.login(username=self.USERNAME, password=self.PASSWORD)
+ CourseNotificationPreference.objects.create(
+ user=self.user,
+ course_id=self.course.id,
+ )
@ddt.data(
# Default (no course modes in the database)
@@ -229,6 +237,112 @@ def test_enroll(self, course_modes, enrollment_mode):
assert is_active
assert course_mode == enrollment_mode
+ def test_enroll_with_email_staff(self):
+ # Create enrollments with email are allowed if you are staff.
+
+ self.client.logout()
+ AdminFactory.create(username='global_staff', email='global_staff@example.com', password=self.PASSWORD)
+ self.client.login(username="global_staff", password=self.PASSWORD)
+
+ resp = self.client.post(
+ reverse('courseenrollments'),
+ {
+ 'course_details': {
+ 'course_id': str(self.course.id)
+ },
+ 'email': self.user.email
+ },
+ format='json'
+ )
+ assert resp.status_code == status.HTTP_200_OK
+
+ @patch('openedx.core.djangoapps.enrollments.views.EnrollmentListView.has_api_key_permissions')
+ def test_enroll_with_email_server(self, has_api_key_permissions_mock):
+ # Create enrollments with email are allowed if it is a server-to-server request.
+
+ has_api_key_permissions_mock.return_value = True
+ resp = self.client.post(
+ reverse('courseenrollments'),
+ {
+ 'course_details': {
+ 'course_id': str(self.course.id)
+ },
+ 'email': self.user.email
+ },
+ format='json'
+ )
+ assert resp.status_code == status.HTTP_200_OK
+
+ def test_enroll_with_email_without_staff(self):
+ # If you are not staff or server request you can't create enrollments with email.
+
+ resp = self.client.post(
+ reverse('courseenrollments'),
+ {
+ 'course_details': {
+ 'course_id': str(self.course.id)
+ },
+ 'email': self.other_user.email
+ },
+ format='json'
+ )
+ assert resp.status_code == status.HTTP_404_NOT_FOUND
+
+ def test_enroll_with_user_and_email(self):
+ # Creating enrollments the user has priority over the email.
+ resp = self.client.post(
+ reverse('courseenrollments'),
+ {
+ 'course_details': {
+ 'course_id': str(self.course.id)
+ },
+ 'user': self.user.username,
+ 'email': self.other_user.email
+ },
+ format='json'
+ )
+ self.assertContains(resp, self.user.username, status_code=status.HTTP_200_OK)
+
+ def test_enroll_with_user_without_permissions_and_email(self):
+ resp = self.client.post(
+ reverse('courseenrollments'),
+ {
+ 'course_details': {
+ 'course_id': str(self.course.id)
+ },
+ 'user': self.other_user.username,
+ 'email': self.user.email
+ },
+ format='json'
+ )
+ assert resp.status_code == status.HTTP_404_NOT_FOUND
+
+ def test_enroll_with_user_as_self_user(self):
+ resp = self.client.post(
+ reverse('courseenrollments'),
+ {
+ 'course_details': {
+ 'course_id': str(self.course.id)
+ },
+ 'user': self.user.username
+ },
+ format='json'
+ )
+ self.assertContains(resp, self.user.username, status_code=status.HTTP_200_OK)
+
+ def test_enroll_without_user(self):
+ # To check if it takes the request.user.
+ resp = self.client.post(
+ reverse('courseenrollments'),
+ {
+ 'course_details': {
+ 'course_id': str(self.course.id)
+ }
+ },
+ format='json'
+ )
+ self.assertContains(resp, self.user.username, status_code=status.HTTP_200_OK)
+
@ddt.data(
# Default (no course modes in the database)
# Expect that users are automatically enrolled as the default
@@ -1820,3 +1934,105 @@ def test_response_valid_queries(self, args):
results = content['results']
self.assertCountEqual(results, expected_results)
+
+
+@ddt.ddt
+@skip_unless_lms
+class EnrollmentAllowedViewTest(APITestCase):
+ """
+ Test the view that allows the retrieval and creation of enrollment
+ allowed for a given user email and course id.
+ """
+
+ def setUp(self):
+ self.url = reverse('courseenrollmentallowed')
+ self.staff_user = AdminFactory(
+ username='staff',
+ email='staff@example.com',
+ password='edx'
+ )
+ self.student1 = UserFactory(
+ username='student1',
+ email='student1@example.com',
+ password='edx'
+ )
+ self.data = {
+ 'email': 'new-student@example.com',
+ 'course_id': 'course-v1:edX+DemoX+Demo_Course'
+ }
+ self.staff_token = create_jwt_for_user(self.staff_user)
+ self.student_token = create_jwt_for_user(self.student1)
+ self.client.credentials(HTTP_AUTHORIZATION='JWT ' + self.staff_token)
+ return super().setUp()
+
+ @ddt.data(
+ [{'email': 'new-student@example.com', 'course_id': 'course-v1:edX+DemoX+Demo_Course'}, status.HTTP_201_CREATED],
+ [{'course_id': 'course-v1:edX+DemoX+Demo_Course'}, status.HTTP_400_BAD_REQUEST],
+ [{'email': 'new-student@example.com'}, status.HTTP_400_BAD_REQUEST],
+ )
+ @ddt.unpack
+ def test_post_enrollment_allowed(self, data, expected_result):
+ """
+ Expected results:
+ - 201: If the request has email and course_id.
+ - 400: If the request has not.
+ """
+ response = self.client.post(self.url, data)
+ assert response.status_code == expected_result
+
+ def test_post_enrollment_allowed_without_staff(self):
+ """
+ Expected result:
+ - 403: Get when I am not staff.
+ """
+ self.client.credentials(HTTP_AUTHORIZATION='JWT ' + self.student_token)
+ response = self.client.post(self.url, self.data)
+ assert response.status_code == status.HTTP_403_FORBIDDEN
+
+ def test_get_enrollment_allowed_empty(self):
+ """
+ Expected result:
+ - Get the enrollment allowed from the request.user.
+ """
+ response = self.client.get(self.url)
+ assert response.status_code == status.HTTP_200_OK
+
+ def test_get_enrollment_allowed(self):
+ """
+ Expected result:
+ - Get the course enrollment allows.
+ """
+ response = self.client.post(path=self.url, data=self.data)
+ response = self.client.get(self.url, {"email": "new-student@example.com"})
+ self.assertContains(response, 'new-student@example.com', status_code=status.HTTP_200_OK)
+
+ def test_get_enrollment_allowed_without_staff(self):
+ """
+ Expected result:
+ - 403: Get when I am not staff.
+ """
+ self.client.credentials(HTTP_AUTHORIZATION='JWT ' + self.student_token)
+ response = self.client.get(self.url, {"email": "new-student@example.com"})
+ assert response.status_code == status.HTTP_403_FORBIDDEN
+
+ @ddt.data(
+ [{'email': 'new-student@example.com',
+ 'course_id': 'course-v1:edX+DemoX+Demo_Course'},
+ status.HTTP_204_NO_CONTENT],
+ [{'email': 'other-student@example.com',
+ 'course_id': 'course-v1:edX+DemoX+Demo_Course'},
+ status.HTTP_404_NOT_FOUND],
+ [{'course_id': 'course-v1:edX+DemoX+Demo_Course'},
+ status.HTTP_400_BAD_REQUEST],
+ )
+ @ddt.unpack
+ def test_delete_enrollment_allowed(self, delete_data, expected_result):
+ """
+ Expected results:
+ - 204: Enrollment allowed deleted.
+ - 404: Not found, the course enrollment allowed doesn't exists.
+ - 400: Bad request, missing data.
+ """
+ self.client.post(self.url, self.data)
+ response = self.client.delete(self.url, delete_data)
+ assert response.status_code == expected_result
diff --git a/openedx/core/djangoapps/enrollments/urls.py b/openedx/core/djangoapps/enrollments/urls.py
index 6b875ec72df0..39a11a98932e 100644
--- a/openedx/core/djangoapps/enrollments/urls.py
+++ b/openedx/core/djangoapps/enrollments/urls.py
@@ -9,6 +9,7 @@
from .views import (
CourseEnrollmentsApiListView,
+ EnrollmentAllowedView,
EnrollmentCourseDetailView,
EnrollmentListView,
EnrollmentUserRolesView,
@@ -29,4 +30,5 @@
EnrollmentCourseDetailView.as_view(), name='courseenrollmentdetails'),
path('unenroll/', UnenrollmentView.as_view(), name='unenrollment'),
path('roles/', EnrollmentUserRolesView.as_view(), name='roles'),
+ path('enrollment_allowed/', EnrollmentAllowedView.as_view(), name='courseenrollmentallowed'),
]
diff --git a/openedx/core/djangoapps/enrollments/views.py b/openedx/core/djangoapps/enrollments/views.py
index 8124db23ee9d..80f6df853194 100644
--- a/openedx/core/djangoapps/enrollments/views.py
+++ b/openedx/core/djangoapps/enrollments/views.py
@@ -11,6 +11,7 @@
ObjectDoesNotExist,
ValidationError
)
+from django.db import IntegrityError # lint-amnesty, pylint: disable=wrong-import-order
from django.utils.decorators import method_decorator # lint-amnesty, pylint: disable=wrong-import-order
from edx_rest_framework_extensions.auth.jwt.authentication import \
JwtAuthentication # lint-amnesty, pylint: disable=wrong-import-order
@@ -26,7 +27,7 @@
from common.djangoapps.course_modes.models import CourseMode
from common.djangoapps.student.auth import user_has_role
-from common.djangoapps.student.models import CourseEnrollment, User
+from common.djangoapps.student.models import CourseEnrollment, CourseEnrollmentAllowed, User
from common.djangoapps.student.roles import CourseStaffRole, GlobalStaff
from common.djangoapps.util.disable_rate_limit import can_disable_rate_limit
from openedx.core.djangoapps.cors_csrf.authentication import SessionAuthenticationCrossDomainCsrf
@@ -41,7 +42,10 @@
)
from openedx.core.djangoapps.enrollments.forms import CourseEnrollmentsApiListForm
from openedx.core.djangoapps.enrollments.paginators import CourseEnrollmentsApiListPagination
-from openedx.core.djangoapps.enrollments.serializers import CourseEnrollmentsApiListSerializer
+from openedx.core.djangoapps.enrollments.serializers import (
+ CourseEnrollmentAllowedSerializer,
+ CourseEnrollmentsApiListSerializer
+)
from openedx.core.djangoapps.user_api.accounts.permissions import CanRetireUser
from openedx.core.djangoapps.user_api.models import UserRetirementStatus
from openedx.core.djangoapps.user_api.preferences.api import update_email_opt_in
@@ -676,7 +680,7 @@ def post(self, request):
"""
# Get the User, Course ID, and Mode from the request.
- username = request.data.get('user', request.user.username)
+ username = request.data.get('user')
course_id = request.data.get('course_details', {}).get('course_id')
if not course_id:
@@ -700,14 +704,32 @@ def post(self, request):
has_api_key_permissions = self.has_api_key_permissions(request)
# Check that the user specified is either the same user, or this is a server-to-server request.
- if not username:
- username = request.user.username
- if username != request.user.username and not has_api_key_permissions \
+ if username and username != request.user.username and not has_api_key_permissions \
and not GlobalStaff().has_user(request.user):
# Return a 404 instead of a 403 (Unauthorized). If one user is looking up
# other users, do not let them deduce the existence of an enrollment.
return Response(status=status.HTTP_404_NOT_FOUND)
+ # A provided user has priority over a provided email.
+ # Fallback on request user if neither is provided.
+ if not username:
+ email = request.data.get('email')
+ if email:
+ # Only server-to-server or staff users can use the email for the request.
+ if not has_api_key_permissions and not GlobalStaff().has_user(request.user):
+ return Response(status=status.HTTP_404_NOT_FOUND)
+ try:
+ username = User.objects.get(email=email).username
+ except ObjectDoesNotExist:
+ return Response(
+ status=status.HTTP_406_NOT_ACCEPTABLE,
+ data={
+ 'message': f'The user with the email address {email} does not exist.'
+ }
+ )
+ else:
+ username = request.user.username
+
if mode not in (CourseMode.AUDIT, CourseMode.HONOR, None) and not has_api_key_permissions \
and not GlobalStaff().has_user(request.user):
return Response(
@@ -911,6 +933,8 @@ class CourseEnrollmentsApiListView(DeveloperErrorViewMixin, ListAPIView):
GET /api/enrollment/v1/enrollments?course_id={course_id}&username={username}
+ GET /api/enrollment/v1/enrollments?email={email},{email}
+
**Query Parameters for GET**
* course_id: Filters the result to course enrollments for the course corresponding to the
@@ -919,6 +943,9 @@ class CourseEnrollmentsApiListView(DeveloperErrorViewMixin, ListAPIView):
* username: List of comma-separated usernames. Filters the result to the course enrollments
of the given users. Optional.
+ * email: List of comma-separated emails. Filters the result to the course enrollments
+ of the given users. Optional.
+
* page_size: Number of results to return per page. Optional.
* page: Page number to retrieve. Optional.
@@ -981,9 +1008,174 @@ def get_queryset(self):
queryset = CourseEnrollment.objects.all()
course_id = form.cleaned_data.get('course_id')
usernames = form.cleaned_data.get('username')
+ emails = form.cleaned_data.get('email')
if course_id:
queryset = queryset.filter(course_id=course_id)
if usernames:
queryset = queryset.filter(user__username__in=usernames)
+ if emails:
+ queryset = queryset.filter(user__email__in=emails)
return queryset
+
+
+class EnrollmentAllowedView(APIView):
+ """
+ A view that allows the retrieval and creation of enrollment allowed for a given user email and course id.
+ """
+ authentication_classes = (
+ JwtAuthentication,
+ )
+ permission_classes = (permissions.IsAdminUser,)
+ throttle_classes = (EnrollmentUserThrottle,)
+ serializer_class = CourseEnrollmentAllowedSerializer
+
+ def get(self, request):
+ """
+ Returns the enrollments allowed for a given user email.
+
+ **Example Requests**
+
+ GET /api/enrollment/v1/enrollment_allowed?email=user@example.com
+
+ **Parameters**
+
+ - `email` (optional, string, _query_params_) - defaults to the calling user if not provided.
+
+ **Responses**
+ - 200: Success.
+ - 403: Forbidden, you need to be staff.
+ """
+ user_email = request.query_params.get('email')
+ if not user_email:
+ user_email = request.user.email
+
+ enrollments_allowed = CourseEnrollmentAllowed.objects.filter(email=user_email) or []
+ serialized_enrollments_allowed = [
+ CourseEnrollmentAllowedSerializer(enrollment).data for enrollment in enrollments_allowed
+ ]
+
+ return Response(
+ status=status.HTTP_200_OK,
+ data=serialized_enrollments_allowed
+ )
+
+ def post(self, request):
+ """
+ Creates an enrollment allowed for a given user email and course id.
+
+ **Example Request**
+
+ POST /api/enrollment/v1/enrollment_allowed
+
+ Example request data:
+ ```
+ {
+ "email": "user@example.com",
+ "course_id": "course-v1:edX+DemoX+Demo_Course",
+ "auto_enroll": true
+ }
+ ```
+
+ **Parameters**
+
+ - `email` (**required**, string, _body_)
+
+ - `course_id` (**required**, string, _body_)
+
+ - `auto_enroll` (optional, bool: default=false, _body_)
+
+ **Responses**
+ - 200: Success, enrollment allowed found.
+ - 400: Bad request, missing data.
+ - 403: Forbidden, you need to be staff.
+ - 409: Conflict, enrollment allowed already exists.
+ """
+ is_bad_request_response, email, course_id = self.check_required_data(request)
+ auto_enroll = request.data.get('auto_enroll', False)
+ if is_bad_request_response:
+ return is_bad_request_response
+
+ try:
+ enrollment_allowed = CourseEnrollmentAllowed.objects.create(
+ email=email,
+ course_id=course_id,
+ auto_enroll=auto_enroll
+ )
+ except IntegrityError:
+ return Response(
+ status=status.HTTP_409_CONFLICT,
+ data={
+ 'message': f'An enrollment allowed with email {email} and course {course_id} already exists.'
+ }
+ )
+
+ serializer = CourseEnrollmentAllowedSerializer(enrollment_allowed)
+ return Response(
+ status=status.HTTP_201_CREATED,
+ data=serializer.data
+ )
+
+ def delete(self, request):
+ """
+ Deletes an enrollment allowed for a given user email and course id.
+
+ **Example Request**
+
+ DELETE /api/enrollment/v1/enrollment_allowed
+
+ Example request data:
+ ```
+ {
+ "email": "user@example.com",
+ "course_id": "course-v1:edX+DemoX+Demo_Course"
+ }
+ ```
+
+ **Parameters**
+
+ - `email` (**required**, string, _body_)
+
+ - `course_id` (**required**, string, _body_)
+
+ **Responses**
+ - 204: Enrollment allowed deleted.
+ - 400: Bad request, missing data.
+ - 403: Forbidden, you need to be staff.
+ - 404: Not found, the course enrollment allowed doesn't exists.
+ """
+ is_bad_request_response, email, course_id = self.check_required_data(request)
+ if is_bad_request_response:
+ return is_bad_request_response
+
+ try:
+ CourseEnrollmentAllowed.objects.get(
+ email=email,
+ course_id=course_id
+ ).delete()
+ return Response(
+ status=status.HTTP_204_NO_CONTENT,
+ )
+ except ObjectDoesNotExist:
+ return Response(
+ status=status.HTTP_404_NOT_FOUND,
+ data={
+ 'message': f"An enrollment allowed with email {email} and course {course_id} doesn't exists."
+ }
+ )
+
+ def check_required_data(self, request):
+ """
+ Check if the request has email and course_id.
+ """
+ email = request.data.get('email')
+ course_id = request.data.get('course_id')
+ if not email or not course_id:
+ is_bad_request = Response(
+ status=status.HTTP_400_BAD_REQUEST,
+ data={
+ "message": "Please provide a value for 'email' and 'course_id' in the request data."
+ })
+ else:
+ is_bad_request = None
+ return (is_bad_request, email, course_id)
diff --git a/openedx/core/djangoapps/external_user_ids/tests/test_batch_generate_id.py b/openedx/core/djangoapps/external_user_ids/tests/test_batch_generate_id.py
index 1a21fd184020..899554599f12 100644
--- a/openedx/core/djangoapps/external_user_ids/tests/test_batch_generate_id.py
+++ b/openedx/core/djangoapps/external_user_ids/tests/test_batch_generate_id.py
@@ -2,6 +2,7 @@
Test batch_get_or_create in ExternalId model
"""
+import django
from django.test import TransactionTestCase
from common.djangoapps.student.tests.factories import UserFactory
from openedx.core.djangoapps.external_user_ids.models import ExternalId
@@ -19,7 +20,7 @@ class TestBatchGenerateExternalIds(TransactionTestCase):
# 3 - Get external ids that already exists
# 4 - BEGIN (from bulk_create)
# 5 - Create new external ids
- EXPECTED_NUM_OF_QUERIES = 5
+ EXPECTED_NUM_OF_QUERIES = 5 if django.VERSION < (4, 2) else 6
def test_batch_get_or_create_user_ids(self):
"""
diff --git a/openedx/core/djangoapps/notifications/admin.py b/openedx/core/djangoapps/notifications/admin.py
index 9fd69af219e7..52a758b97b03 100644
--- a/openedx/core/djangoapps/notifications/admin.py
+++ b/openedx/core/djangoapps/notifications/admin.py
@@ -3,17 +3,61 @@
"""
from django.contrib import admin
+from django.utils.translation import gettext_lazy as _
+from .base_notification import COURSE_NOTIFICATION_APPS, COURSE_NOTIFICATION_TYPES
from .models import CourseNotificationPreference, Notification
+class NotificationAppNameListFilter(admin.SimpleListFilter):
+ """
+ Shows list filter in django admin of notification apps
+ """
+ title = _("Notification App")
+ parameter_name = "app_name"
+
+ def lookups(self, request, model_admin):
+ lookup_list = [
+ (app_name, app_name)
+ for app_name in COURSE_NOTIFICATION_APPS.keys()
+ ]
+ return lookup_list
+
+ def queryset(self, request, queryset):
+ app_name = self.value()
+ if app_name not in COURSE_NOTIFICATION_APPS.keys():
+ return queryset
+ return queryset.filter(app_name=app_name)
+
+
+class NotificationTypeListFilter(admin.SimpleListFilter):
+ """
+ Shows list filter in django admin of notification types
+ """
+ title = _("Notification Type")
+ parameter_name = "notification_type"
+
+ def lookups(self, request, model_admin):
+ lookup_list = [
+ (notification_type, notification_type)
+ for notification_type in COURSE_NOTIFICATION_TYPES.keys()
+ ]
+ return lookup_list
+
+ def queryset(self, request, queryset):
+ notification_type = self.value()
+ if notification_type not in COURSE_NOTIFICATION_TYPES.keys():
+ return queryset
+ return queryset.filter(notification_type=notification_type)
+
+
class NotificationAdmin(admin.ModelAdmin):
"""
Admin for Notifications
"""
raw_id_fields = ('user',)
- search_fields = ('course_id', 'user__username')
- list_filter = ('app_name',)
+ search_fields = ('course_id', 'app_name', 'notification_type', 'user__username')
+ list_filter = (NotificationAppNameListFilter, NotificationTypeListFilter)
class CourseNotificationPreferenceAdmin(admin.ModelAdmin):
diff --git a/openedx/core/djangoapps/notifications/handlers.py b/openedx/core/djangoapps/notifications/handlers.py
index 7d37bbe7d6fe..c0b85d7c8da8 100644
--- a/openedx/core/djangoapps/notifications/handlers.py
+++ b/openedx/core/djangoapps/notifications/handlers.py
@@ -4,7 +4,7 @@
import logging
from django.core.exceptions import ObjectDoesNotExist
-from django.db import IntegrityError
+from django.db import IntegrityError, transaction
from django.dispatch import receiver
from openedx_events.learning.signals import (
COURSE_ENROLLMENT_CREATED,
@@ -26,12 +26,13 @@ def course_enrollment_post_save(signal, sender, enrollment, metadata, **kwargs):
"""
if ENABLE_NOTIFICATIONS.is_enabled(enrollment.course.course_key):
try:
- CourseNotificationPreference.objects.create(
- user_id=enrollment.user.id,
- course_id=enrollment.course.course_key
- )
+ with transaction.atomic():
+ CourseNotificationPreference.objects.create(
+ user_id=enrollment.user.id,
+ course_id=enrollment.course.course_key
+ )
except IntegrityError:
- log.info(f'CourseNotificationPreference already exists for user {enrollment.user} '
+ log.info(f'CourseNotificationPreference already exists for user {enrollment.user.id} '
f'and course {enrollment.course.course_key}')
diff --git a/openedx/core/djangoapps/notifications/permissions.py b/openedx/core/djangoapps/notifications/permissions.py
new file mode 100644
index 000000000000..8aa47037894c
--- /dev/null
+++ b/openedx/core/djangoapps/notifications/permissions.py
@@ -0,0 +1,27 @@
+"""
+Permissions for notifications
+"""
+from edx_rest_framework_extensions.auth.jwt.authentication import JwtAuthentication
+from edx_rest_framework_extensions.auth.session.authentication import SessionAuthenticationAllowInactiveUser
+from rest_framework.permissions import IsAuthenticated
+
+from openedx.core.lib.api.authentication import BearerAuthenticationAllowInactiveUser
+
+
+def allow_any_authenticated_user():
+ """
+ Function and class decorator that abstracts the authentication and permission checks for api views.
+ Allows both verified and non-verified users
+ """
+ def _decorator(func_or_class):
+ """
+ Requires either OAuth2 or Session-based authentication.
+ """
+ func_or_class.authentication_classes = (
+ JwtAuthentication,
+ BearerAuthenticationAllowInactiveUser,
+ SessionAuthenticationAllowInactiveUser
+ )
+ func_or_class.permission_classes = (IsAuthenticated,)
+ return func_or_class
+ return _decorator
diff --git a/openedx/core/djangoapps/notifications/tests/test_views.py b/openedx/core/djangoapps/notifications/tests/test_views.py
index d423eb7dfe67..88fd9619ef45 100644
--- a/openedx/core/djangoapps/notifications/tests/test_views.py
+++ b/openedx/core/djangoapps/notifications/tests/test_views.py
@@ -91,11 +91,11 @@ def test_course_enrollment_list_view(self, show_notifications_tray):
def test_course_enrollment_api_permission(self):
"""
Calls api without login.
- Check is 403 is returned
+ Check is 401 is returned
"""
url = reverse('enrollment-list')
response = self.client.get(url)
- self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)
+ self.assertEqual(response.status_code, status.HTTP_401_UNAUTHORIZED)
@override_waffle_flag(ENABLE_NOTIFICATIONS, active=True)
@@ -241,7 +241,7 @@ def test_get_user_notification_preference_without_login(self):
Test get user notification preference without login.
"""
response = self.client.get(self.path)
- self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)
+ self.assertEqual(response.status_code, status.HTTP_401_UNAUTHORIZED)
@mock.patch("eventtracking.tracker.emit")
def test_get_user_notification_preference(self, mock_emit):
@@ -411,13 +411,13 @@ def test_list_notifications_with_tray_opened_param(self, mock_emit):
def test_list_notifications_without_authentication(self):
"""
- Test that the view returns 403 if the user is not authenticated.
+ Test that the view returns 401 if the user is not authenticated.
"""
# Make a request to the view without authenticating.
response = self.client.get(self.url)
# Assert that the response is unauthorized.
- self.assertEqual(response.status_code, 403)
+ self.assertEqual(response.status_code, status.HTTP_401_UNAUTHORIZED)
def test_list_notifications_with_expiry_date(self):
"""
@@ -533,10 +533,10 @@ def test_get_unseen_notifications_count_with_show_notifications_tray(self, show_
def test_get_unseen_notifications_count_for_unauthenticated_user(self):
"""
- Test that the endpoint returns 403 for an unauthenticated user.
+ Test that the endpoint returns 401 for an unauthenticated user.
"""
response = self.client.get(self.url)
- self.assertEqual(response.status_code, 403)
+ self.assertEqual(response.status_code, status.HTTP_401_UNAUTHORIZED)
def test_get_unseen_notifications_count_for_user_with_no_notifications(self):
"""
diff --git a/openedx/core/djangoapps/notifications/views.py b/openedx/core/djangoapps/notifications/views.py
index 1b72da965aaa..6d82f67f0120 100644
--- a/openedx/core/djangoapps/notifications/views.py
+++ b/openedx/core/djangoapps/notifications/views.py
@@ -9,7 +9,7 @@
from django.utils.translation import gettext as _
from opaque_keys.edx.keys import CourseKey
from pytz import UTC
-from rest_framework import generics, permissions, status
+from rest_framework import generics, status
from rest_framework.generics import UpdateAPIView
from rest_framework.response import Response
from rest_framework.views import APIView
@@ -19,6 +19,7 @@
CourseNotificationPreference,
get_course_notification_preference_config_version
)
+from openedx.core.djangoapps.notifications.permissions import allow_any_authenticated_user
from .base_notification import COURSE_NOTIFICATION_APPS
from .config.waffle import ENABLE_NOTIFICATIONS
@@ -38,6 +39,7 @@
from .utils import get_show_notifications_tray
+@allow_any_authenticated_user()
class CourseEnrollmentListView(generics.ListAPIView):
"""
API endpoint to get active CourseEnrollments for requester.
@@ -67,7 +69,6 @@ class CourseEnrollmentListView(generics.ListAPIView):
- 403: The requester cannot access resource.
"""
serializer_class = NotificationCourseEnrollmentSerializer
- permission_classes = [permissions.IsAuthenticated]
def get_paginated_response(self, data):
"""
@@ -105,6 +106,7 @@ def list(self, request, *args, **kwargs):
})
+@allow_any_authenticated_user()
class UserNotificationPreferenceView(APIView):
"""
Supports retrieving and patching the UserNotificationPreference
@@ -141,7 +143,6 @@ class UserNotificationPreferenceView(APIView):
}
}
"""
- permission_classes = (permissions.IsAuthenticated,)
def get(self, request, course_key_string):
"""
@@ -220,6 +221,7 @@ def patch(self, request, course_key_string):
return Response(serializer.data, status=status.HTTP_200_OK)
+@allow_any_authenticated_user()
class NotificationListAPIView(generics.ListAPIView):
"""
API view for listing notifications for a user.
@@ -253,7 +255,6 @@ class NotificationListAPIView(generics.ListAPIView):
"""
serializer_class = NotificationSerializer
- permission_classes = (permissions.IsAuthenticated,)
def get_queryset(self):
"""
@@ -279,13 +280,12 @@ def get_queryset(self):
).order_by('-id')
+@allow_any_authenticated_user()
class NotificationCountView(APIView):
"""
API view for getting the unseen notifications count and show_notification_tray flag for a user.
"""
- permission_classes = (permissions.IsAuthenticated,)
-
def get(self, request):
"""
Get the unseen notifications count and show_notification_tray flag for a user.
@@ -334,13 +334,12 @@ def get(self, request):
})
+@allow_any_authenticated_user()
class MarkNotificationsSeenAPIView(UpdateAPIView):
"""
API view for marking user's all notifications seen for a provided app_name.
"""
- permission_classes = (permissions.IsAuthenticated,)
-
def update(self, request, *args, **kwargs):
"""
Marks all notifications for the given app name seen for the authenticated user.
@@ -368,13 +367,12 @@ def update(self, request, *args, **kwargs):
return Response({'message': _('Notifications marked as seen.')}, status=200)
+@allow_any_authenticated_user()
class NotificationReadAPIView(APIView):
"""
API view for marking user notifications as read, either all notifications or a single notification
"""
- permission_classes = (permissions.IsAuthenticated,)
-
def patch(self, request, *args, **kwargs):
"""
Marks all notifications or single notification read for the given
diff --git a/openedx/core/djangoapps/user_api/accounts/tests/test_retirement_views.py b/openedx/core/djangoapps/user_api/accounts/tests/test_retirement_views.py
index 8f34d4ba42d1..6ec6e3694fed 100644
--- a/openedx/core/djangoapps/user_api/accounts/tests/test_retirement_views.py
+++ b/openedx/core/djangoapps/user_api/accounts/tests/test_retirement_views.py
@@ -74,6 +74,7 @@
from openedx.core.djangolib.testing.utils import skip_unless_lms
from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase # lint-amnesty, pylint: disable=wrong-import-order
from xmodule.modulestore.tests.factories import CourseFactory # lint-amnesty, pylint: disable=wrong-import-order
+from openedx.core.djangoapps.oauth_dispatch.tests.factories import ApplicationFactory, AccessTokenFactory
from ...tests.factories import UserOrgTagFactory
from ..views import USER_PROFILE_PII, AccountRetirementView
@@ -263,6 +264,22 @@ def test_called_twice(self):
response = self.client.post(self.url, self.build_post(self.test_password), **headers)
assert response.status_code == status.HTTP_403_FORBIDDEN
+ def test_bearer_auth(self):
+ """
+ Test the account deactivation/logout endpoint using Bearer auth
+ """
+ # testing with broken token
+ headers = {'HTTP_AUTHORIZATION': 'Bearer broken_token'}
+ response = self.client.post(self.url, self.build_post(self.test_password), **headers)
+ assert response.status_code == status.HTTP_401_UNAUTHORIZED
+ # testing with correct token
+ access_token = AccessTokenFactory(user=self.test_user,
+ application=ApplicationFactory(name="test_bearer",
+ user=self.test_user)).token
+ headers = {'HTTP_AUTHORIZATION': f'Bearer {access_token}'}
+ response = self.client.post(self.url, self.build_post(self.test_password), **headers)
+ assert response.status_code == status.HTTP_204_NO_CONTENT
+
@skip_unless_lms
class TestPartnerReportingCleanup(ModuleStoreTestCase):
diff --git a/openedx/core/djangoapps/user_api/accounts/views.py b/openedx/core/djangoapps/user_api/accounts/views.py
index a2598013f6cc..83bdde4f442d 100644
--- a/openedx/core/djangoapps/user_api/accounts/views.py
+++ b/openedx/core/djangoapps/user_api/accounts/views.py
@@ -21,6 +21,7 @@
from edx_ace import ace
from edx_ace.recipient import Recipient
from edx_rest_framework_extensions.auth.jwt.authentication import JwtAuthentication
+from openedx.core.lib.api.authentication import BearerAuthentication
from edx_rest_framework_extensions.auth.session.authentication import SessionAuthenticationAllowInactiveUser
from enterprise.models import EnterpriseCourseEnrollment, EnterpriseCustomerUser, PendingEnterpriseCustomerUser
from integrated_channels.degreed.models import DegreedLearnerDataTransmissionAudit
@@ -567,7 +568,10 @@ class DeactivateLogoutView(APIView):
- Log the user out
- Create a row in the retirement table for that user
"""
- authentication_classes = (JwtAuthentication, SessionAuthentication,)
+ # BearerAuthentication is added here to support account deletion
+ # from the mobile app until it moves to JWT Auth.
+ # See mobile roadmap issue https://github.com/openedx/edx-platform/issues/33307.
+ authentication_classes = (JwtAuthentication, SessionAuthentication, BearerAuthentication)
permission_classes = (permissions.IsAuthenticated,)
def post(self, request):
diff --git a/openedx/core/djangoapps/user_authn/views/register.py b/openedx/core/djangoapps/user_authn/views/register.py
index 083a821b9314..04b0ae678f65 100644
--- a/openedx/core/djangoapps/user_authn/views/register.py
+++ b/openedx/core/djangoapps/user_authn/views/register.py
@@ -190,10 +190,9 @@ def create_account_with_params(request, params): # pylint: disable=too-many-sta
set_custom_attribute('register_user_tpa', pipeline.running(request))
extended_profile_fields = configuration_helpers.get_value('extended_profile_fields', [])
# Can't have terms of service for certain SHIB users, like at Stanford
- registration_fields = getattr(settings, 'REGISTRATION_EXTRA_FIELDS', {})
tos_required = (
- registration_fields.get('terms_of_service') != 'hidden' or
- registration_fields.get('honor_code') != 'hidden'
+ extra_fields.get('terms_of_service') != 'hidden' or
+ extra_fields.get('honor_code') != 'hidden'
)
form = AccountCreationForm(
diff --git a/openedx/core/lib/xblock_serializer/block_serializer.py b/openedx/core/lib/xblock_serializer/block_serializer.py
index 84736a7762ff..b91ca1594cd9 100644
--- a/openedx/core/lib/xblock_serializer/block_serializer.py
+++ b/openedx/core/lib/xblock_serializer/block_serializer.py
@@ -38,7 +38,7 @@ def __init__(self, block):
if path not in [sf.name for sf in self.static_files]:
self.static_files.append(StaticFile(name=path, url=asset['url'], data=None))
- if block.scope_ids.usage_id.block_type == 'problem':
+ if block.scope_ids.usage_id.block_type in ['problem', 'vertical']:
py_lib_zip_file = utils.get_python_lib_zip_if_using(self.olx_str, course_key)
if py_lib_zip_file:
self.static_files.append(py_lib_zip_file)
@@ -112,7 +112,10 @@ def _serialize_html_block(self, block) -> etree.Element:
olx_node.attrib["editor"] = block.editor
if block.use_latex_compiler:
olx_node.attrib["use_latex_compiler"] = "true"
- olx_node.text = etree.CDATA("\n" + block.data + "\n")
+
+ # Escape any CDATA special chars
+ escaped_block_data = block.data.replace("]]>", "]]>")
+ olx_node.text = etree.CDATA("\n" + escaped_block_data + "\n")
return olx_node
diff --git a/openedx/core/lib/xblock_utils/__init__.py b/openedx/core/lib/xblock_utils/__init__.py
index 0910018f6046..26127dbfb3b8 100644
--- a/openedx/core/lib/xblock_utils/__init__.py
+++ b/openedx/core/lib/xblock_utils/__init__.py
@@ -452,7 +452,7 @@ def xblock_resource_pkg(block):
ProblemBlock, and most other built-in blocks currently. Handling for these
assets does not interact with this function.
2. The (preferred) standard XBlock runtime resource loading system, used by
- LibrarySourcedBlock. Handling for these assets *does* interact with this
+ LibraryContentBlock. Handling for these assets *does* interact with this
function.
We hope to migrate to (2) eventually, tracked by:
diff --git a/openedx/features/content_tagging/rules.py b/openedx/features/content_tagging/rules.py
deleted file mode 100644
index df256b9331dd..000000000000
--- a/openedx/features/content_tagging/rules.py
+++ /dev/null
@@ -1,127 +0,0 @@
-"""Django rules-based permissions for tagging"""
-
-import openedx_tagging.core.tagging.rules as oel_tagging
-import rules
-from django.contrib.auth import get_user_model
-
-from common.djangoapps.student.auth import is_content_creator
-
-from .models import TaxonomyOrg
-
-User = get_user_model()
-
-
-def is_taxonomy_user(user: User, taxonomy: oel_tagging.Taxonomy = None) -> bool:
- """
- Returns True if the given user is a Taxonomy User for the given content taxonomy.
-
- Taxonomy users include global staff and superusers, plus course creators who can create courses for any org.
- Otherwise, we need a taxonomy provided to determine if the user is an org-level course creator for one of the
- orgs allowed to use this taxonomy.
- """
- if oel_tagging.is_taxonomy_admin(user):
- return True
-
- if not taxonomy:
- return is_content_creator(user, None)
-
- taxonomy_orgs = TaxonomyOrg.get_organizations(
- taxonomy=taxonomy,
- rel_type=TaxonomyOrg.RelType.OWNER,
- )
- for org in taxonomy_orgs:
- if is_content_creator(user, org.short_name):
- return True
- return False
-
-
-def is_taxonomy_admin(user: User) -> bool:
- """
- Returns True if the given user is a Taxonomy Admin.
-
- Taxonomy Admins include global staff and superusers.
- """
- return oel_tagging.is_taxonomy_admin(user)
-
-
-@rules.predicate
-def can_view_taxonomy(user: User, taxonomy: oel_tagging.Taxonomy = None) -> bool:
- """
- Everyone can potentially view a taxonomy (taxonomy=None). The object permission must be checked
- to determine if the user can view a specific taxonomy.
- Only taxonomy admins can view a disabled taxonomy.
- """
- if not taxonomy:
- return True
-
- taxonomy = taxonomy.cast()
-
- return taxonomy.enabled or is_taxonomy_admin(user)
-
-
-@rules.predicate
-def can_add_taxonomy(user: User) -> bool:
- """
- Only taxonomy admins can add taxonomies.
- """
- return is_taxonomy_admin(user)
-
-
-@rules.predicate
-def can_change_taxonomy(user: User, taxonomy: oel_tagging.Taxonomy = None) -> bool:
- """
- Only taxonomy admins can change a taxonomies.
- Even taxonomy admins cannot change system taxonomies.
- """
- if taxonomy:
- taxonomy = taxonomy.cast()
-
- return (not taxonomy or (not taxonomy.system_defined)) and is_taxonomy_admin(user)
-
-
-@rules.predicate
-def can_change_taxonomy_tag(user: User, tag: oel_tagging.Tag = None) -> bool:
- """
- Even taxonomy admins cannot add tags to system taxonomies (their tags are system-defined), or free-text taxonomies
- (these don't have predefined tags).
- """
- taxonomy = tag.taxonomy if tag else None
- if taxonomy:
- taxonomy = taxonomy.cast()
- return is_taxonomy_admin(user) and (
- not tag
- or not taxonomy
- or (taxonomy and not taxonomy.allow_free_text and not taxonomy.system_defined)
- )
-
-
-@rules.predicate
-def can_change_object_tag(user: User, object_tag: oel_tagging.ObjectTag = None) -> bool:
- """
- Taxonomy users can create or modify object tags on enabled taxonomies.
- """
- taxonomy = object_tag.taxonomy if object_tag else None
- if taxonomy:
- taxonomy = taxonomy.cast()
- return is_taxonomy_user(user, taxonomy) and (
- not object_tag or not taxonomy or (taxonomy and taxonomy.cast().enabled)
- )
-
-
-# Taxonomy
-rules.set_perm("oel_tagging.add_taxonomy", can_add_taxonomy)
-rules.set_perm("oel_tagging.change_taxonomy", can_change_taxonomy)
-rules.set_perm("oel_tagging.delete_taxonomy", can_change_taxonomy)
-rules.set_perm("oel_tagging.view_taxonomy", can_view_taxonomy)
-
-# Tag
-rules.set_perm("oel_tagging.add_tag", can_change_taxonomy_tag)
-rules.set_perm("oel_tagging.change_tag", can_change_taxonomy_tag)
-rules.set_perm("oel_tagging.delete_tag", can_change_taxonomy_tag)
-rules.set_perm("oel_tagging.view_tag", rules.always_allow)
-
-# ObjectTag
-rules.set_perm("oel_tagging.add_object_tag", can_change_object_tag)
-rules.set_perm("oel_tagging.change_object_tag", can_change_object_tag)
-rules.set_perm("oel_tagging.delete_object_tag", can_change_object_tag)
-rules.set_perm("oel_tagging.view_object_tag", rules.always_allow)
diff --git a/openedx/features/enterprise_support/enrollments/tests/test_utils.py b/openedx/features/enterprise_support/enrollments/tests/test_utils.py
index d0588b2f010d..35a93311866a 100644
--- a/openedx/features/enterprise_support/enrollments/tests/test_utils.py
+++ b/openedx/features/enterprise_support/enrollments/tests/test_utils.py
@@ -1,25 +1,24 @@
"""
Test the enterprise support utils.
"""
-import ddt
from unittest import mock
from unittest.case import TestCase
from django.core.exceptions import ObjectDoesNotExist
-from django.test import override_settings
from opaque_keys.edx.keys import CourseKey
from openedx.core.djangoapps.course_groups.cohorts import CourseUserGroup
-from openedx.core.djangoapps.enrollments.errors import CourseEnrollmentError, CourseEnrollmentExistsError
+from openedx.core.djangoapps.enrollments.errors import (
+ CourseEnrollmentError,
+ CourseEnrollmentExistsError,
+)
from openedx.core.djangolib.testing.utils import skip_unless_lms
from openedx.features.enterprise_support.enrollments.exceptions import (
CourseIdMissingException,
UserDoesNotExistException
)
-from openedx.features.enterprise_support.enrollments.utils import (
- lms_enroll_user_in_course,
- lms_update_or_create_enrollment,
-)
+from openedx.features.enterprise_support.enrollments.utils import lms_update_or_create_enrollment
+
COURSE_STRING = 'course-v1:OpenEdX+OutlineCourse+Run3'
ENTERPRISE_UUID = 'enterprise_uuid'
COURSE_ID = CourseKey.from_string(COURSE_STRING)
@@ -29,7 +28,6 @@
@skip_unless_lms
-@ddt.ddt
class EnrollmentUtilsTest(TestCase):
"""
Test enterprise support utils.
@@ -41,221 +39,97 @@ def setUp(self):
self.a_user.id = USER_ID
self.a_user.username = USERNAME
- def run_test_with_setting(
- self,
- setting,
- mock_update_create_enroll,
- mock_enroll_user,
- test_function_true,
- test_function_false,
- ):
- """
- Run a test with a setting.
- """
- with override_settings(
- ENABLE_ENTERPRISE_BACKEND_EMET_AUTO_UPGRADE_ENROLLMENT_MODE=setting
- ):
- if setting:
- return test_function_true(mock_update_create_enroll)
- return test_function_false(mock_enroll_user)
-
- @mock.patch('openedx.features.enterprise_support.enrollments.utils.lms_enroll_user_in_course')
- @mock.patch('openedx.features.enterprise_support.enrollments.utils.lms_update_or_create_enrollment')
- @ddt.data(True, False)
- def test_validation_of_inputs_course_id(self, setting_value, mock_update_create_enroll, mock_enroll_user):
- test_function_true = lambda mock_fn: lms_update_or_create_enrollment(
- USERNAME, None, COURSE_MODE, is_active=True, enterprise_uuid=ENTERPRISE_UUID
- )
- test_function_false = lambda mock_fn: lms_enroll_user_in_course(USERNAME, None, COURSE_MODE, ENTERPRISE_UUID)
+ def test_validation_of_inputs_course_id(self):
with self.assertRaises(CourseIdMissingException):
- self.run_test_with_setting(
- setting_value,
- mock_update_create_enroll,
- mock_enroll_user,
- test_function_true,
- test_function_false
+ lms_update_or_create_enrollment(
+ USERNAME, None, COURSE_MODE, is_active=True, enterprise_uuid=ENTERPRISE_UUID
)
- @mock.patch('openedx.features.enterprise_support.enrollments.utils.lms_enroll_user_in_course')
- @mock.patch('openedx.features.enterprise_support.enrollments.utils.lms_update_or_create_enrollment')
- @ddt.data(True, False)
- def test_validation_of_inputs_user_not_provided(self, setting_value, mock_update_create_enroll, mock_enroll_user):
- test_function_true = lambda mock_fn: lms_update_or_create_enrollment(
- None, COURSE_ID, COURSE_MODE, is_active=True, enterprise_uuid=ENTERPRISE_UUID
- )
- test_function_false = lambda mock_fn: lms_enroll_user_in_course(None, COURSE_ID, COURSE_MODE, ENTERPRISE_UUID)
+ def test_validation_of_inputs_user_not_provided(self):
with self.assertRaises(UserDoesNotExistException):
- self.run_test_with_setting(
- setting_value,
- mock_update_create_enroll,
- mock_enroll_user,
- test_function_true,
- test_function_false
+ lms_update_or_create_enrollment(
+ None, COURSE_ID, COURSE_MODE, is_active=True, enterprise_uuid=ENTERPRISE_UUID
)
- @mock.patch('openedx.features.enterprise_support.enrollments.utils.lms_enroll_user_in_course')
- @mock.patch('openedx.features.enterprise_support.enrollments.utils.lms_update_or_create_enrollment')
@mock.patch('openedx.features.enterprise_support.enrollments.utils.User.objects.get')
@mock.patch('openedx.features.enterprise_support.enrollments.utils.transaction')
- @ddt.data(True, False)
def test_validation_of_inputs_user_not_found(
self,
- setting_value,
mock_tx,
mock_user_model,
- mock_update_create_enroll,
- mock_enroll_user
):
mock_tx.return_value.atomic.side_effect = None
mock_user_model.side_effect = ObjectDoesNotExist()
- test_function_true = lambda mock_fn: lms_update_or_create_enrollment(
- USERNAME, COURSE_ID, COURSE_MODE, is_active=True, enterprise_uuid=ENTERPRISE_UUID
- )
- test_function_false = lambda mock_fn: lms_enroll_user_in_course(
- USERNAME,
- COURSE_ID,
- COURSE_MODE,
- ENTERPRISE_UUID
- )
with self.assertRaises(UserDoesNotExistException):
- self.run_test_with_setting(
- setting_value,
- mock_update_create_enroll,
- mock_enroll_user,
- test_function_true,
- test_function_false
+ lms_update_or_create_enrollment(
+ USERNAME, COURSE_ID, COURSE_MODE, is_active=True, enterprise_uuid=ENTERPRISE_UUID
)
- @mock.patch('openedx.features.enterprise_support.enrollments.utils.lms_enroll_user_in_course')
- @mock.patch('openedx.features.enterprise_support.enrollments.utils.lms_update_or_create_enrollment')
@mock.patch('openedx.features.enterprise_support.enrollments.utils.enrollment_api.add_enrollment')
@mock.patch('openedx.features.enterprise_support.enrollments.utils.enrollment_api.get_enrollment')
@mock.patch('openedx.features.enterprise_support.enrollments.utils.User.objects.get')
@mock.patch('openedx.features.enterprise_support.enrollments.utils.transaction')
- @ddt.data(True, False)
def test_course_enrollment_error_raises(
self,
- setting_value,
mock_tx,
mock_user_model,
mock_get_enrollment_api,
mock_add_enrollment_api,
- mock_update_create_enroll,
- mock_enroll_user
):
- test_function_true = lambda mock_fn: lms_update_or_create_enrollment(
- USERNAME, COURSE_ID, COURSE_MODE, is_active=True, enterprise_uuid=ENTERPRISE_UUID
- )
- test_function_false = lambda mock_fn: lms_enroll_user_in_course(
- USERNAME,
- COURSE_ID,
- COURSE_MODE,
- ENTERPRISE_UUID
- )
-
mock_add_enrollment_api.side_effect = CourseEnrollmentError("test")
mock_tx.return_value.atomic.side_effect = None
mock_user_model.return_value = self.a_user
-
- enrollment_response = {'mode': COURSE_MODE, 'is_active': True} if not setting_value else None
- mock_get_enrollment_api.return_value = enrollment_response
+ mock_get_enrollment_api.return_value = None
with self.assertRaises(CourseEnrollmentError):
- self.run_test_with_setting(
- setting_value,
- mock_update_create_enroll,
- mock_enroll_user,
- test_function_true,
- test_function_false
+ lms_update_or_create_enrollment(
+ USERNAME, COURSE_ID, COURSE_MODE, is_active=True, enterprise_uuid=ENTERPRISE_UUID
)
mock_get_enrollment_api.assert_called_once_with(USERNAME, str(COURSE_ID))
- @mock.patch('openedx.features.enterprise_support.enrollments.utils.lms_enroll_user_in_course')
- @mock.patch('openedx.features.enterprise_support.enrollments.utils.lms_update_or_create_enrollment')
@mock.patch('openedx.features.enterprise_support.enrollments.utils.enrollment_api.add_enrollment')
@mock.patch('openedx.features.enterprise_support.enrollments.utils.enrollment_api.get_enrollment')
@mock.patch('openedx.features.enterprise_support.enrollments.utils.User.objects.get')
@mock.patch('openedx.features.enterprise_support.enrollments.utils.transaction')
- @ddt.data(True, False)
def test_course_group_error_raises(
self,
- setting_value,
mock_tx,
mock_user_model,
mock_get_enrollment_api,
mock_add_enrollment_api,
- mock_update_create_enroll,
- mock_enroll_user
):
- test_function_true = lambda mock_fn: lms_update_or_create_enrollment(
- USERNAME, COURSE_ID, COURSE_MODE, is_active=True, enterprise_uuid=ENTERPRISE_UUID
- )
- test_function_false = lambda mock_fn: lms_enroll_user_in_course(
- USERNAME,
- COURSE_ID,
- COURSE_MODE,
- ENTERPRISE_UUID
- )
mock_add_enrollment_api.side_effect = CourseUserGroup.DoesNotExist()
mock_tx.return_value.atomic.side_effect = None
mock_user_model.return_value = self.a_user
- enrollment_response = {'mode': COURSE_MODE, 'is_active': True} if not setting_value else None
- mock_get_enrollment_api.return_value = enrollment_response
+ mock_get_enrollment_api.return_value = None
with self.assertRaises(CourseUserGroup.DoesNotExist):
- self.run_test_with_setting(
- setting_value,
- mock_update_create_enroll,
- mock_enroll_user,
- test_function_true,
- test_function_false
+ lms_update_or_create_enrollment(
+ USERNAME, COURSE_ID, COURSE_MODE, is_active=True, enterprise_uuid=ENTERPRISE_UUID
)
mock_get_enrollment_api.assert_called_once_with(USERNAME, str(COURSE_ID))
- @mock.patch('openedx.features.enterprise_support.enrollments.utils.lms_enroll_user_in_course')
- @mock.patch('openedx.features.enterprise_support.enrollments.utils.lms_update_or_create_enrollment')
@mock.patch('openedx.features.enterprise_support.enrollments.utils.enrollment_api.add_enrollment')
@mock.patch('openedx.features.enterprise_support.enrollments.utils.enrollment_api.get_enrollment')
@mock.patch('openedx.features.enterprise_support.enrollments.utils.User.objects.get')
@mock.patch('openedx.features.enterprise_support.enrollments.utils.transaction')
- @ddt.data(True, False)
def test_calls_enrollment_and_cohort_apis(
self,
- setting,
mock_tx,
mock_user_model,
mock_get_enrollment_api,
mock_add_enrollment_api,
- mock_update_create_enroll,
- mock_enroll_user,
):
- test_function_true = lambda mock_fn: lms_update_or_create_enrollment(
- USERNAME, COURSE_ID, COURSE_MODE, is_active=True, enterprise_uuid=ENTERPRISE_UUID
- )
- test_function_false = lambda mock_fn: lms_enroll_user_in_course(
- USERNAME,
- COURSE_ID,
- COURSE_MODE,
- ENTERPRISE_UUID
- )
expected_response = {'mode': COURSE_MODE, 'is_active': True}
- enrollment_response = {'mode': COURSE_MODE, 'is_active': True}
mock_add_enrollment_api.return_value = expected_response
mock_tx.return_value.atomic.side_effect = None
mock_user_model.return_value = self.a_user
+ mock_get_enrollment_api.return_value = None
- if setting:
- mock_get_enrollment_api.return_value = None
- else:
- mock_get_enrollment_api.return_value = enrollment_response
- response = self.run_test_with_setting(
- setting,
- mock_update_create_enroll,
- mock_enroll_user,
- test_function_true,
- test_function_false
+ response = lms_update_or_create_enrollment(
+ USERNAME, COURSE_ID, COURSE_MODE, is_active=True, enterprise_uuid=ENTERPRISE_UUID
)
assert response == expected_response
mock_add_enrollment_api.assert_called_once_with(
@@ -268,32 +142,17 @@ def test_calls_enrollment_and_cohort_apis(
)
mock_get_enrollment_api.assert_called_once_with(USERNAME, str(COURSE_ID))
- @mock.patch('openedx.features.enterprise_support.enrollments.utils.lms_enroll_user_in_course')
- @mock.patch('openedx.features.enterprise_support.enrollments.utils.lms_update_or_create_enrollment')
@mock.patch('openedx.features.enterprise_support.enrollments.utils.enrollment_api.add_enrollment')
@mock.patch('openedx.features.enterprise_support.enrollments.utils.enrollment_api.get_enrollment')
@mock.patch('openedx.features.enterprise_support.enrollments.utils.User.objects.get')
@mock.patch('openedx.features.enterprise_support.enrollments.utils.transaction')
- @ddt.data(True, False)
def test_existing_enrollment_does_not_fail(
self,
- setting_value,
mock_tx,
mock_user_model,
mock_get_enrollment_api,
mock_add_enrollment_api,
- mock_update_create_enroll,
- mock_enroll_user,
):
- test_function_true = lambda mock_fn: lms_update_or_create_enrollment(
- USERNAME, COURSE_ID, COURSE_MODE, is_active=True, enterprise_uuid=ENTERPRISE_UUID
- )
- test_function_false = lambda mock_fn: lms_enroll_user_in_course(
- USERNAME,
- COURSE_ID,
- COURSE_MODE,
- ENTERPRISE_UUID
- )
expected_response = {'mode': COURSE_MODE, 'is_active': True}
enrollment_response = {'mode': COURSE_MODE, 'is_active': True}
@@ -301,29 +160,13 @@ def test_existing_enrollment_does_not_fail(
mock_tx.return_value.atomic.side_effect = None
mock_get_enrollment_api.return_value = enrollment_response
-
mock_user_model.return_value = self.a_user
- response = self.run_test_with_setting(
- setting_value,
- mock_update_create_enroll,
- mock_enroll_user,
- test_function_true,
- test_function_false
+ response = lms_update_or_create_enrollment(
+ USERNAME, COURSE_ID, COURSE_MODE, is_active=True, enterprise_uuid=ENTERPRISE_UUID
)
- if setting_value:
- mock_add_enrollment_api.assert_not_called()
- assert response == expected_response
- else:
- mock_add_enrollment_api.assert_called_once_with(
- USERNAME,
- str(COURSE_ID),
- mode=COURSE_MODE,
- is_active=True,
- enrollment_attributes=None,
- enterprise_uuid=ENTERPRISE_UUID,
- )
- assert response is None
+ mock_add_enrollment_api.assert_not_called()
+ assert response == expected_response
mock_get_enrollment_api.assert_called_once()
@mock.patch('openedx.features.enterprise_support.enrollments.utils.enrollment_api.update_enrollment')
diff --git a/openedx/features/enterprise_support/enrollments/utils.py b/openedx/features/enterprise_support/enrollments/utils.py
index f44de3e2d416..1a8a105f4b34 100644
--- a/openedx/features/enterprise_support/enrollments/utils.py
+++ b/openedx/features/enterprise_support/enrollments/utils.py
@@ -22,51 +22,6 @@
log = logging.getLogger(__name__)
-def lms_enroll_user_in_course(
- username,
- course_id,
- mode,
- enterprise_uuid,
- is_active=True,
-):
- """
- Temporarily keeping the original enrollment function to help with deployment
- """
- user = _validate_enrollment_inputs(username, course_id)
-
- with transaction.atomic():
- try:
- response = enrollment_api.add_enrollment(
- username,
- str(course_id),
- mode=mode,
- is_active=is_active,
- enrollment_attributes=None,
- enterprise_uuid=enterprise_uuid,
- )
- log.info('The user [%s] has been enrolled in course run [%s].', username, course_id)
- return response
- except CourseEnrollmentExistsError as error: # pylint: disable=unused-variable
- log.warning('An enrollment already exists for user [%s] in course run [%s].', username, course_id)
- return None
- except CourseEnrollmentError as error:
- log.exception("An error occurred while creating the new course enrollment for user "
- "[%s] in course run [%s]", username, course_id)
- raise error
- finally:
- # Assumes that the ecommerce service uses an API key to authenticate.
- current_enrollment = enrollment_api.get_enrollment(username, str(course_id))
- audit_log(
- 'enrollment_change_requested',
- course_id=str(course_id),
- requested_mode=mode,
- actual_mode=current_enrollment['mode'] if current_enrollment else None,
- requested_activation=is_active,
- actual_activation=current_enrollment['is_active'] if current_enrollment else None,
- user_id=user.id
- )
-
-
def lms_update_or_create_enrollment(
username,
course_id,
diff --git a/requirements/README.rst b/requirements/README.rst
index 4e14554e000f..c602cc8905b1 100644
--- a/requirements/README.rst
+++ b/requirements/README.rst
@@ -12,22 +12,29 @@ directly in the requirements directory.)
.. _OEP-18: https://github.com/openedx/open-edx-proposals/blob/master/oeps/oep-0018-bp-python-dependencies.rst
-Upgrading all dependencies
-**************************
+While the ``*.in`` files are intended to be updated manually, the ``*.txt`` files should only be manipulated using Makefile targets in a Linux environment (to match our build and deploy systems). For developers on Mac, this can be achieved by using the GitHub workflows or by running Make targets from inside devstack's lms-shell or another Linux environment.
-You can use the `upgrade-requirements Github Workflow `_ to make a PR that upgrades as many packages as possible.
+If you don't have write permissions to openedx/edx-platform, you'll need to run these workflows on a fork.
-Upgrading just one dependency
-*****************************
+Workflows and Makefile targets
+******************************
+
+Add a dependency
+================
+
+To add a Python dependency, specify it in the appropriate ``requirements/edx/*.in`` file, push that up to a branch, and then use the `compile-python-requirements.yml workflow `_ to run ``make compile-requirements`` against your branch. This will ensure the lockfiles are updated with any transitive dependencies and will ping you on a PR for updating your branch.
+
+Upgrade just one dependency
+===========================
Want to upgrade just *one* dependency without pulling in other upgrades? You can `run the upgrade-one-python-dependency.yml workflow `_ to have a pull request made against a branch of your choice.
-Or, if you need to do it locally, you can use the ``upgrade-package`` make target directly. For example, you could run ``make upgrade-package package=ecommerce``. But the GitHub workflow is likely easier.
+Or, if you need to do it locally, you can use the ``upgrade-package`` make target directly. For example, you could run ``make upgrade-package package=ecommerce``.
If your dependency is pinned in constraints.txt, you'll need to enter an explicit version number in the appropriate field when running the workflow; this will include an update to the constraint file in the resulting PR.
-Downgrading a dependency
-************************
+Downgrade a dependency
+======================
If you instead need to surgically *downgrade* a dependency:
@@ -36,9 +43,12 @@ If you instead need to surgically *downgrade* a dependency:
# frobulator 2.x has breaking API changes; see https://github.com/openedx/edx-platform/issue/1234567 for fixing it
frobulator<2.0.0
-2. Run ``make compile-requirements``
+2. After pushing that up to a branch, use the `compile-python-requirements.yml workflow `_ to run ``make compile-requirements`` against your branch.
+
+Upgrade all dependencies
+========================
-This is considerably safer than trying to manually edit the ``*.txt`` files, which can easily result in incompatible dependency versions.
+ You can use the `upgrade-requirements Github Workflow `_ to make a PR that upgrades as many packages as possible to newer versions. This is a wrapper around ``make upgrade`` and is run on a schedule to keep dependencies up to date.
Inconsistent dependencies
*************************
diff --git a/requirements/constraints.txt b/requirements/constraints.txt
index 3594f741809e..ee3c12f7a11c 100644
--- a/requirements/constraints.txt
+++ b/requirements/constraints.txt
@@ -20,20 +20,17 @@ celery>=5.2.2,<6.0.0
# required for celery>=5.2.0;<5.3.0
click>=8.0,<9.0
-# django-storages version 1.11.1 is major version upgrade.
-django-storages==1.11.1
-
+# each version upgrade need release notes review.
+django-storages==1.14
# The team that owns this package will manually bump this package rather than having it pulled in automatically.
# This is to allow them to better control its deployment and to do it in a process that works better
# for them.
-edx-enterprise==4.1.11
+edx-enterprise==4.3.2
-# 1. django-oauth-toolkit version >=2.0.0 has breaking changes. More details
-# mentioned on this issue https://github.com/openedx/edx-platform/issues/32884
-# 2. Versions from 1.5.0 to 2.0.0 have some migrations related changes.
-# so we're upgrading minor versions one by one.
-django-oauth-toolkit==1.4.1
+# django-oauth-toolkit version >=2.0.0 has breaking changes. More details
+# mentioned on this issue https://github.com/openedx/edx-platform/issues/32884
+django-oauth-toolkit==1.7.1
# constrained in opaque_keys. migration guide here: https://pymongo.readthedocs.io/en/4.0/migrate-to-pymongo4.html
@@ -78,8 +75,7 @@ pylint<2.16.0 # greater version failing quality test. Fix them in seperate ticke
# Deprecated version of the AWS SDK;
# we should stop using this
boto==2.39.0
-boto3==1.7.0 # Amazon Web Services SDK for Python
-botocore==1.10.84 # via boto3, s3transfer
+
# adding these constraints to minimize boto3 and botocore changeset
social-auth-core==4.3.0
@@ -121,11 +117,16 @@ djangorestframework-stubs==3.14.0 # Pinned to match django-stubs. Remove this w
# https://github.com/openedx/edx-platform/issues/31616
libsass==0.10.0
-# incremental upgrade
-django-simple-history==3.3.0
-
# greater version breaking upgrade builds
click==8.1.6
-# plz upgrade this in separate ticket
-redis==4.6.0
+# openedx-events 8.6.0 introduces publishing via configuration. Ticket to unpin: https://github.com/edx/edx-arch-experiments/issues/381
+openedx-events<8.6.0 # Open edX Events from Hooks Extension Framework (OEP-50)
+
+# pinning this version to avoid updates while the library is being developed
+openedx-learning==0.1.6
+
+# lti-consumer-xblock 9.6.2 contains a breaking change that makes
+# existing custom parameter configurations unusable.
+# https://github.com/openedx/xblock-lti-consumer/issues/410 has been opened to track a fix
+lti-consumer-xblock==9.6.1
diff --git a/requirements/edx-sandbox/py38.txt b/requirements/edx-sandbox/py38.txt
index bc49374be05f..27138116fdac 100644
--- a/requirements/edx-sandbox/py38.txt
+++ b/requirements/edx-sandbox/py38.txt
@@ -14,7 +14,7 @@ click==8.1.6
# nltk
codejail-includes==1.0.0
# via -r requirements/edx-sandbox/py38.in
-contourpy==1.1.0
+contourpy==1.1.1
# via matplotlib
cryptography==38.0.4
# via
@@ -24,7 +24,7 @@ cycler==0.11.0
# via matplotlib
fonttools==4.42.1
# via matplotlib
-importlib-resources==6.0.1
+importlib-resources==6.1.0
# via matplotlib
joblib==1.3.2
# via nltk
@@ -38,7 +38,7 @@ markupsafe==2.1.3
# via
# chem
# openedx-calc
-matplotlib==3.7.2
+matplotlib==3.7.3
# via -r requirements/edx-sandbox/py38.in
mpmath==1.3.0
# via sympy
@@ -65,7 +65,7 @@ pillow==9.5.0
# matplotlib
pycparser==2.21
# via cffi
-pyparsing==3.0.9
+pyparsing==3.1.1
# via
# -r requirements/edx-sandbox/py38.in
# chem
@@ -94,5 +94,5 @@ sympy==1.12
# openedx-calc
tqdm==4.66.1
# via nltk
-zipp==3.16.2
+zipp==3.17.0
# via importlib-resources
diff --git a/requirements/edx/base.txt b/requirements/edx/base.txt
index 07bea7af5afa..5074dbadd097 100644
--- a/requirements/edx/base.txt
+++ b/requirements/edx/base.txt
@@ -77,16 +77,14 @@ boto==2.39.0
# via
# -c requirements/edx/../constraints.txt
# -r requirements/edx/kernel.in
-boto3==1.7.0
+boto3==1.28.53
# via
- # -c requirements/edx/../constraints.txt
# -r requirements/edx/kernel.in
# django-ses
# fs-s3fs
# ora2
-botocore==1.10.84
+botocore==1.31.53
# via
- # -c requirements/edx/../constraints.txt
# -r requirements/edx/kernel.in
# boto3
# s3transfer
@@ -209,6 +207,7 @@ django==3.2.21
# done-xblock
# drf-jwt
# drf-nested-routers
+ # drf-spectacular
# drf-yasg
# edx-ace
# edx-api-doc-tools
@@ -252,13 +251,13 @@ django==3.2.21
# xss-utils
django-appconf==1.0.5
# via django-statici18n
-django-cache-memoize==0.1.10
+django-cache-memoize==0.2.0
# via edx-enterprise
django-celery-results==2.5.1
# via -r requirements/edx/kernel.in
django-classy-tags==4.1.0
# via django-sekizai
-django-config-models==2.5.0
+django-config-models==2.5.1
# via
# -r requirements/edx/kernel.in
# edx-enterprise
@@ -283,7 +282,7 @@ django-environ==0.11.2
# via openedx-blockstore
django-fernet-fields-v2==0.9
# via edx-enterprise
-django-filter==23.2
+django-filter==23.3
# via
# -r requirements/edx/kernel.in
# edx-enterprise
@@ -324,7 +323,7 @@ django-multi-email-field==0.7.0
# via edx-enterprise
django-mysql==4.11.0
# via -r requirements/edx/kernel.in
-django-oauth-toolkit==1.4.1
+django-oauth-toolkit==1.7.1
# via
# -c requirements/edx/../constraints.txt
# -r requirements/edx/kernel.in
@@ -341,9 +340,8 @@ django-sekizai==4.1.0
# openedx-django-wiki
django-ses==3.5.0
# via -r requirements/edx/bundled.in
-django-simple-history==3.3.0
+django-simple-history==3.4.0
# via
- # -c requirements/edx/../constraints.txt
# -r requirements/edx/kernel.in
# edx-enterprise
# edx-name-affirmation
@@ -357,7 +355,7 @@ django-statici18n==2.4.0
# -r requirements/edx/kernel.in
# lti-consumer-xblock
# xblock-drag-and-drop-v2
-django-storages==1.11.1
+django-storages==1.14
# via
# -c requirements/edx/../constraints.txt
# -r requirements/edx/kernel.in
@@ -386,6 +384,7 @@ djangorestframework==3.14.0
# django-user-tasks
# drf-jwt
# drf-nested-routers
+ # drf-spectacular
# drf-yasg
# edx-api-doc-tools
# edx-completion
@@ -401,16 +400,14 @@ djangorestframework==3.14.0
# super-csv
djangorestframework-xml==2.0.0
# via edx-enterprise
-docutils==0.19
- # via
- # -c requirements/edx/../constraints.txt
- # botocore
done-xblock==2.1.0
# via -r requirements/edx/bundled.in
drf-jwt==1.19.2
# via edx-drf-extensions
drf-nested-routers==0.93.4
# via openedx-blockstore
+drf-spectacular==0.26.4
+ # via -r requirements/edx/kernel.in
drf-yasg==1.21.5
# via
# -c requirements/edx/../constraints.txt
@@ -428,7 +425,9 @@ edx-auth-backends==4.2.0
# -r requirements/edx/kernel.in
# openedx-blockstore
edx-braze-client==0.1.7
- # via -r requirements/edx/bundled.in
+ # via
+ # -r requirements/edx/bundled.in
+ # edx-enterprise
edx-bulk-grades==1.0.2
# via
# -r requirements/edx/kernel.in
@@ -469,7 +468,7 @@ edx-django-utils==5.7.0
# openedx-blockstore
# ora2
# super-csv
-edx-drf-extensions==8.9.2
+edx-drf-extensions==8.10.0
# via
# -r requirements/edx/kernel.in
# edx-completion
@@ -481,21 +480,21 @@ edx-drf-extensions==8.9.2
# edx-when
# edxval
# openedx-learning
-edx-enterprise==4.1.11
+edx-enterprise==4.3.2
# via
# -c requirements/edx/../constraints.txt
# -r requirements/edx/kernel.in
-edx-event-bus-kafka==5.4.0
+edx-event-bus-kafka==5.5.0
# via -r requirements/edx/kernel.in
edx-event-bus-redis==0.3.1
# via -r requirements/edx/kernel.in
-edx-i18n-tools==1.1.0
+edx-i18n-tools==1.2.0
# via ora2
edx-milestones==0.5.0
# via -r requirements/edx/kernel.in
edx-name-affirmation==2.3.6
# via -r requirements/edx/kernel.in
-edx-opaque-keys[django]==2.5.0
+edx-opaque-keys[django]==2.5.1
# via
# -r requirements/edx/kernel.in
# -r requirements/edx/paver.txt
@@ -507,7 +506,6 @@ edx-opaque-keys[django]==2.5.0
# edx-milestones
# edx-organizations
# edx-proctoring
- # edx-user-state-client
# edx-when
# lti-consumer-xblock
# openedx-events
@@ -529,7 +527,7 @@ edx-rest-api-client==5.6.0
# edx-proctoring
edx-search==3.6.0
# via -r requirements/edx/kernel.in
-edx-sga==0.22.0
+edx-sga==0.23.0
# via -r requirements/edx/bundled.in
edx-submissions==3.6.0
# via
@@ -541,6 +539,7 @@ edx-toggles==5.1.0
# via
# -r requirements/edx/kernel.in
# edx-completion
+ # edx-enterprise
# edx-event-bus-kafka
# edx-event-bus-redis
# edx-name-affirmation
@@ -549,13 +548,11 @@ edx-toggles==5.1.0
# ora2
edx-token-utils==0.2.1
# via -r requirements/edx/kernel.in
-edx-user-state-client==1.3.2
- # via -r requirements/edx/kernel.in
edx-when==2.4.0
# via
# -r requirements/edx/kernel.in
# edx-proctoring
-edxval==2.4.2
+edxval==2.4.3
# via -r requirements/edx/kernel.in
elasticsearch==7.13.4
# via
@@ -572,7 +569,7 @@ event-tracking==2.2.0
# edx-search
fastavro==1.8.3
# via openedx-events
-filelock==3.12.3
+filelock==3.12.4
# via snowflake-connector-python
frozenlist==1.4.0
# via
@@ -602,7 +599,7 @@ html5lib==1.1
# via
# -r requirements/edx/kernel.in
# ora2
-icalendar==5.0.7
+icalendar==5.0.8
# via -r requirements/edx/kernel.in
idna==3.4
# via
@@ -613,12 +610,14 @@ idna==3.4
# yarl
importlib-metadata==6.8.0
# via markdown
-importlib-resources==6.0.1
+importlib-resources==6.1.0
# via
# jsonschema
# jsonschema-specifications
inflection==0.5.1
- # via drf-yasg
+ # via
+ # drf-spectacular
+ # drf-yasg
interchange==2021.0.4
# via py2neo
ipaddress==1.0.23
@@ -631,7 +630,7 @@ jinja2==3.1.2
# via
# code-annotations
# coreschema
-jmespath==0.10.0
+jmespath==1.0.1
# via
# boto3
# botocore
@@ -648,17 +647,21 @@ jsonfield==3.1.0
# edx-submissions
# lti-consumer-xblock
# ora2
-jsonschema==4.19.0
- # via optimizely-sdk
+jsonschema==4.19.1
+ # via
+ # drf-spectacular
+ # optimizely-sdk
jsonschema-specifications==2023.7.1
# via jsonschema
jwcrypto==1.5.0
- # via pylti1p3
+ # via
+ # django-oauth-toolkit
+ # pylti1p3
kombu==5.3.2
# via celery
laboratory==1.0.2
# via -r requirements/edx/kernel.in
-lazy==1.5
+lazy==1.6
# via
# -r requirements/edx/paver.txt
# acid-xblock
@@ -671,8 +674,10 @@ libsass==0.10.0
# -r requirements/edx/paver.txt
loremipsum==1.0.5
# via ora2
-lti-consumer-xblock==9.6.2
- # via -r requirements/edx/kernel.in
+lti-consumer-xblock==9.6.1
+ # via
+ # -c requirements/edx/../constraints.txt
+ # -r requirements/edx/kernel.in
lxml==4.9.3
# via
# -r requirements/edx/kernel.in
@@ -755,6 +760,8 @@ olxcleaner==0.2.1
# via -r requirements/edx/kernel.in
openai==0.28.0
# via edx-enterprise
+openedx-atlas==0.5.0
+ # via -r requirements/edx/kernel.in
openedx-blockstore==1.4.0
# via -r requirements/edx/kernel.in
openedx-calc==3.0.1
@@ -765,10 +772,11 @@ openedx-django-pyfs==3.4.0
# xblock
openedx-django-require==2.1.0
# via -r requirements/edx/kernel.in
-openedx-django-wiki==2.0.1
+openedx-django-wiki==2.0.3
# via -r requirements/edx/kernel.in
-openedx-events==8.6.0
+openedx-events==8.5.0
# via
+ # -c requirements/edx/../constraints.txt
# -r requirements/edx/kernel.in
# edx-event-bus-kafka
# edx-event-bus-redis
@@ -776,13 +784,15 @@ openedx-filters==1.6.0
# via
# -r requirements/edx/kernel.in
# lti-consumer-xblock
-openedx-learning==0.1.5
- # via -r requirements/edx/kernel.in
+openedx-learning==0.1.6
+ # via
+ # -c requirements/edx/../constraints.txt
+ # -r requirements/edx/kernel.in
openedx-mongodbproxy==0.2.0
# via -r requirements/edx/kernel.in
optimizely-sdk==4.1.1
# via -r requirements/edx/bundled.in
-ora2==5.3.0
+ora2==5.4.0
# via -r requirements/edx/bundled.in
oscrypto==1.3.0
# via snowflake-connector-python
@@ -844,7 +854,7 @@ pycountry==22.3.5
# via -r requirements/edx/kernel.in
pycparser==2.21
# via cffi
-pycryptodomex==3.18.0
+pycryptodomex==3.19.0
# via
# -r requirements/edx/kernel.in
# edx-proctoring
@@ -912,7 +922,6 @@ python-dateutil==2.8.2
# botocore
# celery
# edx-ace
- # edx-drf-extensions
# edx-enterprise
# edx-proctoring
# icalendar
@@ -960,6 +969,7 @@ pyyaml==6.0.1
# via
# -r requirements/edx/kernel.in
# code-annotations
+ # drf-spectacular
# edx-django-release-util
# edx-i18n-tools
# xblock
@@ -967,9 +977,8 @@ random2==1.0.1
# via -r requirements/edx/kernel.in
recommender-xblock==2.0.1
# via -r requirements/edx/bundled.in
-redis==4.6.0
+redis==5.0.0
# via
- # -c requirements/edx/../constraints.txt
# -r requirements/edx/kernel.in
# walrus
referencing==0.30.2
@@ -1005,7 +1014,7 @@ requests-oauthlib==1.3.1
# via
# -r requirements/edx/kernel.in
# social-auth-core
-rpds-py==0.10.2
+rpds-py==0.10.3
# via
# jsonschema
# referencing
@@ -1019,7 +1028,7 @@ rules==3.3
# edx-enterprise
# edx-proctoring
# openedx-learning
-s3transfer==0.1.13
+s3transfer==0.6.2
# via boto3
sailthru-client==2.2.3
# via edx-ace
@@ -1052,7 +1061,6 @@ six==1.16.0
# edx-ccx-keys
# edx-codejail
# edx-django-release-util
- # edx-drf-extensions
# edx-milestones
# edx-rbac
# event-tracking
@@ -1117,7 +1125,7 @@ super-csv==3.1.0
# via edx-bulk-grades
sympy==1.12
# via openedx-calc
-testfixtures==7.1.0
+testfixtures==7.2.0
# via edx-enterprise
text-unidecode==1.3
# via python-slugify
@@ -1129,13 +1137,12 @@ tqdm==4.66.1
# via
# nltk
# openai
-typing-extensions==4.7.1
+typing-extensions==4.8.0
# via
# -r requirements/edx/paver.txt
# asgiref
# django-countries
# edx-opaque-keys
- # filelock
# kombu
# pylti1p3
# snowflake-connector-python
@@ -1150,11 +1157,13 @@ unicodecsv==0.14.1
uritemplate==4.1.1
# via
# coreapi
+ # drf-spectacular
# drf-yasg
urllib3==1.26.16
# via
# -c requirements/edx/../constraints.txt
# -r requirements/edx/paver.txt
+ # botocore
# elasticsearch
# py2neo
# requests
@@ -1203,7 +1212,6 @@ xblock[django]==1.7.0
# done-xblock
# edx-completion
# edx-sga
- # edx-user-state-client
# edx-when
# lti-consumer-xblock
# ora2
@@ -1232,7 +1240,7 @@ xss-utils==0.5.0
# via -r requirements/edx/kernel.in
yarl==1.9.2
# via aiohttp
-zipp==3.16.2
+zipp==3.17.0
# via
# importlib-metadata
# importlib-resources
diff --git a/requirements/edx/development.txt b/requirements/edx/development.txt
index 93c26cb636a6..257daff4fdaa 100644
--- a/requirements/edx/development.txt
+++ b/requirements/edx/development.txt
@@ -145,17 +145,15 @@ boto==2.39.0
# -c requirements/edx/../constraints.txt
# -r requirements/edx/doc.txt
# -r requirements/edx/testing.txt
-boto3==1.7.0
+boto3==1.28.53
# via
- # -c requirements/edx/../constraints.txt
# -r requirements/edx/doc.txt
# -r requirements/edx/testing.txt
# django-ses
# fs-s3fs
# ora2
-botocore==1.10.84
+botocore==1.31.53
# via
- # -c requirements/edx/../constraints.txt
# -r requirements/edx/doc.txt
# -r requirements/edx/testing.txt
# boto3
@@ -370,6 +368,7 @@ django==3.2.21
# done-xblock
# drf-jwt
# drf-nested-routers
+ # drf-spectacular
# drf-yasg
# edx-ace
# edx-api-doc-tools
@@ -416,7 +415,7 @@ django-appconf==1.0.5
# -r requirements/edx/doc.txt
# -r requirements/edx/testing.txt
# django-statici18n
-django-cache-memoize==0.1.10
+django-cache-memoize==0.2.0
# via
# -r requirements/edx/doc.txt
# -r requirements/edx/testing.txt
@@ -430,7 +429,7 @@ django-classy-tags==4.1.0
# -r requirements/edx/doc.txt
# -r requirements/edx/testing.txt
# django-sekizai
-django-config-models==2.5.0
+django-config-models==2.5.1
# via
# -r requirements/edx/doc.txt
# -r requirements/edx/testing.txt
@@ -468,7 +467,7 @@ django-fernet-fields-v2==0.9
# -r requirements/edx/doc.txt
# -r requirements/edx/testing.txt
# edx-enterprise
-django-filter==23.2
+django-filter==23.3
# via
# -r requirements/edx/doc.txt
# -r requirements/edx/testing.txt
@@ -523,7 +522,7 @@ django-mysql==4.11.0
# via
# -r requirements/edx/doc.txt
# -r requirements/edx/testing.txt
-django-oauth-toolkit==1.4.1
+django-oauth-toolkit==1.7.1
# via
# -c requirements/edx/../constraints.txt
# -r requirements/edx/doc.txt
@@ -551,9 +550,8 @@ django-ses==3.5.0
# via
# -r requirements/edx/doc.txt
# -r requirements/edx/testing.txt
-django-simple-history==3.3.0
+django-simple-history==3.4.0
# via
- # -c requirements/edx/../constraints.txt
# -r requirements/edx/doc.txt
# -r requirements/edx/testing.txt
# edx-enterprise
@@ -571,7 +569,7 @@ django-statici18n==2.4.0
# -r requirements/edx/testing.txt
# lti-consumer-xblock
# xblock-drag-and-drop-v2
-django-storages==1.11.1
+django-storages==1.14
# via
# -c requirements/edx/../constraints.txt
# -r requirements/edx/doc.txt
@@ -613,6 +611,7 @@ djangorestframework==3.14.0
# django-user-tasks
# drf-jwt
# drf-nested-routers
+ # drf-spectacular
# drf-yasg
# edx-api-doc-tools
# edx-completion
@@ -639,8 +638,6 @@ docutils==0.19
# via
# -c requirements/edx/../constraints.txt
# -r requirements/edx/doc.txt
- # -r requirements/edx/testing.txt
- # botocore
# pydata-sphinx-theme
# sphinx
# sphinx-mdinclude
@@ -658,6 +655,10 @@ drf-nested-routers==0.93.4
# -r requirements/edx/doc.txt
# -r requirements/edx/testing.txt
# openedx-blockstore
+drf-spectacular==0.26.4
+ # via
+ # -r requirements/edx/doc.txt
+ # -r requirements/edx/testing.txt
drf-yasg==1.21.5
# via
# -c requirements/edx/../constraints.txt
@@ -684,6 +685,7 @@ edx-braze-client==0.1.7
# via
# -r requirements/edx/doc.txt
# -r requirements/edx/testing.txt
+ # edx-enterprise
edx-bulk-grades==1.0.2
# via
# -r requirements/edx/doc.txt
@@ -735,7 +737,7 @@ edx-django-utils==5.7.0
# openedx-blockstore
# ora2
# super-csv
-edx-drf-extensions==8.9.2
+edx-drf-extensions==8.10.0
# via
# -r requirements/edx/doc.txt
# -r requirements/edx/testing.txt
@@ -748,12 +750,12 @@ edx-drf-extensions==8.9.2
# edx-when
# edxval
# openedx-learning
-edx-enterprise==4.1.11
+edx-enterprise==4.3.2
# via
# -c requirements/edx/../constraints.txt
# -r requirements/edx/doc.txt
# -r requirements/edx/testing.txt
-edx-event-bus-kafka==5.4.0
+edx-event-bus-kafka==5.5.0
# via
# -r requirements/edx/doc.txt
# -r requirements/edx/testing.txt
@@ -761,7 +763,7 @@ edx-event-bus-redis==0.3.1
# via
# -r requirements/edx/doc.txt
# -r requirements/edx/testing.txt
-edx-i18n-tools==1.1.0
+edx-i18n-tools==1.2.0
# via
# -r requirements/edx/doc.txt
# -r requirements/edx/testing.txt
@@ -776,7 +778,7 @@ edx-name-affirmation==2.3.6
# via
# -r requirements/edx/doc.txt
# -r requirements/edx/testing.txt
-edx-opaque-keys[django]==2.5.0
+edx-opaque-keys[django]==2.5.1
# via
# -r requirements/edx/doc.txt
# -r requirements/edx/testing.txt
@@ -788,7 +790,6 @@ edx-opaque-keys[django]==2.5.0
# edx-milestones
# edx-organizations
# edx-proctoring
- # edx-user-state-client
# edx-when
# lti-consumer-xblock
# openedx-events
@@ -821,7 +822,7 @@ edx-search==3.6.0
# via
# -r requirements/edx/doc.txt
# -r requirements/edx/testing.txt
-edx-sga==0.22.0
+edx-sga==0.23.0
# via
# -r requirements/edx/doc.txt
# -r requirements/edx/testing.txt
@@ -840,6 +841,7 @@ edx-toggles==5.1.0
# -r requirements/edx/doc.txt
# -r requirements/edx/testing.txt
# edx-completion
+ # edx-enterprise
# edx-event-bus-kafka
# edx-event-bus-redis
# edx-name-affirmation
@@ -850,16 +852,12 @@ edx-token-utils==0.2.1
# via
# -r requirements/edx/doc.txt
# -r requirements/edx/testing.txt
-edx-user-state-client==1.3.2
- # via
- # -r requirements/edx/doc.txt
- # -r requirements/edx/testing.txt
edx-when==2.4.0
# via
# -r requirements/edx/doc.txt
# -r requirements/edx/testing.txt
# edx-proctoring
-edxval==2.4.2
+edxval==2.4.3
# via
# -r requirements/edx/doc.txt
# -r requirements/edx/testing.txt
@@ -895,7 +893,7 @@ execnet==2.0.2
# pytest-xdist
factory-boy==3.3.0
# via -r requirements/edx/testing.txt
-faker==19.6.1
+faker==19.6.2
# via
# -r requirements/edx/testing.txt
# factory-boy
@@ -908,7 +906,7 @@ fastavro==1.8.3
# -r requirements/edx/doc.txt
# -r requirements/edx/testing.txt
# openedx-events
-filelock==3.12.3
+filelock==3.12.4
# via
# -r requirements/edx/doc.txt
# -r requirements/edx/testing.txt
@@ -948,7 +946,7 @@ gitdb==4.0.10
# via
# -r requirements/edx/doc.txt
# gitpython
-gitpython==3.1.35
+gitpython==3.1.37
# via -r requirements/edx/doc.txt
glob2==0.7
# via
@@ -986,7 +984,7 @@ httpx==0.23.3
# via
# -r requirements/edx/testing.txt
# pact-python
-icalendar==5.0.7
+icalendar==5.0.8
# via
# -r requirements/edx/doc.txt
# -r requirements/edx/testing.txt
@@ -1015,7 +1013,7 @@ importlib-metadata==6.8.0
# markdown
# pytest-randomly
# sphinx
-importlib-resources==6.0.1
+importlib-resources==6.1.0
# via
# -r requirements/edx/doc.txt
# -r requirements/edx/testing.txt
@@ -1025,6 +1023,7 @@ inflection==0.5.1
# via
# -r requirements/edx/doc.txt
# -r requirements/edx/testing.txt
+ # drf-spectacular
# drf-yasg
iniconfig==2.0.0
# via
@@ -1061,7 +1060,7 @@ jinja2==3.1.2
# coreschema
# diff-cover
# sphinx
-jmespath==0.10.0
+jmespath==1.0.1
# via
# -r requirements/edx/doc.txt
# -r requirements/edx/testing.txt
@@ -1087,10 +1086,11 @@ jsonfield==3.1.0
# edx-submissions
# lti-consumer-xblock
# ora2
-jsonschema==4.19.0
+jsonschema==4.19.1
# via
# -r requirements/edx/doc.txt
# -r requirements/edx/testing.txt
+ # drf-spectacular
# optimizely-sdk
# sphinxcontrib-openapi
jsonschema-specifications==2023.7.1
@@ -1102,6 +1102,7 @@ jwcrypto==1.5.0
# via
# -r requirements/edx/doc.txt
# -r requirements/edx/testing.txt
+ # django-oauth-toolkit
# pylti1p3
kombu==5.3.2
# via
@@ -1112,7 +1113,7 @@ laboratory==1.0.2
# via
# -r requirements/edx/doc.txt
# -r requirements/edx/testing.txt
-lazy==1.5
+lazy==1.6
# via
# -r requirements/edx/doc.txt
# -r requirements/edx/testing.txt
@@ -1136,8 +1137,9 @@ loremipsum==1.0.5
# -r requirements/edx/doc.txt
# -r requirements/edx/testing.txt
# ora2
-lti-consumer-xblock==9.6.2
+lti-consumer-xblock==9.6.1
# via
+ # -c requirements/edx/../constraints.txt
# -r requirements/edx/doc.txt
# -r requirements/edx/testing.txt
lxml==4.9.3
@@ -1277,6 +1279,10 @@ openai==0.28.0
# -r requirements/edx/doc.txt
# -r requirements/edx/testing.txt
# edx-enterprise
+openedx-atlas==0.5.0
+ # via
+ # -r requirements/edx/doc.txt
+ # -r requirements/edx/testing.txt
openedx-blockstore==1.4.0
# via
# -r requirements/edx/doc.txt
@@ -1295,12 +1301,13 @@ openedx-django-require==2.1.0
# via
# -r requirements/edx/doc.txt
# -r requirements/edx/testing.txt
-openedx-django-wiki==2.0.1
+openedx-django-wiki==2.0.3
# via
# -r requirements/edx/doc.txt
# -r requirements/edx/testing.txt
-openedx-events==8.6.0
+openedx-events==8.5.0
# via
+ # -c requirements/edx/../constraints.txt
# -r requirements/edx/doc.txt
# -r requirements/edx/testing.txt
# edx-event-bus-kafka
@@ -1310,8 +1317,9 @@ openedx-filters==1.6.0
# -r requirements/edx/doc.txt
# -r requirements/edx/testing.txt
# lti-consumer-xblock
-openedx-learning==0.1.5
+openedx-learning==0.1.6
# via
+ # -c requirements/edx/../constraints.txt
# -r requirements/edx/doc.txt
# -r requirements/edx/testing.txt
openedx-mongodbproxy==0.2.0
@@ -1322,7 +1330,7 @@ optimizely-sdk==4.1.1
# via
# -r requirements/edx/doc.txt
# -r requirements/edx/testing.txt
-ora2==5.3.0
+ora2==5.4.0
# via
# -r requirements/edx/doc.txt
# -r requirements/edx/testing.txt
@@ -1459,7 +1467,7 @@ pycparser==2.21
# -r requirements/edx/doc.txt
# -r requirements/edx/testing.txt
# cffi
-pycryptodomex==3.18.0
+pycryptodomex==3.19.0
# via
# -r requirements/edx/doc.txt
# -r requirements/edx/testing.txt
@@ -1475,7 +1483,7 @@ pydantic-core==2.6.3
# via
# -r requirements/edx/testing.txt
# pydantic
-pydata-sphinx-theme==0.13.3
+pydata-sphinx-theme==0.14.1
# via
# -r requirements/edx/doc.txt
# sphinx-book-theme
@@ -1626,7 +1634,6 @@ python-dateutil==2.8.2
# botocore
# celery
# edx-ace
- # edx-drf-extensions
# edx-enterprise
# edx-proctoring
# faker
@@ -1693,6 +1700,7 @@ pyyaml==6.0.1
# -r requirements/edx/doc.txt
# -r requirements/edx/testing.txt
# code-annotations
+ # drf-spectacular
# edx-django-release-util
# edx-i18n-tools
# sphinxcontrib-openapi
@@ -1705,9 +1713,8 @@ recommender-xblock==2.0.1
# via
# -r requirements/edx/doc.txt
# -r requirements/edx/testing.txt
-redis==4.6.0
+redis==5.0.0
# via
- # -c requirements/edx/../constraints.txt
# -r requirements/edx/doc.txt
# -r requirements/edx/testing.txt
# walrus
@@ -1758,7 +1765,7 @@ rfc3986[idna2008]==1.5.0
# via
# -r requirements/edx/testing.txt
# httpx
-rpds-py==0.10.2
+rpds-py==0.10.3
# via
# -r requirements/edx/doc.txt
# -r requirements/edx/testing.txt
@@ -1781,7 +1788,7 @@ rules==3.3
# edx-enterprise
# edx-proctoring
# openedx-learning
-s3transfer==0.1.13
+s3transfer==0.6.2
# via
# -r requirements/edx/doc.txt
# -r requirements/edx/testing.txt
@@ -1835,7 +1842,6 @@ six==1.16.0
# edx-ccx-keys
# edx-codejail
# edx-django-release-util
- # edx-drf-extensions
# edx-lint
# edx-milestones
# edx-rbac
@@ -1863,7 +1869,7 @@ slumber==0.7.1
# edx-bulk-grades
# edx-enterprise
# edx-rest-api-client
-smmap==5.0.0
+smmap==5.0.1
# via
# -r requirements/edx/doc.txt
# gitdb
@@ -1996,7 +2002,7 @@ sympy==1.12
# -r requirements/edx/doc.txt
# -r requirements/edx/testing.txt
# openedx-calc
-testfixtures==7.1.0
+testfixtures==7.2.0
# via
# -r requirements/edx/doc.txt
# -r requirements/edx/testing.txt
@@ -2046,17 +2052,17 @@ tqdm==4.66.1
# -r requirements/edx/testing.txt
# nltk
# openai
-types-pytz==2023.3.0.1
+types-pytz==2023.3.1.1
# via django-stubs
types-pyyaml==6.0.12.11
# via
# django-stubs
# djangorestframework-stubs
-types-requests==2.31.0.2
+types-requests==2.31.0.3
# via djangorestframework-stubs
types-urllib3==1.26.25.14
# via types-requests
-typing-extensions==4.7.1
+typing-extensions==4.8.0
# via
# -r requirements/edx/doc.txt
# -r requirements/edx/testing.txt
@@ -2070,7 +2076,6 @@ typing-extensions==4.7.1
# edx-opaque-keys
# faker
# fastapi
- # filelock
# grimp
# import-linter
# kombu
@@ -2101,12 +2106,14 @@ uritemplate==4.1.1
# -r requirements/edx/doc.txt
# -r requirements/edx/testing.txt
# coreapi
+ # drf-spectacular
# drf-yasg
urllib3==1.26.16
# via
# -c requirements/edx/../constraints.txt
# -r requirements/edx/doc.txt
# -r requirements/edx/testing.txt
+ # botocore
# elasticsearch
# pact-python
# py2neo
@@ -2194,7 +2201,6 @@ xblock[django]==1.7.0
# done-xblock
# edx-completion
# edx-sga
- # edx-user-state-client
# edx-when
# lti-consumer-xblock
# ora2
@@ -2238,7 +2244,7 @@ yarl==1.9.2
# -r requirements/edx/doc.txt
# -r requirements/edx/testing.txt
# aiohttp
-zipp==3.16.2
+zipp==3.17.0
# via
# -r requirements/edx/../pip-tools.txt
# -r requirements/edx/doc.txt
diff --git a/requirements/edx/doc.txt b/requirements/edx/doc.txt
index 078b1f3162ba..bcc1381772b7 100644
--- a/requirements/edx/doc.txt
+++ b/requirements/edx/doc.txt
@@ -103,16 +103,14 @@ boto==2.39.0
# via
# -c requirements/edx/../constraints.txt
# -r requirements/edx/base.txt
-boto3==1.7.0
+boto3==1.28.53
# via
- # -c requirements/edx/../constraints.txt
# -r requirements/edx/base.txt
# django-ses
# fs-s3fs
# ora2
-botocore==1.10.84
+botocore==1.31.53
# via
- # -c requirements/edx/../constraints.txt
# -r requirements/edx/base.txt
# boto3
# s3transfer
@@ -256,6 +254,7 @@ django==3.2.21
# done-xblock
# drf-jwt
# drf-nested-routers
+ # drf-spectacular
# drf-yasg
# edx-ace
# edx-api-doc-tools
@@ -301,7 +300,7 @@ django-appconf==1.0.5
# via
# -r requirements/edx/base.txt
# django-statici18n
-django-cache-memoize==0.1.10
+django-cache-memoize==0.2.0
# via
# -r requirements/edx/base.txt
# edx-enterprise
@@ -311,7 +310,7 @@ django-classy-tags==4.1.0
# via
# -r requirements/edx/base.txt
# django-sekizai
-django-config-models==2.5.0
+django-config-models==2.5.1
# via
# -r requirements/edx/base.txt
# edx-enterprise
@@ -340,7 +339,7 @@ django-fernet-fields-v2==0.9
# via
# -r requirements/edx/base.txt
# edx-enterprise
-django-filter==23.2
+django-filter==23.3
# via
# -r requirements/edx/base.txt
# edx-enterprise
@@ -385,7 +384,7 @@ django-multi-email-field==0.7.0
# edx-enterprise
django-mysql==4.11.0
# via -r requirements/edx/base.txt
-django-oauth-toolkit==1.4.1
+django-oauth-toolkit==1.7.1
# via
# -c requirements/edx/../constraints.txt
# -r requirements/edx/base.txt
@@ -404,9 +403,8 @@ django-sekizai==4.1.0
# openedx-django-wiki
django-ses==3.5.0
# via -r requirements/edx/base.txt
-django-simple-history==3.3.0
+django-simple-history==3.4.0
# via
- # -c requirements/edx/../constraints.txt
# -r requirements/edx/base.txt
# edx-enterprise
# edx-name-affirmation
@@ -420,7 +418,7 @@ django-statici18n==2.4.0
# -r requirements/edx/base.txt
# lti-consumer-xblock
# xblock-drag-and-drop-v2
-django-storages==1.11.1
+django-storages==1.14
# via
# -c requirements/edx/../constraints.txt
# -r requirements/edx/base.txt
@@ -449,6 +447,7 @@ djangorestframework==3.14.0
# django-user-tasks
# drf-jwt
# drf-nested-routers
+ # drf-spectacular
# drf-yasg
# edx-api-doc-tools
# edx-completion
@@ -469,8 +468,6 @@ djangorestframework-xml==2.0.0
docutils==0.19
# via
# -c requirements/edx/../constraints.txt
- # -r requirements/edx/base.txt
- # botocore
# pydata-sphinx-theme
# sphinx
# sphinx-mdinclude
@@ -484,6 +481,8 @@ drf-nested-routers==0.93.4
# via
# -r requirements/edx/base.txt
# openedx-blockstore
+drf-spectacular==0.26.4
+ # via -r requirements/edx/base.txt
drf-yasg==1.21.5
# via
# -c requirements/edx/../constraints.txt
@@ -502,7 +501,9 @@ edx-auth-backends==4.2.0
# -r requirements/edx/base.txt
# openedx-blockstore
edx-braze-client==0.1.7
- # via -r requirements/edx/base.txt
+ # via
+ # -r requirements/edx/base.txt
+ # edx-enterprise
edx-bulk-grades==1.0.2
# via
# -r requirements/edx/base.txt
@@ -543,7 +544,7 @@ edx-django-utils==5.7.0
# openedx-blockstore
# ora2
# super-csv
-edx-drf-extensions==8.9.2
+edx-drf-extensions==8.10.0
# via
# -r requirements/edx/base.txt
# edx-completion
@@ -555,15 +556,15 @@ edx-drf-extensions==8.9.2
# edx-when
# edxval
# openedx-learning
-edx-enterprise==4.1.11
+edx-enterprise==4.3.2
# via
# -c requirements/edx/../constraints.txt
# -r requirements/edx/base.txt
-edx-event-bus-kafka==5.4.0
+edx-event-bus-kafka==5.5.0
# via -r requirements/edx/base.txt
edx-event-bus-redis==0.3.1
# via -r requirements/edx/base.txt
-edx-i18n-tools==1.1.0
+edx-i18n-tools==1.2.0
# via
# -r requirements/edx/base.txt
# ora2
@@ -571,7 +572,7 @@ edx-milestones==0.5.0
# via -r requirements/edx/base.txt
edx-name-affirmation==2.3.6
# via -r requirements/edx/base.txt
-edx-opaque-keys[django]==2.5.0
+edx-opaque-keys[django]==2.5.1
# via
# -r requirements/edx/base.txt
# edx-bulk-grades
@@ -582,7 +583,6 @@ edx-opaque-keys[django]==2.5.0
# edx-milestones
# edx-organizations
# edx-proctoring
- # edx-user-state-client
# edx-when
# lti-consumer-xblock
# openedx-events
@@ -606,7 +606,7 @@ edx-rest-api-client==5.6.0
# edx-proctoring
edx-search==3.6.0
# via -r requirements/edx/base.txt
-edx-sga==0.22.0
+edx-sga==0.23.0
# via -r requirements/edx/base.txt
edx-submissions==3.6.0
# via
@@ -620,6 +620,7 @@ edx-toggles==5.1.0
# via
# -r requirements/edx/base.txt
# edx-completion
+ # edx-enterprise
# edx-event-bus-kafka
# edx-event-bus-redis
# edx-name-affirmation
@@ -628,13 +629,11 @@ edx-toggles==5.1.0
# ora2
edx-token-utils==0.2.1
# via -r requirements/edx/base.txt
-edx-user-state-client==1.3.2
- # via -r requirements/edx/base.txt
edx-when==2.4.0
# via
# -r requirements/edx/base.txt
# edx-proctoring
-edxval==2.4.2
+edxval==2.4.3
# via -r requirements/edx/base.txt
elasticsearch==7.13.4
# via
@@ -656,7 +655,7 @@ fastavro==1.8.3
# via
# -r requirements/edx/base.txt
# openedx-events
-filelock==3.12.3
+filelock==3.12.4
# via
# -r requirements/edx/base.txt
# snowflake-connector-python
@@ -683,7 +682,7 @@ geoip2==4.7.0
# via -r requirements/edx/base.txt
gitdb==4.0.10
# via gitpython
-gitpython==3.1.35
+gitpython==3.1.37
# via -r requirements/edx/doc.in
glob2==0.7
# via -r requirements/edx/base.txt
@@ -695,7 +694,7 @@ html5lib==1.1
# via
# -r requirements/edx/base.txt
# ora2
-icalendar==5.0.7
+icalendar==5.0.8
# via -r requirements/edx/base.txt
idna==3.4
# via
@@ -711,7 +710,7 @@ importlib-metadata==6.8.0
# -r requirements/edx/base.txt
# markdown
# sphinx
-importlib-resources==6.0.1
+importlib-resources==6.1.0
# via
# -r requirements/edx/base.txt
# jsonschema
@@ -719,6 +718,7 @@ importlib-resources==6.0.1
inflection==0.5.1
# via
# -r requirements/edx/base.txt
+ # drf-spectacular
# drf-yasg
interchange==2021.0.4
# via
@@ -740,7 +740,7 @@ jinja2==3.1.2
# code-annotations
# coreschema
# sphinx
-jmespath==0.10.0
+jmespath==1.0.1
# via
# -r requirements/edx/base.txt
# boto3
@@ -762,9 +762,10 @@ jsonfield==3.1.0
# edx-submissions
# lti-consumer-xblock
# ora2
-jsonschema==4.19.0
+jsonschema==4.19.1
# via
# -r requirements/edx/base.txt
+ # drf-spectacular
# optimizely-sdk
# sphinxcontrib-openapi
jsonschema-specifications==2023.7.1
@@ -774,6 +775,7 @@ jsonschema-specifications==2023.7.1
jwcrypto==1.5.0
# via
# -r requirements/edx/base.txt
+ # django-oauth-toolkit
# pylti1p3
kombu==5.3.2
# via
@@ -781,7 +783,7 @@ kombu==5.3.2
# celery
laboratory==1.0.2
# via -r requirements/edx/base.txt
-lazy==1.5
+lazy==1.6
# via
# -r requirements/edx/base.txt
# acid-xblock
@@ -796,8 +798,10 @@ loremipsum==1.0.5
# via
# -r requirements/edx/base.txt
# ora2
-lti-consumer-xblock==9.6.2
- # via -r requirements/edx/base.txt
+lti-consumer-xblock==9.6.1
+ # via
+ # -c requirements/edx/../constraints.txt
+ # -r requirements/edx/base.txt
lxml==4.9.3
# via
# -r requirements/edx/base.txt
@@ -895,6 +899,8 @@ openai==0.28.0
# via
# -r requirements/edx/base.txt
# edx-enterprise
+openedx-atlas==0.5.0
+ # via -r requirements/edx/base.txt
openedx-blockstore==1.4.0
# via -r requirements/edx/base.txt
openedx-calc==3.0.1
@@ -906,10 +912,11 @@ openedx-django-pyfs==3.4.0
# xblock
openedx-django-require==2.1.0
# via -r requirements/edx/base.txt
-openedx-django-wiki==2.0.1
+openedx-django-wiki==2.0.3
# via -r requirements/edx/base.txt
-openedx-events==8.6.0
+openedx-events==8.5.0
# via
+ # -c requirements/edx/../constraints.txt
# -r requirements/edx/base.txt
# edx-event-bus-kafka
# edx-event-bus-redis
@@ -917,13 +924,15 @@ openedx-filters==1.6.0
# via
# -r requirements/edx/base.txt
# lti-consumer-xblock
-openedx-learning==0.1.5
- # via -r requirements/edx/base.txt
+openedx-learning==0.1.6
+ # via
+ # -c requirements/edx/../constraints.txt
+ # -r requirements/edx/base.txt
openedx-mongodbproxy==0.2.0
# via -r requirements/edx/base.txt
optimizely-sdk==4.1.1
# via -r requirements/edx/base.txt
-ora2==5.3.0
+ora2==5.4.0
# via -r requirements/edx/base.txt
oscrypto==1.3.0
# via
@@ -1008,14 +1017,14 @@ pycparser==2.21
# via
# -r requirements/edx/base.txt
# cffi
-pycryptodomex==3.18.0
+pycryptodomex==3.19.0
# via
# -r requirements/edx/base.txt
# edx-proctoring
# lti-consumer-xblock
# pyjwkest
# snowflake-connector-python
-pydata-sphinx-theme==0.13.3
+pydata-sphinx-theme==0.14.1
# via sphinx-book-theme
pygments==2.16.1
# via
@@ -1089,7 +1098,6 @@ python-dateutil==2.8.2
# botocore
# celery
# edx-ace
- # edx-drf-extensions
# edx-enterprise
# edx-proctoring
# icalendar
@@ -1141,6 +1149,7 @@ pyyaml==6.0.1
# via
# -r requirements/edx/base.txt
# code-annotations
+ # drf-spectacular
# edx-django-release-util
# edx-i18n-tools
# sphinxcontrib-openapi
@@ -1149,9 +1158,8 @@ random2==1.0.1
# via -r requirements/edx/base.txt
recommender-xblock==2.0.1
# via -r requirements/edx/base.txt
-redis==4.6.0
+redis==5.0.0
# via
- # -c requirements/edx/../constraints.txt
# -r requirements/edx/base.txt
# walrus
referencing==0.30.2
@@ -1191,7 +1199,7 @@ requests-oauthlib==1.3.1
# via
# -r requirements/edx/base.txt
# social-auth-core
-rpds-py==0.10.2
+rpds-py==0.10.3
# via
# -r requirements/edx/base.txt
# jsonschema
@@ -1210,7 +1218,7 @@ rules==3.3
# edx-enterprise
# edx-proctoring
# openedx-learning
-s3transfer==0.1.13
+s3transfer==0.6.2
# via
# -r requirements/edx/base.txt
# boto3
@@ -1249,7 +1257,6 @@ six==1.16.0
# edx-ccx-keys
# edx-codejail
# edx-django-release-util
- # edx-drf-extensions
# edx-milestones
# edx-rbac
# event-tracking
@@ -1273,7 +1280,7 @@ slumber==0.7.1
# edx-bulk-grades
# edx-enterprise
# edx-rest-api-client
-smmap==5.0.0
+smmap==5.0.1
# via gitdb
snowballstemmer==2.2.0
# via sphinx
@@ -1363,7 +1370,7 @@ sympy==1.12
# via
# -r requirements/edx/base.txt
# openedx-calc
-testfixtures==7.1.0
+testfixtures==7.2.0
# via
# -r requirements/edx/base.txt
# edx-enterprise
@@ -1384,13 +1391,12 @@ tqdm==4.66.1
# -r requirements/edx/base.txt
# nltk
# openai
-typing-extensions==4.7.1
+typing-extensions==4.8.0
# via
# -r requirements/edx/base.txt
# asgiref
# django-countries
# edx-opaque-keys
- # filelock
# kombu
# pydata-sphinx-theme
# pylti1p3
@@ -1408,11 +1414,13 @@ uritemplate==4.1.1
# via
# -r requirements/edx/base.txt
# coreapi
+ # drf-spectacular
# drf-yasg
urllib3==1.26.16
# via
# -c requirements/edx/../constraints.txt
# -r requirements/edx/base.txt
+ # botocore
# elasticsearch
# py2neo
# requests
@@ -1469,7 +1477,6 @@ xblock[django]==1.7.0
# done-xblock
# edx-completion
# edx-sga
- # edx-user-state-client
# edx-when
# lti-consumer-xblock
# ora2
@@ -1502,7 +1509,7 @@ yarl==1.9.2
# via
# -r requirements/edx/base.txt
# aiohttp
-zipp==3.16.2
+zipp==3.17.0
# via
# -r requirements/edx/base.txt
# importlib-metadata
diff --git a/requirements/edx/kernel.in b/requirements/edx/kernel.in
index 8c0258f55f94..dd3403655d28 100644
--- a/requirements/edx/kernel.in
+++ b/requirements/edx/kernel.in
@@ -58,6 +58,7 @@ django-user-tasks
django-waffle
django-webpack-loader # Used to wire webpack bundles into the django asset pipeline
djangorestframework
+drf-spectacular
edx-ace
edx-api-doc-tools
edx-auth-backends # Allow Studio to use LMS SSO
@@ -86,7 +87,6 @@ edx-search
edx-submissions
edx-toggles # Feature toggles management
edx-token-utils # Validate exam access tokens
-edx-user-state-client
edx-when
edxval
event-tracking
@@ -111,9 +111,10 @@ mysqlclient # Driver for the default production relation
nodeenv # Utility for managing Node.js environments; we use this for deployments and testing
oauthlib # OAuth specification support for authenticating via LTI or other Open edX services
olxcleaner
+openedx-atlas # CLI tool to manage translations
openedx-calc # Library supporting mathematical calculations for Open edX
openedx-django-require
-openedx-events>=8.3.0 # Open edX Events from Hooks Extension Framework (OEP-50)
+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)
openedx-mongodbproxy
diff --git a/requirements/edx/paver.txt b/requirements/edx/paver.txt
index 4c498e9476c6..46af4d76cc27 100644
--- a/requirements/edx/paver.txt
+++ b/requirements/edx/paver.txt
@@ -10,11 +10,11 @@ charset-normalizer==2.0.12
# via
# -c requirements/edx/../constraints.txt
# requests
-edx-opaque-keys==2.5.0
+edx-opaque-keys==2.5.1
# via -r requirements/edx/paver.in
idna==3.4
# via requests
-lazy==1.5
+lazy==1.6
# via -r requirements/edx/paver.in
libsass==0.10.0
# via
@@ -52,7 +52,7 @@ stevedore==5.1.0
# via
# -r requirements/edx/paver.in
# edx-opaque-keys
-typing-extensions==4.7.1
+typing-extensions==4.8.0
# via edx-opaque-keys
urllib3==1.26.16
# via
diff --git a/requirements/edx/semgrep.in b/requirements/edx/semgrep.in
new file mode 100644
index 000000000000..0fc07d64532b
--- /dev/null
+++ b/requirements/edx/semgrep.in
@@ -0,0 +1,13 @@
+# Requirements to run Semgrep code quality checks
+#
+# DON'T JUST ADD NEW DEPENDENCIES!!!
+#
+# If you open a pull request that adds a new dependency, you should:
+# * verify that the dependency has a license compatible with AGPLv3
+# * confirm that it has no system requirements beyond what we already install
+# * run "make upgrade" to update the detailed requirements files
+#
+
+-c ../constraints.txt
+
+semgrep # Semgrep performs structural code searches
diff --git a/requirements/edx/semgrep.txt b/requirements/edx/semgrep.txt
new file mode 100644
index 000000000000..ab6f0a120f90
--- /dev/null
+++ b/requirements/edx/semgrep.txt
@@ -0,0 +1,99 @@
+#
+# This file is autogenerated by pip-compile with Python 3.8
+# by the following command:
+#
+# make upgrade
+#
+attrs==23.1.0
+ # via
+ # glom
+ # jsonschema
+ # referencing
+ # semgrep
+boltons==21.0.0
+ # via
+ # face
+ # glom
+ # semgrep
+bracex==2.4
+ # via wcmatch
+certifi==2023.7.22
+ # via requests
+charset-normalizer==2.0.12
+ # via
+ # -c requirements/edx/../constraints.txt
+ # requests
+click==8.1.6
+ # via
+ # -c requirements/edx/../constraints.txt
+ # click-option-group
+ # semgrep
+click-option-group==0.5.6
+ # via semgrep
+colorama==0.4.6
+ # via semgrep
+defusedxml==0.7.1
+ # via semgrep
+face==22.0.0
+ # via glom
+glom==22.1.0
+ # via semgrep
+idna==3.4
+ # via requests
+importlib-resources==6.1.0
+ # via
+ # jsonschema
+ # jsonschema-specifications
+jsonschema==4.19.1
+ # via semgrep
+jsonschema-specifications==2023.7.1
+ # via jsonschema
+markdown-it-py==3.0.0
+ # via rich
+mdurl==0.1.2
+ # via markdown-it-py
+packaging==23.1
+ # via semgrep
+peewee==3.16.3
+ # via semgrep
+pkgutil-resolve-name==1.3.10
+ # via jsonschema
+pygments==2.16.1
+ # via rich
+python-lsp-jsonrpc==1.0.0
+ # via semgrep
+referencing==0.30.2
+ # via
+ # jsonschema
+ # jsonschema-specifications
+requests==2.31.0
+ # via semgrep
+rich==13.5.3
+ # via semgrep
+rpds-py==0.10.3
+ # via
+ # jsonschema
+ # referencing
+ruamel-yaml==0.17.32
+ # via semgrep
+ruamel-yaml-clib==0.2.7
+ # via ruamel-yaml
+semgrep==1.41.0
+ # via -r requirements/edx/semgrep.in
+tomli==2.0.1
+ # via semgrep
+typing-extensions==4.8.0
+ # via
+ # rich
+ # semgrep
+ujson==5.8.0
+ # via python-lsp-jsonrpc
+urllib3==1.26.16
+ # via
+ # -c requirements/edx/../constraints.txt
+ # requests
+ # semgrep
+wcmatch==8.5
+ # via semgrep
+zipp==3.17.0
+ # via importlib-resources
diff --git a/requirements/edx/testing.txt b/requirements/edx/testing.txt
index 4974d8f07768..2368bc59aa88 100644
--- a/requirements/edx/testing.txt
+++ b/requirements/edx/testing.txt
@@ -110,16 +110,14 @@ boto==2.39.0
# via
# -c requirements/edx/../constraints.txt
# -r requirements/edx/base.txt
-boto3==1.7.0
+boto3==1.28.53
# via
- # -c requirements/edx/../constraints.txt
# -r requirements/edx/base.txt
# django-ses
# fs-s3fs
# ora2
-botocore==1.10.84
+botocore==1.31.53
# via
- # -c requirements/edx/../constraints.txt
# -r requirements/edx/base.txt
# boto3
# s3transfer
@@ -289,6 +287,7 @@ django==3.2.21
# done-xblock
# drf-jwt
# drf-nested-routers
+ # drf-spectacular
# drf-yasg
# edx-ace
# edx-api-doc-tools
@@ -334,7 +333,7 @@ django-appconf==1.0.5
# via
# -r requirements/edx/base.txt
# django-statici18n
-django-cache-memoize==0.1.10
+django-cache-memoize==0.2.0
# via
# -r requirements/edx/base.txt
# edx-enterprise
@@ -344,7 +343,7 @@ django-classy-tags==4.1.0
# via
# -r requirements/edx/base.txt
# django-sekizai
-django-config-models==2.5.0
+django-config-models==2.5.1
# via
# -r requirements/edx/base.txt
# edx-enterprise
@@ -373,7 +372,7 @@ django-fernet-fields-v2==0.9
# via
# -r requirements/edx/base.txt
# edx-enterprise
-django-filter==23.2
+django-filter==23.3
# via
# -r requirements/edx/base.txt
# edx-enterprise
@@ -418,7 +417,7 @@ django-multi-email-field==0.7.0
# edx-enterprise
django-mysql==4.11.0
# via -r requirements/edx/base.txt
-django-oauth-toolkit==1.4.1
+django-oauth-toolkit==1.7.1
# via
# -c requirements/edx/../constraints.txt
# -r requirements/edx/base.txt
@@ -437,9 +436,8 @@ django-sekizai==4.1.0
# openedx-django-wiki
django-ses==3.5.0
# via -r requirements/edx/base.txt
-django-simple-history==3.3.0
+django-simple-history==3.4.0
# via
- # -c requirements/edx/../constraints.txt
# -r requirements/edx/base.txt
# edx-enterprise
# edx-name-affirmation
@@ -453,7 +451,7 @@ django-statici18n==2.4.0
# -r requirements/edx/base.txt
# lti-consumer-xblock
# xblock-drag-and-drop-v2
-django-storages==1.11.1
+django-storages==1.14
# via
# -c requirements/edx/../constraints.txt
# -r requirements/edx/base.txt
@@ -482,6 +480,7 @@ djangorestframework==3.14.0
# django-user-tasks
# drf-jwt
# drf-nested-routers
+ # drf-spectacular
# drf-yasg
# edx-api-doc-tools
# edx-completion
@@ -499,11 +498,6 @@ djangorestframework-xml==2.0.0
# via
# -r requirements/edx/base.txt
# edx-enterprise
-docutils==0.19
- # via
- # -c requirements/edx/../constraints.txt
- # -r requirements/edx/base.txt
- # botocore
done-xblock==2.1.0
# via -r requirements/edx/base.txt
drf-jwt==1.19.2
@@ -514,6 +508,8 @@ drf-nested-routers==0.93.4
# via
# -r requirements/edx/base.txt
# openedx-blockstore
+drf-spectacular==0.26.4
+ # via -r requirements/edx/base.txt
drf-yasg==1.21.5
# via
# -c requirements/edx/../constraints.txt
@@ -532,7 +528,9 @@ edx-auth-backends==4.2.0
# -r requirements/edx/base.txt
# openedx-blockstore
edx-braze-client==0.1.7
- # via -r requirements/edx/base.txt
+ # via
+ # -r requirements/edx/base.txt
+ # edx-enterprise
edx-bulk-grades==1.0.2
# via
# -r requirements/edx/base.txt
@@ -573,7 +571,7 @@ edx-django-utils==5.7.0
# openedx-blockstore
# ora2
# super-csv
-edx-drf-extensions==8.9.2
+edx-drf-extensions==8.10.0
# via
# -r requirements/edx/base.txt
# edx-completion
@@ -585,15 +583,15 @@ edx-drf-extensions==8.9.2
# edx-when
# edxval
# openedx-learning
-edx-enterprise==4.1.11
+edx-enterprise==4.3.2
# via
# -c requirements/edx/../constraints.txt
# -r requirements/edx/base.txt
-edx-event-bus-kafka==5.4.0
+edx-event-bus-kafka==5.5.0
# via -r requirements/edx/base.txt
edx-event-bus-redis==0.3.1
# via -r requirements/edx/base.txt
-edx-i18n-tools==1.1.0
+edx-i18n-tools==1.2.0
# via
# -r requirements/edx/base.txt
# -r requirements/edx/testing.in
@@ -604,7 +602,7 @@ edx-milestones==0.5.0
# via -r requirements/edx/base.txt
edx-name-affirmation==2.3.6
# via -r requirements/edx/base.txt
-edx-opaque-keys[django]==2.5.0
+edx-opaque-keys[django]==2.5.1
# via
# -r requirements/edx/base.txt
# edx-bulk-grades
@@ -615,7 +613,6 @@ edx-opaque-keys[django]==2.5.0
# edx-milestones
# edx-organizations
# edx-proctoring
- # edx-user-state-client
# edx-when
# lti-consumer-xblock
# openedx-events
@@ -639,7 +636,7 @@ edx-rest-api-client==5.6.0
# edx-proctoring
edx-search==3.6.0
# via -r requirements/edx/base.txt
-edx-sga==0.22.0
+edx-sga==0.23.0
# via -r requirements/edx/base.txt
edx-submissions==3.6.0
# via
@@ -653,6 +650,7 @@ edx-toggles==5.1.0
# via
# -r requirements/edx/base.txt
# edx-completion
+ # edx-enterprise
# edx-event-bus-kafka
# edx-event-bus-redis
# edx-name-affirmation
@@ -661,13 +659,11 @@ edx-toggles==5.1.0
# ora2
edx-token-utils==0.2.1
# via -r requirements/edx/base.txt
-edx-user-state-client==1.3.2
- # via -r requirements/edx/base.txt
edx-when==2.4.0
# via
# -r requirements/edx/base.txt
# edx-proctoring
-edxval==2.4.2
+edxval==2.4.3
# via -r requirements/edx/base.txt
elasticsearch==7.13.4
# via
@@ -693,7 +689,7 @@ execnet==2.0.2
# via pytest-xdist
factory-boy==3.3.0
# via -r requirements/edx/testing.in
-faker==19.6.1
+faker==19.6.2
# via factory-boy
fastapi==0.103.1
# via pact-python
@@ -701,7 +697,7 @@ fastavro==1.8.3
# via
# -r requirements/edx/base.txt
# openedx-events
-filelock==3.12.3
+filelock==3.12.4
# via
# -r requirements/edx/base.txt
# snowflake-connector-python
@@ -752,7 +748,7 @@ httpretty==1.1.4
# via -r requirements/edx/testing.in
httpx==0.23.3
# via pact-python
-icalendar==5.0.7
+icalendar==5.0.8
# via -r requirements/edx/base.txt
idna==3.4
# via
@@ -770,7 +766,7 @@ importlib-metadata==6.8.0
# -r requirements/edx/base.txt
# markdown
# pytest-randomly
-importlib-resources==6.0.1
+importlib-resources==6.1.0
# via
# -r requirements/edx/base.txt
# jsonschema
@@ -778,6 +774,7 @@ importlib-resources==6.0.1
inflection==0.5.1
# via
# -r requirements/edx/base.txt
+ # drf-spectacular
# drf-yasg
iniconfig==2.0.0
# via pytest
@@ -806,7 +803,7 @@ jinja2==3.1.2
# code-annotations
# coreschema
# diff-cover
-jmespath==0.10.0
+jmespath==1.0.1
# via
# -r requirements/edx/base.txt
# boto3
@@ -828,9 +825,10 @@ jsonfield==3.1.0
# edx-submissions
# lti-consumer-xblock
# ora2
-jsonschema==4.19.0
+jsonschema==4.19.1
# via
# -r requirements/edx/base.txt
+ # drf-spectacular
# optimizely-sdk
jsonschema-specifications==2023.7.1
# via
@@ -839,6 +837,7 @@ jsonschema-specifications==2023.7.1
jwcrypto==1.5.0
# via
# -r requirements/edx/base.txt
+ # django-oauth-toolkit
# pylti1p3
kombu==5.3.2
# via
@@ -846,7 +845,7 @@ kombu==5.3.2
# celery
laboratory==1.0.2
# via -r requirements/edx/base.txt
-lazy==1.5
+lazy==1.6
# via
# -r requirements/edx/base.txt
# acid-xblock
@@ -864,8 +863,10 @@ loremipsum==1.0.5
# via
# -r requirements/edx/base.txt
# ora2
-lti-consumer-xblock==9.6.2
- # via -r requirements/edx/base.txt
+lti-consumer-xblock==9.6.1
+ # via
+ # -c requirements/edx/../constraints.txt
+ # -r requirements/edx/base.txt
lxml==4.9.3
# via
# -r requirements/edx/base.txt
@@ -965,6 +966,8 @@ openai==0.28.0
# via
# -r requirements/edx/base.txt
# edx-enterprise
+openedx-atlas==0.5.0
+ # via -r requirements/edx/base.txt
openedx-blockstore==1.4.0
# via -r requirements/edx/base.txt
openedx-calc==3.0.1
@@ -976,10 +979,11 @@ openedx-django-pyfs==3.4.0
# xblock
openedx-django-require==2.1.0
# via -r requirements/edx/base.txt
-openedx-django-wiki==2.0.1
+openedx-django-wiki==2.0.3
# via -r requirements/edx/base.txt
-openedx-events==8.6.0
+openedx-events==8.5.0
# via
+ # -c requirements/edx/../constraints.txt
# -r requirements/edx/base.txt
# edx-event-bus-kafka
# edx-event-bus-redis
@@ -987,13 +991,15 @@ openedx-filters==1.6.0
# via
# -r requirements/edx/base.txt
# lti-consumer-xblock
-openedx-learning==0.1.5
- # via -r requirements/edx/base.txt
+openedx-learning==0.1.6
+ # via
+ # -c requirements/edx/../constraints.txt
+ # -r requirements/edx/base.txt
openedx-mongodbproxy==0.2.0
# via -r requirements/edx/base.txt
optimizely-sdk==4.1.1
# via -r requirements/edx/base.txt
-ora2==5.3.0
+ora2==5.4.0
# via -r requirements/edx/base.txt
oscrypto==1.3.0
# via
@@ -1095,7 +1101,7 @@ pycparser==2.21
# via
# -r requirements/edx/base.txt
# cffi
-pycryptodomex==3.18.0
+pycryptodomex==3.19.0
# via
# -r requirements/edx/base.txt
# edx-proctoring
@@ -1223,7 +1229,6 @@ python-dateutil==2.8.2
# botocore
# celery
# edx-ace
- # edx-drf-extensions
# edx-enterprise
# edx-proctoring
# faker
@@ -1277,6 +1282,7 @@ pyyaml==6.0.1
# via
# -r requirements/edx/base.txt
# code-annotations
+ # drf-spectacular
# edx-django-release-util
# edx-i18n-tools
# xblock
@@ -1284,9 +1290,8 @@ random2==1.0.1
# via -r requirements/edx/base.txt
recommender-xblock==2.0.1
# via -r requirements/edx/base.txt
-redis==4.6.0
+redis==5.0.0
# via
- # -c requirements/edx/../constraints.txt
# -r requirements/edx/base.txt
# walrus
referencing==0.30.2
@@ -1328,7 +1333,7 @@ requests-oauthlib==1.3.1
# social-auth-core
rfc3986[idna2008]==1.5.0
# via httpx
-rpds-py==0.10.2
+rpds-py==0.10.3
# via
# -r requirements/edx/base.txt
# jsonschema
@@ -1347,7 +1352,7 @@ rules==3.3
# edx-enterprise
# edx-proctoring
# openedx-learning
-s3transfer==0.1.13
+s3transfer==0.6.2
# via
# -r requirements/edx/base.txt
# boto3
@@ -1392,7 +1397,6 @@ six==1.16.0
# edx-ccx-keys
# edx-codejail
# edx-django-release-util
- # edx-drf-extensions
# edx-lint
# edx-milestones
# edx-rbac
@@ -1475,7 +1479,7 @@ sympy==1.12
# via
# -r requirements/edx/base.txt
# openedx-calc
-testfixtures==7.1.0
+testfixtures==7.2.0
# via
# -r requirements/edx/base.txt
# -r requirements/edx/testing.in
@@ -1512,7 +1516,7 @@ tqdm==4.66.1
# -r requirements/edx/base.txt
# nltk
# openai
-typing-extensions==4.7.1
+typing-extensions==4.8.0
# via
# -r requirements/edx/base.txt
# annotated-types
@@ -1522,7 +1526,6 @@ typing-extensions==4.7.1
# edx-opaque-keys
# faker
# fastapi
- # filelock
# grimp
# import-linter
# kombu
@@ -1548,11 +1551,13 @@ uritemplate==4.1.1
# via
# -r requirements/edx/base.txt
# coreapi
+ # drf-spectacular
# drf-yasg
urllib3==1.26.16
# via
# -c requirements/edx/../constraints.txt
# -r requirements/edx/base.txt
+ # botocore
# elasticsearch
# pact-python
# py2neo
@@ -1616,7 +1621,6 @@ xblock[django]==1.7.0
# done-xblock
# edx-completion
# edx-sga
- # edx-user-state-client
# edx-when
# lti-consumer-xblock
# ora2
@@ -1649,7 +1653,7 @@ yarl==1.9.2
# via
# -r requirements/edx/base.txt
# aiohttp
-zipp==3.16.2
+zipp==3.17.0
# via
# -r requirements/edx/base.txt
# importlib-metadata
diff --git a/requirements/pip-tools.txt b/requirements/pip-tools.txt
index a4b79a932dda..f9aebfe766c5 100644
--- a/requirements/pip-tools.txt
+++ b/requirements/pip-tools.txt
@@ -25,7 +25,7 @@ tomli==2.0.1
# pyproject-hooks
wheel==0.41.2
# via pip-tools
-zipp==3.16.2
+zipp==3.17.0
# via importlib-metadata
# The following packages are considered to be unsafe in a requirements file:
diff --git a/requirements/pip.txt b/requirements/pip.txt
index a53f711a5dcd..3e7d8f4a813f 100644
--- a/requirements/pip.txt
+++ b/requirements/pip.txt
@@ -10,5 +10,5 @@ wheel==0.41.2
# The following packages are considered to be unsafe in a requirements file:
pip==23.2.1
# via -r requirements/pip.in
-setuptools==68.2.1
+setuptools==68.2.2
# via -r requirements/pip.in
diff --git a/scripts/gha-shards-readme.md b/scripts/gha-shards-readme.md
index 8a3d96da3a37..9996a1f3b241 100644
--- a/scripts/gha-shards-readme.md
+++ b/scripts/gha-shards-readme.md
@@ -18,7 +18,7 @@ with django settings for each module and paths for submodules to test for exampl
```
The `common` and `openedx` modules are tested with both `lms` and `cms` settings; that's why there are shards with the same `openedx`
submodules but with different Django settings.
-For more details on sharding strategy please refer to this section on [sharding](https://openedx.atlassian.net/wiki/spaces/AT/pages/3235971586/edx-platfrom+unit+tests+migration+from+Jenkins+to+Github+Actions#Motivation-for-sharding-manually)
+For more details on sharding strategy please refer to this section on [sharding](https://openedx.atlassian.net/wiki/spaces/PLAT/pages/3869376544/edx-platform+unit+tests+migration+from+Jenkins+to+Github+Actions#Motivation-for-sharding-manually)
#### Unit tests count check is failing
There's a check in place that makes sure that all the unit tests under edx-platform modules are specified in `unit-test-shards.json`
@@ -27,7 +27,7 @@ against the entire codebase the check will fail.
You'd have to update the `unit-test-shards.json` file manually to fix this.
##### How to fix
-- If you've added a new django app to the codebase, and you want to add it to the unit tests you need to add it to the `unit-test-shards.json`, details on where (in which shard) to place your Django app please refer to the [sharding](https://openedx.atlassian.net/wiki/spaces/AT/pages/3235971586/edx-platfrom+unit+tests+migration+from+Jenkins+to+Github+Actions#Where-should-I-place-my-new-Django-app) section in this document.
+- If you've added a new django app to the codebase, and you want to add it to the unit tests you need to add it to the `unit-test-shards.json`, details on where (in which shard) to place your Django app please refer to the [sharding](https://openedx.atlassian.net/wiki/spaces/PLAT/pages/3869376544/edx-platform+unit+tests+migration+from+Jenkins+to+Github+Actions#Where-should-I-place-my-new-Django-app%3A) section in this document.
- If you haven't added any new django app to the codebase, you can debug / verify this by collecting unit tests against a submodule by running `pytest` for example:
```
pytest --collect-only --ds=cms.envs.test cms/
diff --git a/scripts/xblock/requirements.txt b/scripts/xblock/requirements.txt
index c7433da88f84..fcde0635a07b 100644
--- a/scripts/xblock/requirements.txt
+++ b/scripts/xblock/requirements.txt
@@ -12,5 +12,5 @@ idna==3.4
# via requests
requests==2.31.0
# via -r scripts/xblock/requirements.in
-urllib3==2.0.4
+urllib3==2.0.5
# via requests
diff --git a/setup.py b/setup.py
index 17d0f07b01e1..f405f92a95b4 100644
--- a/setup.py
+++ b/setup.py
@@ -22,7 +22,6 @@
"image = xmodule.template_block:TranslateCustomTagBlock",
"library = xmodule.library_root_xblock:LibraryRoot",
"library_content = xmodule.library_content_block:LibraryContentBlock",
- "library_sourced = xmodule.library_sourced_block:LibrarySourcedBlock",
"lti = xmodule.lti_block:LTIBlock",
"poll_question = xmodule.poll_block:PollBlock",
"problem = xmodule.capa_block:ProblemBlock",
diff --git a/test_root/semgrep/README.rst b/test_root/semgrep/README.rst
new file mode 100644
index 000000000000..92fa16f1bf05
--- /dev/null
+++ b/test_root/semgrep/README.rst
@@ -0,0 +1,21 @@
+Semgrep linters
+###############
+
+Linting rules for use with `semgrep`_ during CI checks on PRs.
+
+Status
+******
+
+This is an experimental approach to developing new linting rules. Semgrep provides by-example structural matching that can be easier to write and maintain than procedural code inspecting ASTs. If the approach works out, we can expand our use of Semgrep; if it becomes a problem for some reason, we can switch to adding pylint rules in edx-lint.
+
+Ignoring failures
+*****************
+
+If you need to tell semgrep to ignore a block of code, put a ``# nosemgrep`` comment on or before the first matched line.
+
+Documentation for writing new rules:
+
+- https://semgrep.dev/docs/writing-rules/rule-syntax/
+- https://semgrep.dev/docs/writing-rules/pattern-syntax/
+
+.. _semgrep: https://github.com/returntocorp/semgrep
diff --git a/test_root/semgrep/celery-code-owner.yml b/test_root/semgrep/celery-code-owner.yml
new file mode 100644
index 000000000000..c8cf417e43a8
--- /dev/null
+++ b/test_root/semgrep/celery-code-owner.yml
@@ -0,0 +1,104 @@
+rules:
+ - id: celery-missing-code-owner-function
+ # We can't link directly to the howto doc in question because
+ # semgrep has a bug around long lines:
+ # https://github.com/returntocorp/semgrep/issues/8608
+ #
+ # Here's the intended URL, for reference:
+ # https://edx.readthedocs.io/projects/edx-django-utils/en/latest/monitoring/how_tos/add_code_owner_custom_attribute_to_an_ida.html#handling-celery-tasks
+ message: |
+ Celery tasks need to be decorated with `@set_code_owner_attribute`
+ (from the `edx_django_utils.monitoring` module) in order for us
+ to correctly track code-owners for errors and in other monitoring.
+
+ For more information, see the Celery section of "Add Code_Owner
+ Custom Attributes to an IDA" in the Monitoring How-Tos of
+ .
+ languages:
+ - python
+ patterns:
+ # Find functions with decorators containing the substring "task"
+ # in their name. This might end up with false positives, but
+ # there are a lot of variations on how we decorate Celery tasks.
+
+ # This pattern should match all decorators, whether or not
+ # they're called as a function (both `@foo(...)` and `@foo`)
+ # and whether or not there are other decorators above or below.
+ - pattern-either:
+ - pattern: |
+ @$TASK
+ def $F(...):
+ ...
+ - pattern: |
+ @$TASK(...)
+ def $F(...):
+ ...
+
+ # Restrict the decorators of interest to just ones with "task"
+ # in the name.
+ - metavariable-pattern:
+ metavariable: $TASK
+ patterns:
+ - pattern-regex: >-
+ [^\(]*task(\(|$)
+
+ # Filter out all of the properly annotated functions, leaving
+ # just the ones of interest.
+ - pattern-not: |
+ @set_code_owner_attribute
+ def $F(...):
+ ...
+ # This is an alternative approach that we have needed in rare cases.
+ - pattern-not: |
+ def $F(...):
+ ...
+ set_code_owner_attribute_from_module(...)
+
+ severity: WARNING
+
+ # This is like celery-missing-code-owner-function but for the `run`
+ # method of Task classes.
+ - id: celery-missing-code-owner-class
+ message: |
+ Celery task classes need to decorate their `run` method with
+ `@set_code_owner_attribute` (imported from `edx_django_utils.monitoring`)
+ in order for us to correctly track code-owners for errors and in other
+ monitoring. Alternatively, the `run` method can call
+ `set_code_owner_attribute_from_module`.
+
+ For more information, see the Celery section of "Add Code_Owner
+ Custom Attributes to an IDA" in the Monitoring How-Tos of
+ .
+ languages:
+ - python
+ patterns:
+ - pattern: |
+ class $C(..., $SUPER, ...):
+ def run(...):
+ ...
+ - metavariable-pattern:
+ metavariable: $SUPER
+ patterns:
+ - pattern-regex: "Task$"
+
+ - pattern-not: |
+ class $C(..., $SUPER, ...):
+
+ @set_code_owner_attribute
+ def run(...):
+ ...
+
+ - pattern-not: |
+ class $C(..., $SUPER, ...):
+
+ @set_code_owner_attribute
+ def run(...):
+ ...
+ - pattern-not: |
+ class $C(..., $SUPER, ...):
+
+ def run(...):
+ ...
+ set_code_owner_attribute_from_module(...)
+
+ severity: WARNING
diff --git a/webpack.common.config.js b/webpack.common.config.js
index 4a7bb7366bba..13d368c559bb 100644
--- a/webpack.common.config.js
+++ b/webpack.common.config.js
@@ -77,7 +77,6 @@ module.exports = Merge.smart({
// Studio
Import: './cms/static/js/features/import/factories/import.js',
CourseOrLibraryListing: './cms/static/js/features_jsx/studio/CourseOrLibraryListing.jsx',
- LibrarySourcedBlockPicker: './xmodule/assets/library_source_block/LibrarySourcedBlockPicker.jsx', // eslint-disable-line max-len
'js/factories/textbooks': './cms/static/js/factories/textbooks.js',
'js/factories/container': './cms/static/js/factories/container.js',
'js/factories/context_course': './cms/static/js/factories/context_course.js',
diff --git a/xmodule/assets/README.rst b/xmodule/assets/README.rst
index a39b389a357a..a697915db835 100644
--- a/xmodule/assets/README.rst
+++ b/xmodule/assets/README.rst
@@ -46,11 +46,6 @@ It is collected into the static root, and then linked to from XBlock fragments b
.. _annotatable/_display.scss: https://github.com/openedx/edx-platform/tree/master/xmodule/assets/annotatable/_display.scss
.. _simplify things: https://github.com/openedx/edx-platform/issues/32621
-Static CSS (.css)
-*****************
-
-Non-themable, ready-to-seve CSS may also be added to the any block type's
-subdirectory. For example, see `library_source_block/style.css`_.
JavaScript (.js)
****************
@@ -72,7 +67,7 @@ Currently, edx-platform XBlock JS is defined both here in `xmodule/assets`_ and
* For other "purer" blocks, the JS is used as a standard XBlock fragment. Example blocks:
* `VerticalBlock`_
- * `LibrarySourcedBlock`_
+ * `LibraryContentBlock`_
As part of an `active build refactoring`_, we will soon consolidate all edx-platform XBlock JS here in `xmodule/assets`_.
@@ -82,7 +77,7 @@ As part of an `active build refactoring`_, we will soon consolidate all edx-plat
.. _HtmlBlock: https://github.com/openedx/edx-platform/blob/master/xmodule/html_block.py
.. _AnnotatableBlock: https://github.com/openedx/edx-platform/blob/master/xmodule/annotatable_block.py
.. _VerticalBlock: https://github.com/openedx/edx-platform/blob/master/xmodule/vertical_block.py
-.. _LibrarySourcedBlock: https://github.com/openedx/edx-platform/blob/master/xmodule/library_sourced_block.py
+.. _LibraryContentBlock: https://github.com/openedx/edx-platform/blob/master/xmodule/library_content_block.py
.. _active build refactoring: https://github.com/openedx/edx-platform/issues/31624
.. _builtin_assets.py: https://github.com/openedx/edx-platform/tree/master/xmodule/util/builtin_assets.py
.. _static_content.py: https://github.com/openedx/edx-platform/blob/master/xmodule/static_content.py
diff --git a/xmodule/assets/library_source_block/LibrarySourcedBlockPicker.jsx b/xmodule/assets/library_source_block/LibrarySourcedBlockPicker.jsx
deleted file mode 100644
index 0b6363893a76..000000000000
--- a/xmodule/assets/library_source_block/LibrarySourcedBlockPicker.jsx
+++ /dev/null
@@ -1,236 +0,0 @@
-/* globals gettext */
-
-import 'whatwg-fetch';
-import PropTypes from 'prop-types';
-import React from 'react';
-import _ from 'underscore';
-import styles from './style.css';
-
-class LibrarySourcedBlockPicker extends React.Component {
- constructor(props) {
- super(props);
- this.state = {
- libraries: [],
- xblocks: [],
- // eslint-disable-next-line react/no-unused-state
- searchedLibrary: '',
- libraryLoading: false,
- xblocksLoading: false,
- selectedLibrary: undefined,
- selectedXblocks: new Set(this.props.selectedXblocks),
- };
- this.onLibrarySearchInput = this.onLibrarySearchInput.bind(this);
- this.onXBlockSearchInput = this.onXBlockSearchInput.bind(this);
- this.onLibrarySelected = this.onLibrarySelected.bind(this);
- this.onXblockSelected = this.onXblockSelected.bind(this);
- this.onDeleteClick = this.onDeleteClick.bind(this);
- }
-
- componentDidMount() {
- this.fetchLibraries();
- }
-
- // eslint-disable-next-line react/sort-comp
- fetchLibraries(textSearch = '', page = 1, append = false) {
- this.setState({
- // eslint-disable-next-line react/no-access-state-in-setstate
- libraries: append ? this.state.libraries : [],
- libraryLoading: true,
- }, async function() {
- try {
- let res = await fetch(`/api/libraries/v2/?pagination=true&page=${page}&text_search=${textSearch}`);
- res = await res.json();
- this.setState({
- // eslint-disable-next-line react/no-access-state-in-setstate
- libraries: this.state.libraries.concat(res.results),
- libraryLoading: false,
- }, () => {
- if (res.next) {
- this.fetchLibraries(textSearch, page + 1, true);
- }
- });
- } catch (error) {
- $('#library-sourced-block-picker').trigger('error', {
- title: 'Could not fetch library',
- message: error,
- });
- this.setState({
- libraries: [],
- libraryLoading: false,
- });
- }
- });
- }
-
- fetchXblocks(library, textSearch = '', page = 1, append = false) {
- this.setState({
- // eslint-disable-next-line react/no-access-state-in-setstate
- xblocks: append ? this.state.xblocks : [],
- xblocksLoading: true,
- }, async function() {
- try {
- let res = await fetch(`/api/libraries/v2/${library}/blocks/?pagination=true&page=${page}&text_search=${textSearch}`);
- res = await res.json();
- this.setState({
- // eslint-disable-next-line react/no-access-state-in-setstate
- xblocks: this.state.xblocks.concat(res.results),
- xblocksLoading: false,
- }, () => {
- if (res.next) {
- this.fetchXblocks(library, textSearch, page + 1, true);
- }
- });
- } catch (error) {
- $('#library-sourced-block-picker').trigger('error', {
- title: 'Could not fetch xblocks',
- message: error,
- });
- this.setState({
- xblocks: [],
- xblocksLoading: false,
- });
- }
- });
- }
-
- onLibrarySearchInput(event) {
- event.persist();
- this.setState({
- // eslint-disable-next-line react/no-unused-state
- searchedLibrary: event.target.value,
- });
- if (!this.debouncedFetchLibraries) {
- this.debouncedFetchLibraries = _.debounce(value => {
- this.fetchLibraries(value);
- }, 300);
- }
- this.debouncedFetchLibraries(event.target.value);
- }
-
- onXBlockSearchInput(event) {
- event.persist();
- if (!this.debouncedFetchXblocks) {
- this.debouncedFetchXblocks = _.debounce(value => {
- this.fetchXblocks(this.state.selectedLibrary, value);
- }, 300);
- }
- this.debouncedFetchXblocks(event.target.value);
- }
-
- onLibrarySelected(event) {
- this.setState({
- selectedLibrary: event.target.value,
- });
- this.fetchXblocks(event.target.value);
- }
-
- onXblockSelected(event) {
- // eslint-disable-next-line prefer-const, react/no-access-state-in-setstate
- let state = new Set(this.state.selectedXblocks);
- if (event.target.checked) {
- state.add(event.target.value);
- } else {
- state.delete(event.target.value);
- }
- this.setState({
- selectedXblocks: state,
- }, this.updateList);
- }
-
- onDeleteClick(event) {
- let value;
- if (event.target.tagName == 'SPAN') {
- value = event.target.parentElement.dataset.value;
- } else {
- value = event.target.dataset.value;
- }
- // eslint-disable-next-line prefer-const, react/no-access-state-in-setstate
- let state = new Set(this.state.selectedXblocks);
- state.delete(value);
- this.setState({
- selectedXblocks: state,
- }, this.updateList);
- }
-
- updateList(list) {
- $('#library-sourced-block-picker').trigger('selected-xblocks', {
- sourceBlockIds: Array.from(this.state.selectedXblocks),
- });
- }
-
- render() {
- return (
-
-
-
-
-
- {/* eslint-disable-next-line react/no-unescaped-entities */}
- Hitting 'Save and Import' will import the latest versions of the selected blocks, overwriting any changes done to this block post-import.
-
-
- );
- }
-}
-
-LibrarySourcedBlockPicker.propTypes = {
- // eslint-disable-next-line react/forbid-prop-types
- selectedXblocks: PropTypes.array,
-};
-
-LibrarySourcedBlockPicker.defaultProps = {
- selectedXblocks: [],
-};
-
-export {LibrarySourcedBlockPicker}; // eslint-disable-line import/prefer-default-export
diff --git a/xmodule/assets/library_source_block/public/js/library_source_block.js b/xmodule/assets/library_source_block/public/js/library_source_block.js
deleted file mode 100644
index 9674080d59dc..000000000000
--- a/xmodule/assets/library_source_block/public/js/library_source_block.js
+++ /dev/null
@@ -1,58 +0,0 @@
-/* JavaScript for allowing editing options on LibrarySourceBlock's studio view */
-window.LibrarySourceBlockStudioView = function(runtime, element) {
- 'use strict';
- var self = this;
-
- $('#library-sourced-block-picker', element).on('selected-xblocks', function(e, params) {
- self.sourceBlockIds = params.sourceBlockIds;
- });
-
- $('#library-sourced-block-picker', element).on('error', function(e, params) {
- runtime.notify('error', {title: gettext(params.title), message: params.message});
- });
-
- $('.save-button', element).on('click', function(e) {
- e.preventDefault();
- var url = $(e.target).data('submit-url');
- var data = {
- values: {
- source_block_ids: self.sourceBlockIds
- },
- defaults: ['display_name']
- };
-
- runtime.notify('save', {
- state: 'start',
- message: gettext('Saving'),
- element: element
- });
- $.ajax({
- type: 'POST',
- url: url,
- data: JSON.stringify(data),
- global: false // Disable error handling that conflicts with studio's notify('save') and notify('cancel')
- }).done(function() {
- runtime.notify('save', {
- state: 'end',
- element: element
- });
- }).fail(function(jqXHR) {
- var message = gettext('This may be happening because of an error with our server or your internet connection. Try refreshing the page or making sure you are online.'); // eslint-disable-line max-len
- if (jqXHR.responseText) { // Is there a more specific error message we can show?
- try {
- message = JSON.parse(jqXHR.responseText).error;
- if (typeof message === 'object' && message.messages) {
- // e.g. {"error": {"messages": [{"text": "Unknown user 'bob'!", "type": "error"}, ...]}} etc.
- message = $.map(message.messages, function(msg) { return msg.text; }).join(', ');
- }
- } catch (error) { message = jqXHR.responseText.substr(0, 300); }
- }
- runtime.notify('error', {title: gettext('Unable to update settings'), message: message});
- });
- });
-
- $('.cancel-button', element).on('click', function(e) {
- e.preventDefault();
- runtime.notify('cancel', {});
- });
-};
diff --git a/xmodule/assets/library_source_block/style.css b/xmodule/assets/library_source_block/style.css
deleted file mode 100644
index 4892f20405c0..000000000000
--- a/xmodule/assets/library_source_block/style.css
+++ /dev/null
@@ -1,58 +0,0 @@
-.column {
- display: flex;
- flex-direction: column;
- margin: 10px;
- max-width: 300px;
- flex-grow: 1;
-}
-.elementList {
- margin-top: 10px;
-}
-input.search {
- width: 100% !important;
- height: auto !important;
-}
-.element > input[type='checkbox'],
-.element > input[type='radio'] {
- position: absolute;
- width: 0 !important;
- height: 0 !important;
- top: -9999px;
-}
-.element > .elementItem {
- display: flex;
- flex-grow: 1;
- padding: 0.625rem 1.25rem;
- border: 1px solid rgba(0, 0, 0, 0.25);
-}
-.element + .element > label {
- border-top: 0;
-}
-.element > input[type='checkbox']:focus + label,
-.element > input[type='radio']:focus + label,
-.element > input:hover + label {
- background: #f6f6f7;
- cursor: pointer;
-}
-.element > input:checked + label {
- background: #23419f;
- color: #fff;
-}
-.element > input[type='checkbox']:checked:focus + label,
-.element > input[type='radio']:checked:focus + label,
-.element > input:checked:hover + label {
- background: #193787;
- cursor: pointer;
-}
-.selectedBlocks {
- padding: 12px 8px 20px;
-}
-button.remove {
- background: #e00;
- color: #fff;
- border: solid rgba(0,0,0,0.25) 1px;
-}
-button.remove:focus,
-button.remove:hover {
- background: #d00;
-}
diff --git a/xmodule/capa_block.py b/xmodule/capa_block.py
index 94d4b2a61f45..67d5fd58c23c 100644
--- a/xmodule/capa_block.py
+++ b/xmodule/capa_block.py
@@ -168,7 +168,7 @@ class ProblemBlock(
scope=Scope.settings,
# it'd be nice to have a useful default but it screws up other things; so,
# use display_name_with_default for those
- default=_("Blank Advanced Problem")
+ default=_("Blank Problem")
)
attempts = Integer(
help=_("Number of attempts taken by the student on this problem"),
diff --git a/xmodule/docs/decisions/0003-library-content-block-schema.rst b/xmodule/docs/decisions/0003-library-content-block-schema.rst
new file mode 100644
index 000000000000..cf49f72864e8
--- /dev/null
+++ b/xmodule/docs/decisions/0003-library-content-block-schema.rst
@@ -0,0 +1,225 @@
+
+Evolving the library_content block schema
+#########################################
+
+Status
+******
+
+**Provisional**
+
+Subject to change due to implementation learnings and stakeholder feedback.
+
+Context
+*******
+
+The library_content block is an existing block type which allows users to include a specified number of blocks into a course, randomly picked per-learner from a "V1" (modulestore-backed) content library, optionally filtered by the blocks' ``capa_type`` (only applicable to ``problem`` blocks). We are incrementally improving this feature:
+
+* We are soon adding support for "V2" (blockstore-backed) content libraries to the library_content block. This will enable an improved library authoring experience and assist our transition away from modulestore and MongoDB. We need this not to break existing usages of the library_content block, and we need there to be a period of simultaneous V1/V2 support overlap to enable a reversible migration of libraries from modulestore to blockstore. Eventually, V1 support will be removed.
+
+* Next, we want to add support for non-randomized, hand-picked reference of library blocks. This is is a highly requested feature across the community.
+
+* In the future, we would like to support other modes: in particular, we want authors to eventually be able to hand-pick a set of blocks from a library, and *then* have the LMS randomly select a specified number of blokcs for each learner.
+
+We need to choose how to evolve the schema of the library_content block to support all of these incremental improvements. This is the current schema:
+
+.. list-table::
+ :header-rows: 1
+
+ * - Field
+ - Scope, Type
+ - Default
+ - Example
+ - Description
+
+ * - source_library_id
+ - settings, str|None
+ - None
+ - "library-v1:OEX+Lib1"
+ - Key of V1 source library; None means no library has been chosen.
+
+ * - source_library\_ version
+ - settings, str|None
+ - None
+ - TBD
+ - Version of V1 source library (a MongoID string). None means latest.
+
+ * - mode
+ - settings, str
+ - "random"
+ - "random"
+ - How blocks should be selected. Only valid value is "random".
+
+ * - capa_type
+ - settings, str
+ - "any"
+ - "symbolicresponse"
+ - Unless "any": Include only problems, and only problems of this response type.
+
+ * - children
+ - children, list of XBlocks
+ - []
+ - ``block-v1:...+type@problem+block@A``
+ ``block-v1:...+type@problem+block@B``
+ ``block-v1:...+type@problem+block@D``
+ ``block-v1:...+type@problem+block@F``
+ - Standard XBlock field that holds references to the child XBlocks. This field is only populated after the library content block is saved, at which time the matching XBlocks (e.g. filtered by capa_type) from the library are copied ("included") to become children of this block. Learners will often only see a subset of these children (up to max_count); see ``selected``. Course author may apply edits that are local to these included child blocks. Such edits to child blocks' Scope.settings fields will persist across library version upgrades, whereas edits to child blocks' Scope.content fields are wiped out when library version is upgraded.
+
+ * - max_count
+ - settings, int
+ - 1
+ - 2
+ - Number of children that LMS will randomly select for each learner. -1 means all.
+
+ * - selected
+ - user_state, list of (block type, block id) tuples
+ - []
+ - [("problem", "A"), ("problem", "F")]
+ - An ordered sub-list of the children, selected by the LMS to be shown to a given learner. At most max_count, unless max_count = -1. Once populated, this is kept stable for the learner, unless a the children or max_count are changed, in which case it will have blocks added or removed as necessary. If the list changes, it is re-shuffled.
+
+
+Decision
+********
+
+We will introduce the support for a "manual selection mode", without explicitly making it *mode* as hinted at by the old block schema. This will lead to a cleaner and more flexible implementation. We will achieve this with two new boolean settings: **manual** and **shuffle**:
+
+* When manual is *disabled* and shuffle is *enabled*, the block will behave as it did before. That is, it will import the entire library (filtered by capa_type) as its children, and present each user a random subset based on max_count. For backwards compatibility, these will be the default value of the settings.
+
+* When manual is *enabled*, shuffle is *disabled*, and max_count is set to -1, the block will behave in the "static" mode. That is, the user will be prompted to select specific blocks in the library, and each user will be presented those blocks in order.
+
+* When manual is *enabled*, any filter fields (currently just capa_type, but perhaps more in the future) will be ignored for the purposes of CMS deciding which blocks to import. That's because in the event that manually-picked children clash with the filters, we need to decide who would "win", and we are deciding here that the manually-picked children would win. However, we could choose to have the block-picker filter blocks based on filters.
+
+We will also remove the **mode** field, as it is no longer needed, and it has only ever had one value.
+
+The interaction between manual, shuffle, and max_count yields a matrix of 8 different behaviors:
+
+.. list-table::
+
+ * -
+ - **manual = False**
+ - **manual = True**
+
+ * - **shuffle = True, max_count = -1**
+ - Entire library included; LMS randomizes order per student *(V1's "random mode")*.
+ - Author manually includes blocks; LMS randomizes order per student.
+
+ * - **shuffle = True, max_count > 0**
+ - Entire library included; LMS selects random subset in random order for each student *(V1's "random mode")*.
+ - Author manually includes blocks; LMS selects random subset in random order for each student *(V2+'s desired "enhanced static" mode)*.
+
+ * - **shuffle = False, max_count = -1**
+ - Entire library included and shown to every learner in original order.
+ - Author manually includes blocks; they are shown to every learner in original order. *(V2's "static" mode)*.
+
+ * - **shuffle = False, max_count > 0**
+ - Entire library included, LMS selects random subset in original order *(No known use cases)*.
+ - Author manually includes blocks, LMS selects random subset in original order *(No known use cases)*.
+
+
+At first, we will only aim to support the "random mode" behaviors plus the new "static mode" behavior. Validation will be used to ensure that the other modes are not available. In the future, we could expect to loosen this restriction.
+
+The final library_content block schema, with all changes, will look like this:
+
+.. list-table::
+ :header-rows: 1
+
+ * - Field Name
+ - Scope, Type
+ - Default
+ - Example
+ - Description
+
+ * - source_library_id
+ - settings, str|None
+ - None
+ - "lib:Open-edX:ExampleLib"
+ - Key of V1 or V2 source library; None means unselected.
+
+ * - source_library\_ version
+ - settings, str|None
+ - None
+ - TBD
+ - Version of V1 source library (MongoID string) or V2 source library (a stringified int). None means latest.
+
+ * - manual
+ - settings, bool
+ - False
+ - True
+ - When False, all library blocks matching capa_type are copied as library_content children, including newly-added library blocks when upgrading source library version. When True, the course author is propmted to pick specific blocks from the library; these blocks become the library_content children. Studio respects these manual block choices (i.e., it won't auto-add new library blocks when the library version is updated).
+
+ * - capa_type
+ - settings, str
+ - "any"
+ - "symbolicresponse"
+ - Unless "any": Include only problems, and only problems of this response type. Setting manual to True overrides this filter, however it could still be used for filtering in the block-picker UI. *Note: In future versions, we may want to have filters available that are not specific to Problem or any other block type.*
+
+ * - children
+ - children, list of XBlocks
+ - []
+ - ``block-v1:...+type@problem+block@A``
+ ``block-v1:...+type@problem+block@B``
+ ``block-v1:...+type@problem+block@D``
+ ``block-v1:...+type@problem+block@F``
+ - Standard XBlock field that holds references to the child XBlocks. This field is only populated after the library content block is saved, at which time the matching XBlocks (e.g. filtered by capa_type, or hand-picked by author when manual is True) from the library are copied ("included") to become children of this block. Learners will often only see a subset of these children (up to max_count); see ``selected``. Course author may apply edits that are local to these included child blocks. Such edits to child blocks' Scope.settings fields will persist across library version upgrades, whereas edits to child blocks' Scope.content fields are wiped out when library version is upgraded.
+
+ * - max_count
+ - settings, int
+ - 1
+ - 2
+ - Number of children that LMS will randomly select for each learner. -1 means all.
+
+ * - shuffle
+ - settings, bool
+ - True
+ - False
+ - If False, the order of each learner's selected blocks will match the order of children. If True, the order will be randomized for each learner.
+
+ * - selected
+ - user_state, list of (block type, block id) tuples
+ - []
+ - [("problem", "A"), ("problem", "F")]
+ - An ordered sub-list of the children, selected by the LMS to be shown to a given learner. At most max_count, unless max_count = -1. Once populated, this is kept stable for the learner, unless a the children or max_count are changed, in which case it will have blocks added or removed as necessary. If the list changes, it is re-shuffled.
+
+
+.. figure:: ./0003-library-content-block-schema/library-block-flow.svg
+
+ The series of transformations library blocks go through, from the source libraries to the learner's unit view. Source `available on LucidChart`_; ask Axim if you need to edit it.
+
+.. _available on LucidChart: https://lucid.app/lucidchart/4cfbb5d6-86f3-4cd6-98cf-c85c123a8cb7/edit?viewport_loc=-208%2C-540%2C2190%2C1564%2C0_0&invitationId=inv_7c5dea04-a713-4f45-b73e-e06e20fcfa9d
+
+Consequences
+************
+
+We will implement the schema as described above, most likely in the following phases:
+
+#. Add support for V2 library sources to the existing random-only library_content block (no field schema changes yet).
+
+#. Add the manual and shuffle fields. Use validation to ensure that only the following permuations are allowed:
+
+ * Existing "random mode" (shuffle = True, manual = False)
+
+ * New "static" mode (shuffle = False, manual = True, max_count = -1)
+
+#. Beta release of V2 library authoring on edX.org.
+
+#. Migrate V1 libraries to V2 on edX.org for all users.
+
+Future work, in no particular order:
+
+ * If supported by product needs, then loosen restrictions on fields, potentially enabling the full matrix of eight "modes" described above.
+
+ * `Remove support for V1 content libraries.`_
+
+.. _Remove support for V1 content libraries: https://github.com/openedx/edx-platform/issues/32457
+
+
+Rejected Alternatives
+*********************
+
+* **Utilize the "mode" field to distinguish between random, manual, and any future modes.** This suffers from a matrix problem: with any given block behavior, it is possible that combination of those behaviors is a desirable "mode". For example, combining random and manual modes into a "random-from-manual-selection" is a desired future feature, but that new mode overlaps in functionality with both random and manual modes; in fact, random and manual modes would most just be special-cases of random-from-manual-selection mode. If the block were ever to be extended to incorporate, for example, recommendations, that would further multiply the available modes. The resulting code and interface would be harder to reason about than the flat list of flags and features that we decide on here.
+
+* **Implement V2 support in a separate block rather than the existing block.** This would make it harder to automatically migrate all modulestore libraries into blockstore, as all usages of the V1 library_content block would still exist. The ``library_sourced`` block was an implementation in this direction, but we deleted it.
+
+* **Implement non-randomized modes in a separate block.** This would yield a less flexible user experience, as it would force authors to pick from two separate blocks in the Studio UI depending on whether they want random or non-randomized (which is still feasible with the ADR's direction, but is not mandatory). Furthermore, it would create duplicated logic between the two blocks on the backend, increasing bug surface area. The ``library_sourced`` block was an implementation in this direction, but we deleted it.
+
+
+
diff --git a/xmodule/docs/decisions/0003-library-content-block-schema/library-block-flow.svg b/xmodule/docs/decisions/0003-library-content-block-schema/library-block-flow.svg
new file mode 100644
index 000000000000..63a0d8fb67dc
--- /dev/null
+++ b/xmodule/docs/decisions/0003-library-content-block-schema/library-block-flow.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/xmodule/library_content_block.py b/xmodule/library_content_block.py
index dd8b73112739..f8f0521ff530 100644
--- a/xmodule/library_content_block.py
+++ b/xmodule/library_content_block.py
@@ -714,10 +714,7 @@ def definition_from_xml(cls, xml_object, system):
if system.error_tracker is not None:
system.error_tracker(msg)
- definition = {
- attr_name: json.loads(attr_value)
- for attr_name, attr_value in xml_object.attrib.items()
- }
+ definition = dict(xml_object.attrib.items())
return definition, children
def definition_to_xml(self, resource_fs):
diff --git a/xmodule/library_sourced_block.py b/xmodule/library_sourced_block.py
deleted file mode 100644
index d96741d6e447..000000000000
--- a/xmodule/library_sourced_block.py
+++ /dev/null
@@ -1,159 +0,0 @@
-"""
-Library Sourced Content XBlock
-"""
-import logging
-
-from copy import copy
-from mako.template import Template as MakoTemplate
-from xblock.core import XBlock
-from xblock.fields import Scope, String, List
-from xblock.validation import ValidationMessage
-from xblockutils.resources import ResourceLoader
-from xblockutils.studio_editable import StudioEditableXBlockMixin
-from webob import Response
-from web_fragments.fragment import Fragment
-
-from xmodule.studio_editable import StudioEditableBlock as EditableChildrenMixin
-from xmodule.validation import StudioValidation, StudioValidationMessage
-
-log = logging.getLogger(__name__)
-loader = ResourceLoader(__name__)
-
-# Make '_' a no-op so we can scrape strings. Using lambda instead of
-# `django.utils.translation.ugettext_noop` because Django cannot be imported in this file
-_ = lambda text: text
-
-
-@XBlock.wants('library_tools') # Only needed in studio
-class LibrarySourcedBlock(StudioEditableXBlockMixin, EditableChildrenMixin, XBlock):
- """
- Library Sourced Content XBlock
-
- Allows copying specific XBlocks from a Blockstore-based content library into
- a modulestore-based course. The selected blocks are copied and become
- children of this block.
-
- When we implement support for Blockstore-based courses, it's expected we'll
- use a different mechanism for importing library content into a course.
- """
- display_name = String(
- help=_("The display name for this component."),
- default="Library Sourced Content",
- display_name=_("Display Name"),
- scope=Scope.content,
- )
- source_block_ids = List(
- display_name=_("Library Blocks List"),
- help=_("Enter the IDs of the library XBlocks that you wish to use."),
- scope=Scope.content,
- )
- editable_fields = ("display_name", "source_block_ids")
- has_children = True
- has_author_view = True
- resources_dir = 'assets/library_source_block'
- MAX_BLOCKS_ALLOWED = 10
-
- def __str__(self):
- return f"LibrarySourcedBlock: {self.display_name}"
-
- def __init__(self, *args, **kwargs):
- super().__init__(*args, **kwargs)
- if not self.source_block_ids:
- self.has_children = False
-
- def studio_view(self, context):
- """
- Render a form for editing this XBlock
- """
- fragment = Fragment()
- static_content = ResourceLoader('common.djangoapps.pipeline_mako').load_unicode('templates/static_content.html')
- render_react = MakoTemplate(static_content, default_filters=[]).get_def('renderReact')
- react_content = render_react.render(
- component="LibrarySourcedBlockPicker",
- id="library-sourced-block-picker",
- props={
- 'selectedXblocks': self.source_block_ids,
- }
- )
- fragment.content = loader.render_django_template('templates/library-sourced-block-studio-view.html', {
- 'react_content': react_content,
- 'save_url': self.runtime.handler_url(self, 'submit_studio_edits'),
- })
-
- fragment.add_javascript_url(self.runtime.local_resource_url(self, 'public/js/library_source_block.js'))
- fragment.initialize_js('LibrarySourceBlockStudioView')
-
- return fragment
-
- def author_view(self, context):
- """
- Renders the Studio preview view.
- """
- fragment = Fragment()
- context = {} if not context else copy(context) # Isolate context - without this there are weird bugs in Studio
- # EditableChildrenMixin.render_children will render HTML that allows instructors to make edits to the children
- context['can_move'] = False
- self.render_children(context, fragment, can_reorder=False, can_add=False)
- return fragment
-
- def student_view(self, context):
- """
- Renders the view that learners see.
- """
- result = Fragment()
- child_frags = self.runtime.render_children(self, context=context)
- result.add_resources(child_frags)
- result.add_content('
')
- for frag in child_frags:
- result.add_content(frag.content)
- result.add_content('
')
- return result
-
- def validate_field_data(self, validation, data):
- """
- Validate this block's field data. Instead of checking fields like self.name, check the
- fields set on data, e.g. data.name. This allows the same validation method to be re-used
- for the studio editor.
- """
- if len(data.source_block_ids) > self.MAX_BLOCKS_ALLOWED:
- # Because importing library blocks is an expensive operation
- validation.add(
- ValidationMessage(
- ValidationMessage.ERROR,
- _("A maximum of {0} components may be added.").format(self.MAX_BLOCKS_ALLOWED)
- )
- )
-
- def validate(self):
- """
- Validates the state of this library_sourced_xblock Instance. This is the override of the general XBlock method,
- and it will also ask its superclass to validate.
- """
- validation = super().validate()
- validation = StudioValidation.copy(validation)
-
- if not self.source_block_ids:
- validation.set_summary(
- StudioValidationMessage(
- StudioValidationMessage.NOT_CONFIGURED,
- _("No XBlock has been configured for this component. Use the editor to select the target blocks."),
- action_class='edit-button',
- action_label=_("Open Editor")
- )
- )
- return validation
-
- @XBlock.handler
- def submit_studio_edits(self, data, suffix=''):
- """
- Save changes to this block, applying edits made in Studio.
- """
- response = super().submit_studio_edits(data, suffix)
- # Replace our current children with the latest ones from the libraries.
- lib_tools = self.runtime.service(self, 'library_tools')
- try:
- lib_tools.import_from_blockstore(self, self.source_block_ids)
- except Exception as err: # pylint: disable=broad-except
- log.exception(err)
- return Response(_("Importing Library Block failed - are the IDs valid and readable?"), status=400)
- return response
diff --git a/xmodule/library_tools.py b/xmodule/library_tools.py
index 58cd8212416f..748f1b58ac23 100644
--- a/xmodule/library_tools.py
+++ b/xmodule/library_tools.py
@@ -196,7 +196,7 @@ def import_from_blockstore(self, dest_block, blockstore_block_ids):
content library) into modulestore, as a new child of dest_block.
Any existing children of dest_block are replaced.
- This is only used by LibrarySourcedBlock. It should verify first that
+ This is only used by LibraryContentBlock. It should verify first that
the number of block IDs is reasonable.
"""
dest_key = dest_block.scope_ids.usage_id
@@ -216,7 +216,7 @@ def import_from_blockstore(self, dest_block, blockstore_block_ids):
raise PermissionDenied()
# Read the source block; this will also confirm that user has permission to read it.
- # (This could be slow and use lots of memory, except for the fact that LibrarySourcedBlock which calls this
+ # (This could be slow and use lots of memory, except for the fact that LibraryContentBlock which calls this
# should be limiting the number of blocks to a reasonable limit. We load them all now instead of one at a
# time in order to raise any errors before we start actually copying blocks over.)
orig_blocks = [load_block(UsageKey.from_string(key), user) for key in blockstore_block_ids]
diff --git a/xmodule/templates/library-sourced-block-studio-view.html b/xmodule/templates/library-sourced-block-studio-view.html
deleted file mode 100644
index 08a2882b51c5..000000000000
--- a/xmodule/templates/library-sourced-block-studio-view.html
+++ /dev/null
@@ -1,19 +0,0 @@
-{% load i18n %}
-