Merge branch 'master' into maq/#33589
This commit is contained in:
@@ -53,16 +53,3 @@ REDIRECT_TO_LIBRARY_AUTHORING_MICROFRONTEND = WaffleFlag(
|
||||
# .. toggle_warning: Flag course_experience.relative_dates should also be active for relative dates functionalities to work.
|
||||
# .. toggle_tickets: https://openedx.atlassian.net/browse/AA-844
|
||||
CUSTOM_RELATIVE_DATES = CourseWaffleFlag(f'{WAFFLE_NAMESPACE}.custom_relative_dates', __name__)
|
||||
|
||||
|
||||
# .. toggle_name: studio.enable_course_update_notifications
|
||||
# .. toggle_implementation: CourseWaffleFlag
|
||||
# .. toggle_default: False
|
||||
# .. toggle_description: Waffle flag to enable course update notifications.
|
||||
# .. toggle_use_cases: temporary, open_edx
|
||||
# .. toggle_creation_date: 14-Feb-2024
|
||||
# .. toggle_target_removal_date: 14-Mar-2024
|
||||
ENABLE_COURSE_UPDATE_NOTIFICATIONS = CourseWaffleFlag(
|
||||
f'{WAFFLE_NAMESPACE}.enable_course_update_notifications',
|
||||
__name__
|
||||
)
|
||||
|
||||
@@ -19,7 +19,6 @@ import re
|
||||
from django.http import HttpResponseBadRequest
|
||||
from django.utils.translation import gettext as _
|
||||
|
||||
from cms.djangoapps.contentstore.config.waffle import ENABLE_COURSE_UPDATE_NOTIFICATIONS
|
||||
from cms.djangoapps.contentstore.utils import track_course_update_event, send_course_update_notification
|
||||
from openedx.core.lib.xblock_utils import get_course_update_items
|
||||
from xmodule.html_block import CourseInfoBlock # lint-amnesty, pylint: disable=wrong-import-order
|
||||
@@ -93,10 +92,9 @@ def update_course_updates(location, update, passed_id=None, user=None, request_m
|
||||
track_course_update_event(location.course_key, user, course_update_dict)
|
||||
|
||||
# send course update notification
|
||||
if ENABLE_COURSE_UPDATE_NOTIFICATIONS.is_enabled(location.course_key):
|
||||
send_course_update_notification(
|
||||
location.course_key, course_update_dict["content"], user,
|
||||
)
|
||||
send_course_update_notification(
|
||||
location.course_key, course_update_dict["content"], user,
|
||||
)
|
||||
|
||||
# remove status key
|
||||
if "status" in course_update_dict:
|
||||
|
||||
@@ -2255,7 +2255,7 @@ def send_course_update_notification(course_key, content, user):
|
||||
"course_update_content": text_content if len(text_content.strip()) < 10 else "Click here to view",
|
||||
**extra_context,
|
||||
},
|
||||
notification_type="course_update",
|
||||
notification_type="course_updates",
|
||||
content_url=f"{settings.LMS_ROOT_URL}/courses/{str(course_key)}/course/updates",
|
||||
app_name="updates",
|
||||
audience_filters={},
|
||||
|
||||
@@ -58,6 +58,7 @@ from common.djangoapps.util.json_request import JsonResponse, JsonResponseBadReq
|
||||
from common.djangoapps.util.string_utils import _has_non_ascii_characters
|
||||
from openedx.core.djangoapps.content.course_overviews.models import CourseOverview
|
||||
from openedx.core.djangoapps.credit.tasks import update_credit_course_requirements
|
||||
from openedx.core.djangoapps.discussions.tasks import update_discussions_settings_from_course
|
||||
from openedx.core.djangoapps.models.course_details import CourseDetails
|
||||
from openedx.core.djangoapps.site_configuration import helpers as configuration_helpers
|
||||
from openedx.core.djangolib.js_utils import dump_js_escaped_json
|
||||
@@ -302,6 +303,10 @@ def course_handler(request, course_key_string=None):
|
||||
else:
|
||||
return HttpResponseBadRequest()
|
||||
elif request.method == 'GET': # assume html
|
||||
# Update course discussion settings, sometimes the course discussion settings are not updated
|
||||
# when the course is created, so we need to update them here.
|
||||
course_key = CourseKey.from_string(course_key_string)
|
||||
update_discussions_settings_from_course(course_key)
|
||||
if course_key_string is None:
|
||||
return redirect(reverse('home'))
|
||||
else:
|
||||
|
||||
@@ -717,8 +717,8 @@ class TestCourseOutline(CourseTestCase):
|
||||
"""
|
||||
Test to check number of queries made to mysql and mongo
|
||||
"""
|
||||
with self.assertNumQueries(29, table_ignorelist=WAFFLE_TABLES):
|
||||
with check_mongo_calls(3):
|
||||
with self.assertNumQueries(32, table_ignorelist=WAFFLE_TABLES):
|
||||
with check_mongo_calls(5):
|
||||
self.client.get_html(reverse_course_url('course_handler', self.course.id))
|
||||
|
||||
|
||||
|
||||
@@ -15,6 +15,8 @@
|
||||
|
||||
// +Libs and Resets - *do not edit*
|
||||
// ====================
|
||||
|
||||
@import '_builtin-block-variables';
|
||||
@import 'bourbon/bourbon'; // lib - bourbon
|
||||
@import 'vendor/bi-app/bi-app-ltr'; // set the layout for left to right languages
|
||||
@import 'build-v1'; // shared app style assets/rendering
|
||||
|
||||
Binary file not shown.
73
common/static/sass/_builtin-block-variables.scss
Normal file
73
common/static/sass/_builtin-block-variables.scss
Normal file
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* In pursuit of decoupling the built-in XBlocks from edx-platform's Sass build
|
||||
* and ensuring comprehensive theming support in the extracted XBlocks,
|
||||
* we need to expose Sass variables as CSS variables.
|
||||
*
|
||||
* Ticket/Issue: https://github.com/openedx/edx-platform/issues/35173
|
||||
*/
|
||||
@import 'bourbon/bourbon';
|
||||
@import 'lms/theme/variables';
|
||||
@import 'lms/theme/variables-v1';
|
||||
@import 'cms/static/sass/partials/cms/theme/_variables';
|
||||
@import 'cms/static/sass/partials/cms/theme/_variables-v1';
|
||||
@import 'bootstrap/scss/variables';
|
||||
@import 'vendor/bi-app/bi-app-ltr';
|
||||
@import 'edx-pattern-library-shims/base/_variables.scss';
|
||||
|
||||
:root {
|
||||
--action-primary-active-bg: $action-primary-active-bg;
|
||||
--all-text-inputs: $all-text-inputs;
|
||||
--base-font-size: $base-font-size;
|
||||
--base-line-height: $base-line-height;
|
||||
--baseline: $baseline;
|
||||
--black: $black;
|
||||
--black-t2: $black-t2;
|
||||
--blue: $blue;
|
||||
--blue-d1: $blue-d1;
|
||||
--blue-d2: $blue-d2;
|
||||
--blue-d4: $blue-d4;
|
||||
--body-color: $body-color;
|
||||
--border-color: $border-color;
|
||||
--bp-screen-lg: $bp-screen-lg;
|
||||
--btn-brand-focus-background: $btn-brand-focus-background;
|
||||
--correct: $correct;
|
||||
--danger: $danger;
|
||||
--darkGrey: $darkGrey;
|
||||
--error-color: $error-color;
|
||||
--font-bold: $font-bold;
|
||||
--font-family-sans-serif: $font-family-sans-serif;
|
||||
--general-color-accent: $general-color-accent;
|
||||
--gray: $gray;
|
||||
--gray-300: $gray-300;
|
||||
--gray-d1: $gray-d1;
|
||||
--gray-l2: $gray-l2;
|
||||
--gray-l3: $gray-l3;
|
||||
--gray-l4: $gray-l4;
|
||||
--gray-l6: $gray-l6;
|
||||
--incorrect: $incorrect;
|
||||
--lightGrey: $lightGrey;
|
||||
--lighter-base-font-color: $lighter-base-font-color;
|
||||
--link-color: $link-color;
|
||||
--medium-font-size: $medium-font-size;
|
||||
--partially-correct: $partially-correct;
|
||||
--primary: $primary;
|
||||
--shadow: $shadow;
|
||||
--shadow-l1: $shadow-l1;
|
||||
--sidebar-color: $sidebar-color;
|
||||
--small-font-size: $small-font-size;
|
||||
--static-path: $static-path;
|
||||
--submitted: $submitted;
|
||||
--success: $success;
|
||||
--tmg-f2: $tmg-f2;
|
||||
--tmg-s2: $tmg-s2;
|
||||
--transparent: $transparent;
|
||||
--uxpl-gray-background: $uxpl-gray-background;
|
||||
--uxpl-gray-base: $uxpl-gray-base;
|
||||
--uxpl-gray-dark: $uxpl-gray-dark;
|
||||
--very-light-text: $very-light-text;
|
||||
--warning: $warning;
|
||||
--warning-color: $warning-color;
|
||||
--warning-color-accent: $warning-color-accent;
|
||||
--white: $white;
|
||||
--yellow: $yellow;
|
||||
}
|
||||
@@ -7,3 +7,7 @@ class BulkEmailConfig(AppConfig):
|
||||
Application Configuration for bulk_email.
|
||||
"""
|
||||
name = 'lms.djangoapps.bulk_email'
|
||||
|
||||
def ready(self):
|
||||
import lms.djangoapps.bulk_email.signals # lint-amnesty, pylint: disable=unused-import
|
||||
from edx_ace.signals import ACE_MESSAGE_SENT # lint-amnesty, pylint: disable=unused-import
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
"""
|
||||
Signal handlers for the bulk_email app
|
||||
"""
|
||||
|
||||
|
||||
from django.contrib.auth import get_user_model
|
||||
from django.dispatch import receiver
|
||||
from eventtracking import tracker
|
||||
|
||||
from common.djangoapps.student.models import CourseEnrollment
|
||||
from openedx.core.djangoapps.user_api.accounts.signals import USER_RETIRE_MAILINGS
|
||||
from edx_ace.signals import ACE_MESSAGE_SENT
|
||||
|
||||
from .models import Optout
|
||||
|
||||
@@ -24,3 +25,28 @@ def force_optout_all(sender, **kwargs): # lint-amnesty, pylint: disable=unused-
|
||||
|
||||
for enrollment in CourseEnrollment.objects.filter(user=user):
|
||||
Optout.objects.get_or_create(user=user, course_id=enrollment.course.id)
|
||||
|
||||
|
||||
@receiver(ACE_MESSAGE_SENT)
|
||||
def ace_email_sent_handler(sender, **kwargs):
|
||||
"""
|
||||
When an email is sent using ACE, this method will create an event to detect ace email success status
|
||||
"""
|
||||
# Fetch the message object from kwargs, defaulting to None if not present
|
||||
message = kwargs.get('message', None)
|
||||
|
||||
user_model = get_user_model()
|
||||
try:
|
||||
user_id = user_model.objects.get(email=message.recipient.email_address).id
|
||||
except user_model.DoesNotExist:
|
||||
user_id = None
|
||||
course_email = message.context.get('course_email', None)
|
||||
course_id = course_email.course_id if course_email else None
|
||||
tracker.emit(
|
||||
'edx.bulk_email.sent',
|
||||
{
|
||||
'message_type': message.name,
|
||||
'course_id': course_id,
|
||||
'user_id': user_id,
|
||||
}
|
||||
)
|
||||
|
||||
@@ -26,6 +26,7 @@ from django.utils import timezone
|
||||
from django.utils.translation import gettext as _
|
||||
from django.utils.translation import override as override_language
|
||||
from edx_django_utils.monitoring import set_code_owner_attribute
|
||||
from eventtracking import tracker
|
||||
from markupsafe import escape
|
||||
|
||||
from common.djangoapps.util.date_utils import get_default_time_display
|
||||
@@ -467,7 +468,14 @@ def _send_course_email(entry_id, email_id, to_list, global_email_context, subtas
|
||||
"send."
|
||||
)
|
||||
raise exc
|
||||
|
||||
tracker.emit(
|
||||
'edx.bulk_email.created',
|
||||
{
|
||||
'course_id': str(course_email.course_id),
|
||||
'to_list': to_list,
|
||||
'total_recipients': total_recipients,
|
||||
}
|
||||
)
|
||||
# Exclude optouts (if not a retry):
|
||||
# Note that we don't have to do the optout logic at all if this is a retry,
|
||||
# because we have presumably already performed the optout logic on the first
|
||||
|
||||
@@ -7,6 +7,7 @@ import logging
|
||||
|
||||
from django.contrib.auth.models import User # lint-amnesty, pylint: disable=imported-auth-user
|
||||
from django.http import Http404
|
||||
from eventtracking import tracker
|
||||
from opaque_keys import InvalidKeyError
|
||||
from opaque_keys.edx.keys import CourseKey
|
||||
|
||||
@@ -60,4 +61,12 @@ def opt_out_email_updates(request, token, course_id):
|
||||
course_id,
|
||||
)
|
||||
|
||||
tracker.emit(
|
||||
'edx.bulk_email.opt_out',
|
||||
{
|
||||
'course_id': course_id,
|
||||
'user_id': user.id,
|
||||
}
|
||||
)
|
||||
|
||||
return render_to_response('bulk_email/unsubscribe_success.html', context)
|
||||
|
||||
@@ -1458,6 +1458,8 @@ class CreateSubCommentUnicodeTestCase(
|
||||
@disable_signal(views, 'comment_created')
|
||||
@disable_signal(views, 'comment_voted')
|
||||
@disable_signal(views, 'comment_deleted')
|
||||
@disable_signal(views, 'comment_flagged')
|
||||
@disable_signal(views, 'thread_flagged')
|
||||
class TeamsPermissionsTestCase(ForumsEnableMixin, UrlResetMixin, SharedModuleStoreTestCase, MockRequestSetupMixin):
|
||||
# Most of the test points use the same ddt data.
|
||||
# args: user, commentable_id, status_code
|
||||
|
||||
@@ -118,9 +118,10 @@ class DiscussionNotificationSender:
|
||||
self.parent_response and
|
||||
self.creator.id != int(self.thread.user_id)
|
||||
):
|
||||
author_name = f"{self.parent_response.username}'s"
|
||||
# use your if author of response is same as author of post.
|
||||
# use 'their' if comment author is also response author.
|
||||
author_name = (
|
||||
author_pronoun = (
|
||||
# Translators: Replier commented on "your" response to your post
|
||||
_("your")
|
||||
if self._response_and_thread_has_same_creator()
|
||||
@@ -129,10 +130,12 @@ class DiscussionNotificationSender:
|
||||
_("their")
|
||||
if self._response_and_comment_has_same_creator()
|
||||
else f"{self.parent_response.username}'s"
|
||||
|
||||
)
|
||||
)
|
||||
context = {
|
||||
"author_name": str(author_name),
|
||||
"author_pronoun": str(author_pronoun),
|
||||
}
|
||||
self._send_notification([self.thread.user_id], "new_comment", extra_context=context)
|
||||
|
||||
@@ -189,10 +192,21 @@ class DiscussionNotificationSender:
|
||||
if not self.parent_id:
|
||||
self._send_notification(users, "response_on_followed_post")
|
||||
else:
|
||||
author_name = f"{self.parent_response.username}'s"
|
||||
# use 'their' if comment author is also response author.
|
||||
author_pronoun = (
|
||||
# Translators: Replier commented on "their" response in a post you're following
|
||||
_("their")
|
||||
if self._response_and_comment_has_same_creator()
|
||||
else f"{self.parent_response.username}'s"
|
||||
)
|
||||
self._send_notification(
|
||||
users,
|
||||
"comment_on_followed_post",
|
||||
extra_context={"author_name": self.parent_response.username}
|
||||
extra_context={
|
||||
"author_name": str(author_name),
|
||||
"author_pronoun": str(author_pronoun),
|
||||
}
|
||||
)
|
||||
|
||||
def _create_cohort_course_audience(self):
|
||||
@@ -300,7 +314,7 @@ class DiscussionNotificationSender:
|
||||
content_type = thread_types[self.thread.type][getattr(self.thread, 'depth', 0)]
|
||||
|
||||
context = {
|
||||
'username': self.creator.username,
|
||||
'username': self.thread.username,
|
||||
'content_type': content_type,
|
||||
'content': thread_body
|
||||
}
|
||||
|
||||
@@ -44,7 +44,7 @@ class TestDiscussionNotificationSender(unittest.TestCase):
|
||||
|
||||
self.assertEqual(notification_type, "content_reported")
|
||||
self.assertEqual(context, {
|
||||
'username': 'test_user',
|
||||
'username': self.thread.username,
|
||||
'content_type': expected_content_type,
|
||||
'content': 'Thread body'
|
||||
})
|
||||
|
||||
@@ -338,6 +338,7 @@ class TestSendResponseNotifications(DiscussionAPIViewTestMixin, ModuleStoreTestC
|
||||
'replier_name': self.user_3.username,
|
||||
'post_title': self.thread.title,
|
||||
'author_name': 'dummy\'s',
|
||||
'author_pronoun': 'dummy\'s',
|
||||
'course_name': self.course.display_name,
|
||||
'sender_id': self.user_3.id
|
||||
}
|
||||
@@ -399,7 +400,8 @@ class TestSendResponseNotifications(DiscussionAPIViewTestMixin, ModuleStoreTestC
|
||||
expected_context = {
|
||||
'replier_name': self.user_3.username,
|
||||
'post_title': self.thread.title,
|
||||
'author_name': 'your',
|
||||
'author_name': 'dummy\'s',
|
||||
'author_pronoun': 'your',
|
||||
'course_name': self.course.display_name,
|
||||
'sender_id': self.user_3.id,
|
||||
}
|
||||
@@ -441,7 +443,8 @@ class TestSendResponseNotifications(DiscussionAPIViewTestMixin, ModuleStoreTestC
|
||||
'sender_id': self.user_2.id,
|
||||
}
|
||||
if parent_id:
|
||||
expected_context['author_name'] = 'dummy'
|
||||
expected_context['author_name'] = 'dummy\'s'
|
||||
expected_context['author_pronoun'] = 'dummy\'s'
|
||||
self.assertDictEqual(args.context, expected_context)
|
||||
self.assertEqual(
|
||||
args.content_url,
|
||||
@@ -531,7 +534,8 @@ class TestSendCommentNotification(DiscussionAPIViewTestMixin, ModuleStoreTestCas
|
||||
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')
|
||||
self.assertEqual(context['author_name'], 'dummy\'s')
|
||||
self.assertEqual(context['author_pronoun'], 'their')
|
||||
|
||||
|
||||
@override_waffle_flag(ENABLE_NOTIFICATIONS, active=True)
|
||||
|
||||
@@ -7,6 +7,7 @@ import logging
|
||||
from datetime import timedelta
|
||||
|
||||
from django.utils import timezone
|
||||
from django.conf import settings
|
||||
|
||||
from openedx.core.djangoapps.content.course_overviews.models import CourseOverview
|
||||
|
||||
@@ -22,7 +23,7 @@ def are_grades_frozen(course_key):
|
||||
if ENFORCE_FREEZE_GRADE_AFTER_COURSE_END.is_enabled(course_key):
|
||||
course = CourseOverview.get_from_id(course_key)
|
||||
if course.end:
|
||||
freeze_grade_date = course.end + timedelta(30)
|
||||
freeze_grade_date = course.end + timedelta(settings.GRADEBOOK_FREEZE_DAYS)
|
||||
now = timezone.now()
|
||||
return now > freeze_grade_date
|
||||
return False
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
"""
|
||||
Permissions for the instructor dashboard and associated actions
|
||||
"""
|
||||
|
||||
from bridgekeeper import perms
|
||||
from bridgekeeper.rules import is_staff
|
||||
from opaque_keys.edx.keys import CourseKey
|
||||
from rest_framework.permissions import BasePermission
|
||||
|
||||
from lms.djangoapps.courseware.rules import HasAccessRule, HasRolesRule
|
||||
from openedx.core.lib.courses import get_course_by_id
|
||||
|
||||
ALLOW_STUDENT_TO_BYPASS_ENTRANCE_EXAM = 'instructor.allow_student_to_bypass_entrance_exam'
|
||||
ASSIGN_TO_COHORTS = 'instructor.assign_to_cohorts'
|
||||
@@ -72,3 +74,11 @@ perms[VIEW_DASHBOARD] = \
|
||||
) | HasAccessRule('staff') | HasAccessRule('instructor')
|
||||
perms[VIEW_ENROLLMENTS] = HasAccessRule('staff')
|
||||
perms[VIEW_FORUM_MEMBERS] = HasAccessRule('staff')
|
||||
|
||||
|
||||
class InstructorPermission(BasePermission):
|
||||
"""Generic permissions"""
|
||||
def has_permission(self, request, view):
|
||||
course = get_course_by_id(CourseKey.from_string(view.kwargs.get('course_id')))
|
||||
permission = getattr(view, 'permission_name', None)
|
||||
return request.user.has_perm(permission, course)
|
||||
|
||||
@@ -642,6 +642,25 @@ class TestInstructorAPIBulkAccountCreationAndEnrollment(SharedModuleStoreTestCas
|
||||
last_name='Student'
|
||||
)
|
||||
|
||||
def test_api_without_login(self):
|
||||
"""
|
||||
verify in case of no authentication it returns 401.
|
||||
"""
|
||||
self.client.logout()
|
||||
uploaded_file = SimpleUploadedFile("temp.jpg", io.BytesIO(b"some initial binary data: \x00\x01").read())
|
||||
response = self.client.post(self.url, {'students_list': uploaded_file})
|
||||
assert response.status_code == 401
|
||||
|
||||
def test_api_without_permission(self):
|
||||
"""
|
||||
verify in case of no authentication it returns 403.
|
||||
"""
|
||||
# removed role from course for instructor
|
||||
CourseInstructorRole(self.course.id).remove_users(self.instructor)
|
||||
uploaded_file = SimpleUploadedFile("temp.jpg", io.BytesIO(b"some initial binary data: \x00\x01").read())
|
||||
response = self.client.post(self.url, {'students_list': uploaded_file})
|
||||
assert response.status_code == 403
|
||||
|
||||
@patch('lms.djangoapps.instructor.views.api.log.info')
|
||||
@ddt.data(
|
||||
b"test_student@example.com,test_student_1,tester1,USA", # Typical use case.
|
||||
@@ -2945,7 +2964,37 @@ class TestInstructorAPILevelsDataDump(SharedModuleStoreTestCase, LoginEnrollment
|
||||
response = self.client.post(url, data)
|
||||
assert response.status_code == 200
|
||||
res_json = json.loads(response.content.decode('utf-8'))
|
||||
assert 'progress_url' in res_json
|
||||
expected_data = {
|
||||
'course_id': str(self.course.id),
|
||||
'progress_url': f'/courses/{self.course.id}/progress/{self.students[0].id}/'
|
||||
}
|
||||
|
||||
for key, value in expected_data.items():
|
||||
self.assertIn(key, res_json)
|
||||
self.assertEqual(res_json[key], value)
|
||||
|
||||
def test_get_student_progress_url_response_headers(self):
|
||||
"""
|
||||
Test that the progress_url endpoint returns the correct headers.
|
||||
"""
|
||||
url = reverse('get_student_progress_url', kwargs={'course_id': str(self.course.id)})
|
||||
data = {'unique_student_identifier': self.students[0].email}
|
||||
response = self.client.post(url, data)
|
||||
assert response.status_code == 200
|
||||
|
||||
expected_headers = {
|
||||
'Allow': 'POST, OPTIONS', # drf view brings this key.
|
||||
'Cache-Control': 'no-cache, no-store, must-revalidate',
|
||||
'Content-Language': 'en',
|
||||
'Content-Length': str(len(response.content.decode('utf-8'))),
|
||||
'Content-Type': 'application/json',
|
||||
'Vary': 'Cookie, Accept-Language, origin',
|
||||
'X-Frame-Options': 'DENY'
|
||||
}
|
||||
|
||||
for key, value in expected_headers.items():
|
||||
self.assertIn(key, response.headers)
|
||||
self.assertEqual(response.headers[key], value)
|
||||
|
||||
def test_get_student_progress_url_from_uname(self):
|
||||
""" Test that progress_url is in the successful response. """
|
||||
@@ -2955,6 +3004,14 @@ class TestInstructorAPILevelsDataDump(SharedModuleStoreTestCase, LoginEnrollment
|
||||
assert response.status_code == 200
|
||||
res_json = json.loads(response.content.decode('utf-8'))
|
||||
assert 'progress_url' in res_json
|
||||
expected_data = {
|
||||
'course_id': str(self.course.id),
|
||||
'progress_url': f'/courses/{self.course.id}/progress/{self.students[0].id}/'
|
||||
}
|
||||
|
||||
for key, value in expected_data.items():
|
||||
self.assertIn(key, res_json)
|
||||
self.assertEqual(res_json[key], value)
|
||||
|
||||
def test_get_student_progress_url_noparams(self):
|
||||
""" Test that the endpoint 404's without the required query params. """
|
||||
@@ -2968,6 +3025,17 @@ class TestInstructorAPILevelsDataDump(SharedModuleStoreTestCase, LoginEnrollment
|
||||
response = self.client.post(url)
|
||||
assert response.status_code == 400
|
||||
|
||||
def test_get_student_progress_url_without_permissions(self):
|
||||
""" Test that progress_url returns 403 without credentials. """
|
||||
|
||||
# removed both roles from courses for instructor
|
||||
CourseDataResearcherRole(self.course.id).remove_users(self.instructor)
|
||||
CourseInstructorRole(self.course.id).remove_users(self.instructor)
|
||||
url = reverse('get_student_progress_url', kwargs={'course_id': str(self.course.id)})
|
||||
data = {'unique_student_identifier': self.students[0].email}
|
||||
response = self.client.post(url, data)
|
||||
assert response.status_code == 403
|
||||
|
||||
|
||||
class TestInstructorAPIRegradeTask(SharedModuleStoreTestCase, LoginEnrollmentTestCase):
|
||||
"""
|
||||
|
||||
@@ -105,6 +105,7 @@ from lms.djangoapps.instructor_task import api as task_api
|
||||
from lms.djangoapps.instructor_task.api_helper import AlreadyRunningError, QueueConnectionError
|
||||
from lms.djangoapps.instructor_task.data import InstructorTaskTypes
|
||||
from lms.djangoapps.instructor_task.models import ReportStore
|
||||
from lms.djangoapps.instructor.views.serializer import RoleNameSerializer, UserSerializer, AccessSerializer
|
||||
from openedx.core.djangoapps.content.course_overviews.models import CourseOverview
|
||||
from openedx.core.djangoapps.course_groups.cohorts import add_user_to_cohort, is_course_cohorted
|
||||
from openedx.core.djangoapps.course_groups.models import CourseUserGroup
|
||||
@@ -122,6 +123,7 @@ from openedx.core.djangolib.markup import HTML, Text
|
||||
from openedx.core.lib.api.authentication import BearerAuthenticationAllowInactiveUser
|
||||
from openedx.core.lib.api.view_utils import DeveloperErrorViewMixin, view_auth_classes
|
||||
from openedx.core.lib.courses import get_course_by_id
|
||||
from openedx.core.lib.api.serializers import CourseKeyField
|
||||
from openedx.features.course_experience.url_helpers import get_learning_mfe_home_url
|
||||
from .tools import (
|
||||
dump_block_extensions,
|
||||
@@ -281,299 +283,305 @@ def require_finance_admin(func):
|
||||
return wrapped
|
||||
|
||||
|
||||
@require_POST
|
||||
@ensure_csrf_cookie
|
||||
@cache_control(no_cache=True, no_store=True, must_revalidate=True)
|
||||
@require_course_permission(permissions.CAN_ENROLL)
|
||||
def register_and_enroll_students(request, course_id): # pylint: disable=too-many-statements
|
||||
@method_decorator(cache_control(no_cache=True, no_store=True, must_revalidate=True), name='dispatch')
|
||||
class RegisterAndEnrollStudents(APIView):
|
||||
"""
|
||||
Create new account and Enroll students in this course.
|
||||
Passing a csv file that contains a list of students.
|
||||
Order in csv should be the following email = 0; username = 1; name = 2; country = 3.
|
||||
If there are more than 4 columns in the csv: cohort = 4, course mode = 5.
|
||||
Requires staff access.
|
||||
|
||||
-If the email address and username already exists and the user is enrolled in the course,
|
||||
do nothing (including no email gets sent out)
|
||||
|
||||
-If the email address already exists, but the username is different,
|
||||
match on the email address only and continue to enroll the user in the course using the email address
|
||||
as the matching criteria. Note the change of username as a warning message (but not a failure).
|
||||
Send a standard enrollment email which is the same as the existing manual enrollment
|
||||
|
||||
-If the username already exists (but not the email), assume it is a different user and fail
|
||||
to create the new account.
|
||||
The failure will be messaged in a response in the browser.
|
||||
"""
|
||||
permission_classes = (IsAuthenticated, permissions.InstructorPermission)
|
||||
permission_name = permissions.CAN_ENROLL
|
||||
|
||||
if not configuration_helpers.get_value(
|
||||
'ALLOW_AUTOMATED_SIGNUPS',
|
||||
settings.FEATURES.get('ALLOW_AUTOMATED_SIGNUPS', False),
|
||||
):
|
||||
return HttpResponseForbidden()
|
||||
@method_decorator(ensure_csrf_cookie)
|
||||
def post(self, request, course_id): # pylint: disable=too-many-statements
|
||||
"""
|
||||
Create new account and Enroll students in this course.
|
||||
Passing a csv file that contains a list of students.
|
||||
Order in csv should be the following email = 0; username = 1; name = 2; country = 3.
|
||||
If there are more than 4 columns in the csv: cohort = 4, course mode = 5.
|
||||
Requires staff access.
|
||||
|
||||
course_id = CourseKey.from_string(course_id)
|
||||
warnings = []
|
||||
row_errors = []
|
||||
general_errors = []
|
||||
-If the email address and username already exists and the user is enrolled in the course,
|
||||
do nothing (including no email gets sent out)
|
||||
|
||||
# email-students is a checkbox input type; will be present in POST if checked, absent otherwise
|
||||
notify_by_email = 'email-students' in request.POST
|
||||
-If the email address already exists, but the username is different,
|
||||
match on the email address only and continue to enroll the user in the course using the email address
|
||||
as the matching criteria. Note the change of username as a warning message (but not a failure).
|
||||
Send a standard enrollment email which is the same as the existing manual enrollment
|
||||
|
||||
# for white labels we use 'shopping cart' which uses CourseMode.HONOR as
|
||||
# course mode for creating course enrollments.
|
||||
if CourseMode.is_white_label(course_id):
|
||||
default_course_mode = CourseMode.HONOR
|
||||
else:
|
||||
default_course_mode = None
|
||||
-If the username already exists (but not the email), assume it is a different user and fail
|
||||
to create the new account.
|
||||
The failure will be messaged in a response in the browser.
|
||||
"""
|
||||
if not configuration_helpers.get_value(
|
||||
'ALLOW_AUTOMATED_SIGNUPS',
|
||||
settings.FEATURES.get('ALLOW_AUTOMATED_SIGNUPS', False),
|
||||
):
|
||||
return HttpResponseForbidden()
|
||||
|
||||
# Allow bulk enrollments in all non-expired course modes including "credit" (which is non-selectable)
|
||||
valid_course_modes = set(map(lambda x: x.slug, CourseMode.modes_for_course(
|
||||
course_id=course_id,
|
||||
only_selectable=False,
|
||||
include_expired=False,
|
||||
)))
|
||||
course_id = CourseKey.from_string(course_id)
|
||||
warnings = []
|
||||
row_errors = []
|
||||
general_errors = []
|
||||
|
||||
if 'students_list' in request.FILES: # lint-amnesty, pylint: disable=too-many-nested-blocks
|
||||
students = []
|
||||
# email-students is a checkbox input type; will be present in POST if checked, absent otherwise
|
||||
notify_by_email = 'email-students' in request.POST
|
||||
|
||||
try:
|
||||
upload_file = request.FILES.get('students_list')
|
||||
if upload_file.name.endswith('.csv'):
|
||||
students = list(csv.reader(upload_file.read().decode('utf-8-sig').splitlines()))
|
||||
course = get_course_by_id(course_id)
|
||||
else:
|
||||
general_errors.append({
|
||||
'username': '', 'email': '',
|
||||
'response': _(
|
||||
'Make sure that the file you upload is in CSV format with no extraneous characters or rows.')
|
||||
})
|
||||
# for white labels we use 'shopping cart' which uses CourseMode.HONOR as
|
||||
# course mode for creating course enrollments.
|
||||
if CourseMode.is_white_label(course_id):
|
||||
default_course_mode = CourseMode.HONOR
|
||||
else:
|
||||
default_course_mode = None
|
||||
|
||||
except Exception: # pylint: disable=broad-except
|
||||
general_errors.append({
|
||||
'username': '', 'email': '', 'response': _('Could not read uploaded file.')
|
||||
})
|
||||
finally:
|
||||
upload_file.close()
|
||||
# Allow bulk enrollments in all non-expired course modes including "credit" (which is non-selectable)
|
||||
valid_course_modes = set(map(lambda x: x.slug, CourseMode.modes_for_course(
|
||||
course_id=course_id,
|
||||
only_selectable=False,
|
||||
include_expired=False,
|
||||
)))
|
||||
|
||||
generated_passwords = []
|
||||
# To skip fetching cohorts from the DB while iterating on students,
|
||||
# {<cohort name>: CourseUserGroup}
|
||||
cohorts_cache = {}
|
||||
already_warned_not_cohorted = False
|
||||
extra_fields_is_enabled = configuration_helpers.get_value(
|
||||
'ENABLE_AUTOMATED_SIGNUPS_EXTRA_FIELDS',
|
||||
settings.FEATURES.get('ENABLE_AUTOMATED_SIGNUPS_EXTRA_FIELDS', False),
|
||||
)
|
||||
if 'students_list' in request.FILES: # lint-amnesty, pylint: disable=too-many-nested-blocks
|
||||
students = []
|
||||
|
||||
# Iterate each student in the uploaded csv file.
|
||||
for row_num, student in enumerate(students, 1):
|
||||
|
||||
# Verify that we have the expected number of columns in every row
|
||||
# but allow for blank lines.
|
||||
if not student:
|
||||
continue
|
||||
|
||||
if extra_fields_is_enabled:
|
||||
is_valid_csv = 4 <= len(student) <= 6
|
||||
error = _('Data in row #{row_num} must have between four and six columns: '
|
||||
'email, username, full name, country, cohort, and course mode. '
|
||||
'The last two columns are optional.').format(row_num=row_num)
|
||||
else:
|
||||
is_valid_csv = len(student) == 4
|
||||
error = _('Data in row #{row_num} must have exactly four columns: '
|
||||
'email, username, full name, and country.').format(row_num=row_num)
|
||||
|
||||
if not is_valid_csv:
|
||||
general_errors.append({
|
||||
'username': '',
|
||||
'email': '',
|
||||
'response': error
|
||||
})
|
||||
continue
|
||||
|
||||
# Extract each column, handle optional columns if they exist.
|
||||
email, username, name, country, *optional_cols = student
|
||||
if optional_cols:
|
||||
optional_cols.append(default_course_mode)
|
||||
cohort_name, course_mode, *_tail = optional_cols
|
||||
else:
|
||||
cohort_name = None
|
||||
course_mode = None
|
||||
|
||||
# Validate cohort name, and get the cohort object. Skip if course
|
||||
# is not cohorted.
|
||||
cohort = None
|
||||
|
||||
if cohort_name and not already_warned_not_cohorted:
|
||||
if not is_course_cohorted(course_id):
|
||||
row_errors.append({
|
||||
'username': username,
|
||||
'email': email,
|
||||
'response': _('Course is not cohorted but cohort provided. '
|
||||
'Ignoring cohort assignment for all users.')
|
||||
})
|
||||
already_warned_not_cohorted = True
|
||||
elif cohort_name in cohorts_cache:
|
||||
cohort = cohorts_cache[cohort_name]
|
||||
try:
|
||||
upload_file = request.FILES.get('students_list')
|
||||
if upload_file.name.endswith('.csv'):
|
||||
students = list(csv.reader(upload_file.read().decode('utf-8-sig').splitlines()))
|
||||
course = get_course_by_id(course_id)
|
||||
else:
|
||||
# Don't attempt to create cohort or assign student if cohort
|
||||
# does not exist.
|
||||
try:
|
||||
cohort = get_cohort_by_name(course_id, cohort_name)
|
||||
except CourseUserGroup.DoesNotExist:
|
||||
general_errors.append({
|
||||
'username': '', 'email': '',
|
||||
'response': _(
|
||||
'Make sure that the file you upload is in CSV format with no '
|
||||
'extraneous characters or rows.')
|
||||
})
|
||||
|
||||
except Exception: # pylint: disable=broad-except
|
||||
general_errors.append({
|
||||
'username': '', 'email': '', 'response': _('Could not read uploaded file.')
|
||||
})
|
||||
finally:
|
||||
upload_file.close()
|
||||
|
||||
generated_passwords = []
|
||||
# To skip fetching cohorts from the DB while iterating on students,
|
||||
# {<cohort name>: CourseUserGroup}
|
||||
cohorts_cache = {}
|
||||
already_warned_not_cohorted = False
|
||||
extra_fields_is_enabled = configuration_helpers.get_value(
|
||||
'ENABLE_AUTOMATED_SIGNUPS_EXTRA_FIELDS',
|
||||
settings.FEATURES.get('ENABLE_AUTOMATED_SIGNUPS_EXTRA_FIELDS', False),
|
||||
)
|
||||
|
||||
# Iterate each student in the uploaded csv file.
|
||||
for row_num, student in enumerate(students, 1):
|
||||
|
||||
# Verify that we have the expected number of columns in every row
|
||||
# but allow for blank lines.
|
||||
if not student:
|
||||
continue
|
||||
|
||||
if extra_fields_is_enabled:
|
||||
is_valid_csv = 4 <= len(student) <= 6
|
||||
error = _('Data in row #{row_num} must have between four and six columns: '
|
||||
'email, username, full name, country, cohort, and course mode. '
|
||||
'The last two columns are optional.').format(row_num=row_num)
|
||||
else:
|
||||
is_valid_csv = len(student) == 4
|
||||
error = _('Data in row #{row_num} must have exactly four columns: '
|
||||
'email, username, full name, and country.').format(row_num=row_num)
|
||||
|
||||
if not is_valid_csv:
|
||||
general_errors.append({
|
||||
'username': '',
|
||||
'email': '',
|
||||
'response': error
|
||||
})
|
||||
continue
|
||||
|
||||
# Extract each column, handle optional columns if they exist.
|
||||
email, username, name, country, *optional_cols = student
|
||||
if optional_cols:
|
||||
optional_cols.append(default_course_mode)
|
||||
cohort_name, course_mode, *_tail = optional_cols
|
||||
else:
|
||||
cohort_name = None
|
||||
course_mode = None
|
||||
|
||||
# Validate cohort name, and get the cohort object. Skip if course
|
||||
# is not cohorted.
|
||||
cohort = None
|
||||
|
||||
if cohort_name and not already_warned_not_cohorted:
|
||||
if not is_course_cohorted(course_id):
|
||||
row_errors.append({
|
||||
'username': username,
|
||||
'email': email,
|
||||
'response': _('Cohort name not found: {cohort}. '
|
||||
'Ignoring cohort assignment for '
|
||||
'all users.').format(cohort=cohort_name)
|
||||
'response': _('Course is not cohorted but cohort provided. '
|
||||
'Ignoring cohort assignment for all users.')
|
||||
})
|
||||
cohorts_cache[cohort_name] = cohort
|
||||
|
||||
# Validate course mode.
|
||||
if not course_mode:
|
||||
course_mode = default_course_mode
|
||||
|
||||
if (course_mode is not None
|
||||
and course_mode not in valid_course_modes):
|
||||
# If `default is None` and the user is already enrolled,
|
||||
# `CourseEnrollment.change_mode()` will not update the mode,
|
||||
# hence two error messages.
|
||||
if default_course_mode is None:
|
||||
err_msg = _(
|
||||
'Invalid course mode: {mode}. Falling back to the '
|
||||
'default mode, or keeping the current mode in case the '
|
||||
'user is already enrolled.'
|
||||
).format(mode=course_mode)
|
||||
else:
|
||||
err_msg = _(
|
||||
'Invalid course mode: {mode}. Failling back to '
|
||||
'{default_mode}, or resetting to {default_mode} in case '
|
||||
'the user is already enrolled.'
|
||||
).format(mode=course_mode, default_mode=default_course_mode)
|
||||
row_errors.append({
|
||||
'username': username,
|
||||
'email': email,
|
||||
'response': err_msg,
|
||||
})
|
||||
course_mode = default_course_mode
|
||||
|
||||
email_params = get_email_params(course, True, secure=request.is_secure())
|
||||
try:
|
||||
validate_email(email) # Raises ValidationError if invalid
|
||||
except ValidationError:
|
||||
row_errors.append({
|
||||
'username': username,
|
||||
'email': email,
|
||||
'response': _('Invalid email {email_address}.').format(email_address=email)
|
||||
})
|
||||
else:
|
||||
if User.objects.filter(email=email).exists():
|
||||
# Email address already exists. assume it is the correct user
|
||||
# and just register the user in the course and send an enrollment email.
|
||||
user = User.objects.get(email=email)
|
||||
|
||||
# see if it is an exact match with email and username
|
||||
# if it's not an exact match then just display a warning message, but continue onwards
|
||||
if not User.objects.filter(email=email, username=username).exists():
|
||||
warning_message = _(
|
||||
'An account with email {email} exists but the provided username {username} '
|
||||
'is different. Enrolling anyway with {email}.'
|
||||
).format(email=email, username=username)
|
||||
|
||||
warnings.append({
|
||||
'username': username, 'email': email, 'response': warning_message
|
||||
})
|
||||
log.warning('email %s already exist', email)
|
||||
already_warned_not_cohorted = True
|
||||
elif cohort_name in cohorts_cache:
|
||||
cohort = cohorts_cache[cohort_name]
|
||||
else:
|
||||
log.info(
|
||||
"user already exists with username '%s' and email '%s'",
|
||||
username,
|
||||
email
|
||||
)
|
||||
|
||||
# enroll a user if it is not already enrolled.
|
||||
if not is_user_enrolled_in_course(user, course_id):
|
||||
# Enroll user to the course and add manual enrollment audit trail
|
||||
create_manual_course_enrollment(
|
||||
user=user,
|
||||
course_id=course_id,
|
||||
mode=course_mode,
|
||||
enrolled_by=request.user,
|
||||
reason='Enrolling via csv upload',
|
||||
state_transition=UNENROLLED_TO_ENROLLED,
|
||||
)
|
||||
enroll_email(course_id=course_id,
|
||||
student_email=email,
|
||||
auto_enroll=True,
|
||||
email_students=notify_by_email,
|
||||
email_params=email_params)
|
||||
else:
|
||||
# update the course mode if already enrolled
|
||||
existing_enrollment = CourseEnrollment.get_enrollment(user, course_id)
|
||||
if existing_enrollment.mode != course_mode:
|
||||
existing_enrollment.change_mode(mode=course_mode)
|
||||
if cohort:
|
||||
# Don't attempt to create cohort or assign student if cohort
|
||||
# does not exist.
|
||||
try:
|
||||
add_user_to_cohort(cohort, user)
|
||||
except ValueError:
|
||||
# user already in this cohort; ignore
|
||||
pass
|
||||
elif is_email_retired(email):
|
||||
# We are either attempting to enroll a retired user or create a new user with an email which is
|
||||
# already associated with a retired account. Simply block these attempts.
|
||||
row_errors.append({
|
||||
'username': username,
|
||||
'email': email,
|
||||
'response': _('Invalid email {email_address}.').format(email_address=email),
|
||||
})
|
||||
log.warning('Email address %s is associated with a retired user, so course enrollment was ' + # lint-amnesty, pylint: disable=logging-not-lazy
|
||||
'blocked.', email)
|
||||
else:
|
||||
# This email does not yet exist, so we need to create a new account
|
||||
# If username already exists in the database, then create_and_enroll_user
|
||||
# will raise an IntegrityError exception.
|
||||
password = generate_unique_password(generated_passwords)
|
||||
errors = create_and_enroll_user(
|
||||
email,
|
||||
username,
|
||||
name,
|
||||
country,
|
||||
password,
|
||||
course_id,
|
||||
course_mode,
|
||||
request.user,
|
||||
email_params,
|
||||
email_user=notify_by_email,
|
||||
)
|
||||
row_errors.extend(errors)
|
||||
if cohort:
|
||||
try:
|
||||
add_user_to_cohort(cohort, email)
|
||||
except ValueError:
|
||||
# user already in this cohort; ignore
|
||||
# NOTE: Checking this here may be unnecessary if we can prove that a new user will never be
|
||||
# automatically assigned to a cohort from the above.
|
||||
pass
|
||||
except ValidationError:
|
||||
cohort = get_cohort_by_name(course_id, cohort_name)
|
||||
except CourseUserGroup.DoesNotExist:
|
||||
row_errors.append({
|
||||
'username': username,
|
||||
'email': email,
|
||||
'response': _('Invalid email {email_address}.').format(email_address=email),
|
||||
'response': _('Cohort name not found: {cohort}. '
|
||||
'Ignoring cohort assignment for '
|
||||
'all users.').format(cohort=cohort_name)
|
||||
})
|
||||
cohorts_cache[cohort_name] = cohort
|
||||
|
||||
else:
|
||||
general_errors.append({
|
||||
'username': '', 'email': '', 'response': _('File is not attached.')
|
||||
})
|
||||
# Validate course mode.
|
||||
if not course_mode:
|
||||
course_mode = default_course_mode
|
||||
|
||||
results = {
|
||||
'row_errors': row_errors,
|
||||
'general_errors': general_errors,
|
||||
'warnings': warnings
|
||||
}
|
||||
return JsonResponse(results)
|
||||
if (course_mode is not None
|
||||
and course_mode not in valid_course_modes):
|
||||
# If `default is None` and the user is already enrolled,
|
||||
# `CourseEnrollment.change_mode()` will not update the mode,
|
||||
# hence two error messages.
|
||||
if default_course_mode is None:
|
||||
err_msg = _(
|
||||
'Invalid course mode: {mode}. Falling back to the '
|
||||
'default mode, or keeping the current mode in case the '
|
||||
'user is already enrolled.'
|
||||
).format(mode=course_mode)
|
||||
else:
|
||||
err_msg = _(
|
||||
'Invalid course mode: {mode}. Failling back to '
|
||||
'{default_mode}, or resetting to {default_mode} in case '
|
||||
'the user is already enrolled.'
|
||||
).format(mode=course_mode, default_mode=default_course_mode)
|
||||
row_errors.append({
|
||||
'username': username,
|
||||
'email': email,
|
||||
'response': err_msg,
|
||||
})
|
||||
course_mode = default_course_mode
|
||||
|
||||
email_params = get_email_params(course, True, secure=request.is_secure())
|
||||
try:
|
||||
validate_email(email) # Raises ValidationError if invalid
|
||||
except ValidationError:
|
||||
row_errors.append({
|
||||
'username': username,
|
||||
'email': email,
|
||||
'response': _('Invalid email {email_address}.').format(email_address=email)
|
||||
})
|
||||
else:
|
||||
if User.objects.filter(email=email).exists():
|
||||
# Email address already exists. assume it is the correct user
|
||||
# and just register the user in the course and send an enrollment email.
|
||||
user = User.objects.get(email=email)
|
||||
|
||||
# see if it is an exact match with email and username
|
||||
# if it's not an exact match then just display a warning message, but continue onwards
|
||||
if not User.objects.filter(email=email, username=username).exists():
|
||||
warning_message = _(
|
||||
'An account with email {email} exists but the provided username {username} '
|
||||
'is different. Enrolling anyway with {email}.'
|
||||
).format(email=email, username=username)
|
||||
|
||||
warnings.append({
|
||||
'username': username, 'email': email, 'response': warning_message
|
||||
})
|
||||
log.warning('email %s already exist', email)
|
||||
else:
|
||||
log.info(
|
||||
"user already exists with username '%s' and email '%s'",
|
||||
username,
|
||||
email
|
||||
)
|
||||
|
||||
# enroll a user if it is not already enrolled.
|
||||
if not is_user_enrolled_in_course(user, course_id):
|
||||
# Enroll user to the course and add manual enrollment audit trail
|
||||
create_manual_course_enrollment(
|
||||
user=user,
|
||||
course_id=course_id,
|
||||
mode=course_mode,
|
||||
enrolled_by=request.user,
|
||||
reason='Enrolling via csv upload',
|
||||
state_transition=UNENROLLED_TO_ENROLLED,
|
||||
)
|
||||
enroll_email(course_id=course_id,
|
||||
student_email=email,
|
||||
auto_enroll=True,
|
||||
email_students=notify_by_email,
|
||||
email_params=email_params)
|
||||
else:
|
||||
# update the course mode if already enrolled
|
||||
existing_enrollment = CourseEnrollment.get_enrollment(user, course_id)
|
||||
if existing_enrollment.mode != course_mode:
|
||||
existing_enrollment.change_mode(mode=course_mode)
|
||||
if cohort:
|
||||
try:
|
||||
add_user_to_cohort(cohort, user)
|
||||
except ValueError:
|
||||
# user already in this cohort; ignore
|
||||
pass
|
||||
elif is_email_retired(email):
|
||||
# We are either attempting to enroll a retired user or create a new user with an email which is
|
||||
# already associated with a retired account. Simply block these attempts.
|
||||
row_errors.append({
|
||||
'username': username,
|
||||
'email': email,
|
||||
'response': _('Invalid email {email_address}.').format(email_address=email),
|
||||
})
|
||||
log.warning('Email address %s is associated with a retired user, so course enrollment was ' + # lint-amnesty, pylint: disable=logging-not-lazy
|
||||
'blocked.', email)
|
||||
else:
|
||||
# This email does not yet exist, so we need to create a new account
|
||||
# If username already exists in the database, then create_and_enroll_user
|
||||
# will raise an IntegrityError exception.
|
||||
password = generate_unique_password(generated_passwords)
|
||||
errors = create_and_enroll_user(
|
||||
email,
|
||||
username,
|
||||
name,
|
||||
country,
|
||||
password,
|
||||
course_id,
|
||||
course_mode,
|
||||
request.user,
|
||||
email_params,
|
||||
email_user=notify_by_email,
|
||||
)
|
||||
row_errors.extend(errors)
|
||||
if cohort:
|
||||
try:
|
||||
add_user_to_cohort(cohort, email)
|
||||
except ValueError:
|
||||
# user already in this cohort; ignore
|
||||
# NOTE: Checking this here may be unnecessary if we can prove that a
|
||||
# new user will never be
|
||||
# automatically assigned to a cohort from the above.
|
||||
pass
|
||||
except ValidationError:
|
||||
row_errors.append({
|
||||
'username': username,
|
||||
'email': email,
|
||||
'response': _('Invalid email {email_address}.').format(email_address=email),
|
||||
})
|
||||
|
||||
else:
|
||||
general_errors.append({
|
||||
'username': '', 'email': '', 'response': _('File is not attached.')
|
||||
})
|
||||
|
||||
results = {
|
||||
'row_errors': row_errors,
|
||||
'general_errors': general_errors,
|
||||
'warnings': warnings
|
||||
}
|
||||
return JsonResponse(results)
|
||||
|
||||
|
||||
def generate_random_string(length):
|
||||
@@ -979,17 +987,8 @@ def bulk_beta_modify_access(request, course_id):
|
||||
return JsonResponse(response_payload)
|
||||
|
||||
|
||||
@require_POST
|
||||
@ensure_csrf_cookie
|
||||
@cache_control(no_cache=True, no_store=True, must_revalidate=True)
|
||||
@require_course_permission(permissions.EDIT_COURSE_ACCESS)
|
||||
@require_post_params(
|
||||
unique_student_identifier="email or username of user to change access",
|
||||
rolename="'instructor', 'staff', 'beta', or 'ccx_coach'",
|
||||
action="'allow' or 'revoke'"
|
||||
)
|
||||
@common_exceptions_400
|
||||
def modify_access(request, course_id):
|
||||
@method_decorator(cache_control(no_cache=True, no_store=True, must_revalidate=True), name='dispatch')
|
||||
class ModifyAccess(APIView):
|
||||
"""
|
||||
Modify staff/instructor access of other user.
|
||||
Requires instructor access.
|
||||
@@ -1001,77 +1000,83 @@ def modify_access(request, course_id):
|
||||
rolename is one of ['instructor', 'staff', 'beta', 'ccx_coach']
|
||||
action is one of ['allow', 'revoke']
|
||||
"""
|
||||
course_id = CourseKey.from_string(course_id)
|
||||
course = get_course_with_access(
|
||||
request.user, 'instructor', course_id, depth=None
|
||||
)
|
||||
unique_student_identifier = request.POST.get('unique_student_identifier')
|
||||
try:
|
||||
user = get_student_from_identifier(unique_student_identifier)
|
||||
except User.DoesNotExist:
|
||||
response_payload = {
|
||||
'unique_student_identifier': unique_student_identifier,
|
||||
'userDoesNotExist': True,
|
||||
}
|
||||
return JsonResponse(response_payload)
|
||||
permission_classes = (IsAuthenticated, permissions.InstructorPermission)
|
||||
permission_name = permissions.EDIT_COURSE_ACCESS
|
||||
serializer_class = AccessSerializer
|
||||
|
||||
# Check that user is active, because add_users
|
||||
# in common/djangoapps/student/roles.py fails
|
||||
# silently when we try to add an inactive user.
|
||||
if not user.is_active:
|
||||
response_payload = {
|
||||
'unique_student_identifier': user.username,
|
||||
'inactiveUser': True,
|
||||
}
|
||||
return JsonResponse(response_payload)
|
||||
@method_decorator(ensure_csrf_cookie)
|
||||
def post(self, request, course_id):
|
||||
"""
|
||||
Modify staff/instructor access of other user.
|
||||
Requires instructor access.
|
||||
"""
|
||||
course_id = CourseKey.from_string(course_id)
|
||||
course = get_course_with_access(
|
||||
request.user, 'instructor', course_id, depth=None
|
||||
)
|
||||
|
||||
rolename = request.POST.get('rolename')
|
||||
action = request.POST.get('action')
|
||||
serializer_data = AccessSerializer(data=request.data)
|
||||
if not serializer_data.is_valid():
|
||||
return HttpResponseBadRequest(reason=serializer_data.errors)
|
||||
|
||||
if rolename not in ROLES:
|
||||
error = strip_tags(f"unknown rolename '{rolename}'")
|
||||
log.error(error)
|
||||
return HttpResponseBadRequest(error)
|
||||
user = serializer_data.validated_data.get('unique_student_identifier')
|
||||
if not user:
|
||||
response_payload = {
|
||||
'unique_student_identifier': request.data.get('unique_student_identifier'),
|
||||
'userDoesNotExist': True,
|
||||
}
|
||||
return JsonResponse(response_payload)
|
||||
|
||||
if not user.is_active:
|
||||
response_payload = {
|
||||
'unique_student_identifier': user.username,
|
||||
'inactiveUser': True,
|
||||
}
|
||||
return JsonResponse(response_payload)
|
||||
|
||||
rolename = serializer_data.data['rolename']
|
||||
action = serializer_data.data['action']
|
||||
|
||||
if rolename not in ROLES:
|
||||
error = strip_tags(f"unknown rolename '{rolename}'")
|
||||
log.error(error)
|
||||
return HttpResponseBadRequest(error)
|
||||
|
||||
# disallow instructors from removing their own instructor access.
|
||||
if rolename == 'instructor' and user == request.user and action != 'allow':
|
||||
response_payload = {
|
||||
'unique_student_identifier': user.username,
|
||||
'rolename': rolename,
|
||||
'action': action,
|
||||
'removingSelfAsInstructor': True,
|
||||
}
|
||||
return JsonResponse(response_payload)
|
||||
|
||||
if action == 'allow':
|
||||
allow_access(course, user, rolename)
|
||||
if not is_user_enrolled_in_course(user, course_id):
|
||||
CourseEnrollment.enroll(user, course_id)
|
||||
elif action == 'revoke':
|
||||
revoke_access(course, user, rolename)
|
||||
else:
|
||||
return HttpResponseBadRequest(strip_tags(
|
||||
f"unrecognized action u'{action}'"
|
||||
))
|
||||
|
||||
# disallow instructors from removing their own instructor access.
|
||||
if rolename == 'instructor' and user == request.user and action != 'allow':
|
||||
response_payload = {
|
||||
'unique_student_identifier': user.username,
|
||||
'rolename': rolename,
|
||||
'action': action,
|
||||
'removingSelfAsInstructor': True,
|
||||
'success': 'yes',
|
||||
}
|
||||
return JsonResponse(response_payload)
|
||||
|
||||
if action == 'allow':
|
||||
allow_access(course, user, rolename)
|
||||
if not is_user_enrolled_in_course(user, course_id):
|
||||
CourseEnrollment.enroll(user, course_id)
|
||||
elif action == 'revoke':
|
||||
revoke_access(course, user, rolename)
|
||||
else:
|
||||
return HttpResponseBadRequest(strip_tags(
|
||||
f"unrecognized action u'{action}'"
|
||||
))
|
||||
|
||||
response_payload = {
|
||||
'unique_student_identifier': user.username,
|
||||
'rolename': rolename,
|
||||
'action': action,
|
||||
'success': 'yes',
|
||||
}
|
||||
return JsonResponse(response_payload)
|
||||
|
||||
|
||||
@require_POST
|
||||
@ensure_csrf_cookie
|
||||
@cache_control(no_cache=True, no_store=True, must_revalidate=True)
|
||||
@require_course_permission(permissions.EDIT_COURSE_ACCESS)
|
||||
@require_post_params(rolename="'instructor', 'staff', or 'beta'")
|
||||
def list_course_role_members(request, course_id):
|
||||
@method_decorator(cache_control(no_cache=True, no_store=True, must_revalidate=True), name='dispatch')
|
||||
class ListCourseRoleMembersView(APIView):
|
||||
"""
|
||||
List instructors and staff.
|
||||
Requires instructor access.
|
||||
View to list instructors and staff for a specific course.
|
||||
Requires the user to have instructor access.
|
||||
|
||||
rolename is one of ['instructor', 'staff', 'beta', 'ccx_coach']
|
||||
|
||||
@@ -1087,33 +1092,41 @@ def list_course_role_members(request, course_id):
|
||||
]
|
||||
}
|
||||
"""
|
||||
course_id = CourseKey.from_string(course_id)
|
||||
course = get_course_with_access(
|
||||
request.user, 'instructor', course_id, depth=None
|
||||
)
|
||||
permission_classes = (IsAuthenticated, permissions.InstructorPermission)
|
||||
permission_name = permissions.EDIT_COURSE_ACCESS
|
||||
|
||||
rolename = request.POST.get('rolename')
|
||||
@method_decorator(ensure_csrf_cookie)
|
||||
def post(self, request, course_id):
|
||||
"""
|
||||
Handles POST request to list instructors and staff.
|
||||
|
||||
if rolename not in ROLES:
|
||||
return HttpResponseBadRequest()
|
||||
Args:
|
||||
request (HttpRequest): The request object containing user data.
|
||||
course_id (str): The ID of the course to list instructors and staff for.
|
||||
|
||||
def extract_user_info(user):
|
||||
""" convert user into dicts for json view """
|
||||
Returns:
|
||||
Response: A Response object containing the list of instructors and staff or an error message.
|
||||
|
||||
return {
|
||||
'username': user.username,
|
||||
'email': user.email,
|
||||
'first_name': user.first_name,
|
||||
'last_name': user.last_name,
|
||||
Raises:
|
||||
Http404: If the course does not exist.
|
||||
"""
|
||||
course_id = CourseKey.from_string(course_id)
|
||||
course = get_course_with_access(
|
||||
request.user, 'instructor', course_id, depth=None
|
||||
)
|
||||
role_serializer = RoleNameSerializer(data=request.data)
|
||||
role_serializer.is_valid(raise_exception=True)
|
||||
rolename = role_serializer.data['rolename']
|
||||
|
||||
users = list_with_level(course.id, rolename)
|
||||
serializer = UserSerializer(users, many=True)
|
||||
|
||||
response_payload = {
|
||||
'course_id': str(course_id),
|
||||
rolename: serializer.data,
|
||||
}
|
||||
|
||||
response_payload = {
|
||||
'course_id': str(course_id),
|
||||
rolename: list(map(extract_user_info, list_with_level(
|
||||
course.id, rolename
|
||||
))),
|
||||
}
|
||||
return JsonResponse(response_payload)
|
||||
return Response(response_payload, status=status.HTTP_200_OK)
|
||||
|
||||
|
||||
class ProblemResponseReportPostParamsSerializer(serializers.Serializer): # pylint: disable=abstract-method
|
||||
@@ -1718,15 +1731,35 @@ def get_student_enrollment_status(request, course_id):
|
||||
return JsonResponse(response_payload)
|
||||
|
||||
|
||||
@require_POST
|
||||
@ensure_csrf_cookie
|
||||
@cache_control(no_cache=True, no_store=True, must_revalidate=True)
|
||||
@require_course_permission(permissions.ENROLLMENT_REPORT)
|
||||
@require_post_params(
|
||||
unique_student_identifier="email or username of student for whom to get progress url"
|
||||
)
|
||||
@common_exceptions_400
|
||||
def get_student_progress_url(request, course_id):
|
||||
class StudentProgressUrlSerializer(serializers.Serializer):
|
||||
"""Serializer for course renders"""
|
||||
unique_student_identifier = serializers.CharField(write_only=True)
|
||||
course_id = CourseKeyField(required=False)
|
||||
progress_url = serializers.SerializerMethodField()
|
||||
|
||||
def get_progress_url(self, obj): # pylint: disable=unused-argument
|
||||
"""
|
||||
Return the progress URL for the student.
|
||||
Args:
|
||||
obj (dict): The dictionary containing data for the serializer.
|
||||
Returns:
|
||||
str: The URL for the progress of the student in the course.
|
||||
"""
|
||||
user = get_student_from_identifier(obj.get('unique_student_identifier'))
|
||||
course_id = obj.get('course_id') # Adjust based on your data structure
|
||||
|
||||
if course_home_mfe_progress_tab_is_active(course_id):
|
||||
progress_url = get_learning_mfe_home_url(course_id, url_fragment='progress')
|
||||
if user is not None:
|
||||
progress_url += '/{}/'.format(user.id)
|
||||
else:
|
||||
progress_url = reverse('student_progress', kwargs={'course_id': str(course_id), 'student_id': user.id})
|
||||
|
||||
return progress_url
|
||||
|
||||
|
||||
@method_decorator(cache_control(no_cache=True, no_store=True, must_revalidate=True), name='dispatch')
|
||||
class StudentProgressUrl(APIView):
|
||||
"""
|
||||
Get the progress url of a student.
|
||||
Limited to staff access.
|
||||
@@ -1736,21 +1769,25 @@ def get_student_progress_url(request, course_id):
|
||||
'progress_url': '/../...'
|
||||
}
|
||||
"""
|
||||
course_id = CourseKey.from_string(course_id)
|
||||
user = get_student_from_identifier(request.POST.get('unique_student_identifier'))
|
||||
authentication_classes = (
|
||||
JwtAuthentication,
|
||||
BearerAuthenticationAllowInactiveUser,
|
||||
SessionAuthenticationAllowInactiveUser,
|
||||
)
|
||||
permission_classes = (IsAuthenticated, permissions.InstructorPermission)
|
||||
serializer_class = StudentProgressUrlSerializer
|
||||
permission_name = permissions.ENROLLMENT_REPORT
|
||||
|
||||
if course_home_mfe_progress_tab_is_active(course_id):
|
||||
progress_url = get_learning_mfe_home_url(course_id, url_fragment='progress')
|
||||
if user is not None:
|
||||
progress_url += '/{}/'.format(user.id)
|
||||
else:
|
||||
progress_url = reverse('student_progress', kwargs={'course_id': str(course_id), 'student_id': user.id})
|
||||
|
||||
response_payload = {
|
||||
'course_id': str(course_id),
|
||||
'progress_url': progress_url,
|
||||
}
|
||||
return JsonResponse(response_payload)
|
||||
@method_decorator(ensure_csrf_cookie)
|
||||
def post(self, request, course_id):
|
||||
"""Post method for validating incoming data and generating progress URL"""
|
||||
data = {
|
||||
'course_id': course_id,
|
||||
'unique_student_identifier': request.data.get('unique_student_identifier')
|
||||
}
|
||||
serializer = self.serializer_class(data=data)
|
||||
serializer.is_valid(raise_exception=True)
|
||||
return Response(serializer.data)
|
||||
|
||||
|
||||
@transaction.non_atomic_requests
|
||||
@@ -2135,23 +2172,35 @@ def list_background_email_tasks(request, course_id):
|
||||
return JsonResponse(response_payload)
|
||||
|
||||
|
||||
@require_POST
|
||||
@ensure_csrf_cookie
|
||||
@cache_control(no_cache=True, no_store=True, must_revalidate=True)
|
||||
@require_course_permission(permissions.EMAIL)
|
||||
def list_email_content(request, course_id):
|
||||
@method_decorator(cache_control(no_cache=True, no_store=True, must_revalidate=True), name='dispatch')
|
||||
class ListEmailContent(APIView):
|
||||
"""
|
||||
List the content of bulk emails sent
|
||||
"""
|
||||
course_id = CourseKey.from_string(course_id)
|
||||
task_type = InstructorTaskTypes.BULK_COURSE_EMAIL
|
||||
# First get tasks list of bulk emails sent
|
||||
emails = task_api.get_instructor_task_history(course_id, task_type=task_type)
|
||||
permission_classes = (IsAuthenticated, permissions.InstructorPermission)
|
||||
permission_name = permissions.EMAIL
|
||||
|
||||
response_payload = {
|
||||
'emails': list(map(extract_email_features, emails)),
|
||||
}
|
||||
return JsonResponse(response_payload)
|
||||
@method_decorator(ensure_csrf_cookie)
|
||||
def post(self, request, course_id):
|
||||
"""
|
||||
List the content of bulk emails sent for a specific course.
|
||||
|
||||
Args:
|
||||
request (HttpRequest): The HTTP request object.
|
||||
course_id (str): The ID of the course for which to list the bulk emails.
|
||||
|
||||
Returns:
|
||||
HttpResponse: A response object containing the list of bulk email contents.
|
||||
"""
|
||||
course_id = CourseKey.from_string(course_id)
|
||||
task_type = InstructorTaskTypes.BULK_COURSE_EMAIL
|
||||
# First get tasks list of bulk emails sent
|
||||
emails = task_api.get_instructor_task_history(course_id, task_type=task_type)
|
||||
|
||||
response_payload = {
|
||||
'emails': list(map(extract_email_features, emails)),
|
||||
}
|
||||
return JsonResponse(response_payload)
|
||||
|
||||
|
||||
class InstructorTaskSerializer(serializers.Serializer): # pylint: disable=abstract-method
|
||||
@@ -2341,46 +2390,51 @@ def _list_instructor_tasks(request, course_id):
|
||||
return JsonResponse(response_payload)
|
||||
|
||||
|
||||
@require_POST
|
||||
@ensure_csrf_cookie
|
||||
@cache_control(no_cache=True, no_store=True, must_revalidate=True)
|
||||
@require_course_permission(permissions.SHOW_TASKS)
|
||||
def list_entrance_exam_instructor_tasks(request, course_id):
|
||||
@method_decorator(cache_control(no_cache=True, no_store=True, must_revalidate=True), name='dispatch')
|
||||
class ListEntranceExamInstructorTasks(APIView):
|
||||
"""
|
||||
List entrance exam related instructor tasks.
|
||||
|
||||
Takes either of the following query parameters
|
||||
- unique_student_identifier is an email or username
|
||||
- all_students is a boolean
|
||||
"""
|
||||
course_id = CourseKey.from_string(course_id)
|
||||
course = get_course_by_id(course_id)
|
||||
student = request.POST.get('unique_student_identifier', None)
|
||||
if student is not None:
|
||||
student = get_student_from_identifier(student)
|
||||
permission_classes = (IsAuthenticated, permissions.InstructorPermission)
|
||||
permission_name = permissions.SHOW_TASKS
|
||||
|
||||
try:
|
||||
entrance_exam_key = UsageKey.from_string(course.entrance_exam_id).map_into_course(course_id)
|
||||
except InvalidKeyError:
|
||||
return HttpResponseBadRequest(_("Course has no valid entrance exam section."))
|
||||
if student:
|
||||
# Specifying for a single student's entrance exam history
|
||||
tasks = task_api.get_entrance_exam_instructor_task_history(
|
||||
course_id,
|
||||
entrance_exam_key,
|
||||
student
|
||||
)
|
||||
else:
|
||||
# Specifying for all student's entrance exam history
|
||||
tasks = task_api.get_entrance_exam_instructor_task_history(
|
||||
course_id,
|
||||
entrance_exam_key
|
||||
)
|
||||
@method_decorator(ensure_csrf_cookie)
|
||||
def post(self, request, course_id):
|
||||
"""
|
||||
List entrance exam related instructor tasks.
|
||||
|
||||
response_payload = {
|
||||
'tasks': list(map(extract_task_features, tasks)),
|
||||
}
|
||||
return JsonResponse(response_payload)
|
||||
Takes either of the following query parameters
|
||||
- unique_student_identifier is an email or username
|
||||
- all_students is a boolean
|
||||
"""
|
||||
course_id = CourseKey.from_string(course_id)
|
||||
course = get_course_by_id(course_id)
|
||||
student = request.POST.get('unique_student_identifier', None)
|
||||
if student is not None:
|
||||
student = get_student_from_identifier(student)
|
||||
|
||||
try:
|
||||
entrance_exam_key = UsageKey.from_string(course.entrance_exam_id).map_into_course(course_id)
|
||||
except InvalidKeyError:
|
||||
return HttpResponseBadRequest(_("Course has no valid entrance exam section."))
|
||||
if student:
|
||||
# Specifying for a single student's entrance exam history
|
||||
tasks = task_api.get_entrance_exam_instructor_task_history(
|
||||
course_id,
|
||||
entrance_exam_key,
|
||||
student
|
||||
)
|
||||
else:
|
||||
# Specifying for all student's entrance exam history
|
||||
tasks = task_api.get_entrance_exam_instructor_task_history(
|
||||
course_id,
|
||||
entrance_exam_key
|
||||
)
|
||||
|
||||
response_payload = {
|
||||
'tasks': list(map(extract_task_features, tasks)),
|
||||
}
|
||||
return JsonResponse(response_payload)
|
||||
|
||||
|
||||
class ReportDownloadSerializer(serializers.Serializer): # pylint: disable=abstract-method
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
|
||||
"""
|
||||
Instructor API endpoint urls.
|
||||
"""
|
||||
@@ -21,9 +22,9 @@ v1_api_urls = [
|
||||
|
||||
urlpatterns = [
|
||||
path('students_update_enrollment', api.students_update_enrollment, name='students_update_enrollment'),
|
||||
path('register_and_enroll_students', api.register_and_enroll_students, name='register_and_enroll_students'),
|
||||
path('list_course_role_members', api.list_course_role_members, name='list_course_role_members'),
|
||||
path('modify_access', api.modify_access, name='modify_access'),
|
||||
path('register_and_enroll_students', api.RegisterAndEnrollStudents.as_view(), name='register_and_enroll_students'),
|
||||
path('list_course_role_members', api.ListCourseRoleMembersView.as_view(), name='list_course_role_members'),
|
||||
path('modify_access', api.ModifyAccess.as_view(), name='modify_access'),
|
||||
path('bulk_beta_modify_access', api.bulk_beta_modify_access, name='bulk_beta_modify_access'),
|
||||
path('get_problem_responses', api.get_problem_responses, name='get_problem_responses'),
|
||||
path('get_grading_config', api.get_grading_config, name='get_grading_config'),
|
||||
@@ -32,20 +33,20 @@ urlpatterns = [
|
||||
path('get_students_who_may_enroll', api.get_students_who_may_enroll, name='get_students_who_may_enroll'),
|
||||
path('get_anon_ids', api.get_anon_ids, name='get_anon_ids'),
|
||||
path('get_student_enrollment_status', api.get_student_enrollment_status, name="get_student_enrollment_status"),
|
||||
path('get_student_progress_url', api.get_student_progress_url, name='get_student_progress_url'),
|
||||
path('get_student_progress_url', api.StudentProgressUrl.as_view(), name='get_student_progress_url'),
|
||||
path('reset_student_attempts', api.reset_student_attempts, name='reset_student_attempts'),
|
||||
path('rescore_problem', api.rescore_problem, name='rescore_problem'),
|
||||
path('override_problem_score', api.override_problem_score, name='override_problem_score'),
|
||||
path('reset_student_attempts_for_entrance_exam', api.reset_student_attempts_for_entrance_exam,
|
||||
name='reset_student_attempts_for_entrance_exam'),
|
||||
path('rescore_entrance_exam', api.rescore_entrance_exam, name='rescore_entrance_exam'),
|
||||
path('list_entrance_exam_instructor_tasks', api.list_entrance_exam_instructor_tasks,
|
||||
path('list_entrance_exam_instructor_tasks', api.ListEntranceExamInstructorTasks.as_view(),
|
||||
name='list_entrance_exam_instructor_tasks'),
|
||||
path('mark_student_can_skip_entrance_exam', api.mark_student_can_skip_entrance_exam,
|
||||
name='mark_student_can_skip_entrance_exam'),
|
||||
path('list_instructor_tasks', api.list_instructor_tasks, name='list_instructor_tasks'),
|
||||
path('list_background_email_tasks', api.list_background_email_tasks, name='list_background_email_tasks'),
|
||||
path('list_email_content', api.list_email_content, name='list_email_content'),
|
||||
path('list_email_content', api.ListEmailContent.as_view(), name='list_email_content'),
|
||||
path('list_forum_members', api.list_forum_members, name='list_forum_members'),
|
||||
path('update_forum_role_membership', api.update_forum_role_membership, name='update_forum_role_membership'),
|
||||
path('send_email', api.send_email, name='send_email'),
|
||||
|
||||
61
lms/djangoapps/instructor/views/serializer.py
Normal file
61
lms/djangoapps/instructor/views/serializer.py
Normal file
@@ -0,0 +1,61 @@
|
||||
""" Instructor apis serializers. """
|
||||
|
||||
from django.contrib.auth.models import User # lint-amnesty, pylint: disable=imported-auth-user
|
||||
from django.core.exceptions import ValidationError
|
||||
from django.utils.translation import gettext as _
|
||||
from rest_framework import serializers
|
||||
from .tools import get_student_from_identifier
|
||||
|
||||
from lms.djangoapps.instructor.access import ROLES
|
||||
|
||||
|
||||
class RoleNameSerializer(serializers.Serializer): # pylint: disable=abstract-method
|
||||
"""
|
||||
Serializer that describes the response of the problem response report generation API.
|
||||
"""
|
||||
|
||||
rolename = serializers.CharField(help_text=_("Role name"))
|
||||
|
||||
def validate_rolename(self, value):
|
||||
"""
|
||||
Check that the rolename is valid.
|
||||
"""
|
||||
if value not in ROLES:
|
||||
raise ValidationError(_("Invalid role name."))
|
||||
return value
|
||||
|
||||
|
||||
class UserSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = User
|
||||
fields = ['username', 'email', 'first_name', 'last_name']
|
||||
|
||||
|
||||
class AccessSerializer(serializers.Serializer):
|
||||
"""
|
||||
Serializer for managing user access changes.
|
||||
This serializer validates and processes the data required to modify
|
||||
user access within a system.
|
||||
"""
|
||||
unique_student_identifier = serializers.CharField(
|
||||
max_length=255,
|
||||
help_text="Email or username of user to change access"
|
||||
)
|
||||
rolename = serializers.CharField(
|
||||
help_text="Role name to assign to the user"
|
||||
)
|
||||
action = serializers.ChoiceField(
|
||||
choices=['allow', 'revoke'],
|
||||
help_text="Action to perform on the user's access"
|
||||
)
|
||||
|
||||
def validate_unique_student_identifier(self, value):
|
||||
"""
|
||||
Validate that the unique_student_identifier corresponds to an existing user.
|
||||
"""
|
||||
try:
|
||||
user = get_student_from_identifier(value)
|
||||
except User.DoesNotExist:
|
||||
return None
|
||||
|
||||
return user
|
||||
@@ -5,7 +5,7 @@
|
||||
# List of valid templates is explicitly managed for (short-term)
|
||||
# security reasons.
|
||||
|
||||
|
||||
import logging
|
||||
import mimetypes
|
||||
|
||||
from django.conf import settings
|
||||
@@ -23,6 +23,8 @@ from common.djangoapps.util.cache import cache_if_anonymous
|
||||
from common.djangoapps.util.views import fix_crum_request
|
||||
from openedx.core.djangoapps.site_configuration import helpers as configuration_helpers
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
valid_templates = []
|
||||
|
||||
if settings.STATIC_GRAB:
|
||||
@@ -122,4 +124,21 @@ def render_429(request, exception=None): # lint-amnesty, pylint: disable=unused
|
||||
|
||||
@fix_crum_request
|
||||
def render_500(request):
|
||||
return HttpResponseServerError(render_to_string('static_templates/server-error.html', {}, request=request))
|
||||
"""
|
||||
Render the generic error page when we have an uncaught error.
|
||||
"""
|
||||
try:
|
||||
return HttpResponseServerError(render_to_string('static_templates/server-error.html', {}, request=request))
|
||||
except BaseException as e:
|
||||
# If we can't render the error page, ensure we don't raise another
|
||||
# exception -- because if we do, we'll probably just end up back
|
||||
# at the same rendering error.
|
||||
#
|
||||
# This is an attempt at working around the recursive error handling issues
|
||||
# observed in <https://github.com/openedx/edx-platform/issues/35151>, which
|
||||
# were triggered by Mako and translation errors.
|
||||
|
||||
log.error("Encountered error while rendering error page.", exc_info=True)
|
||||
# This message is intentionally hardcoded and does not involve
|
||||
# any translation, templating, etc. Do not translate.
|
||||
return HttpResponseServerError("Encountered error while rendering error page.")
|
||||
|
||||
@@ -56,7 +56,10 @@ from enterprise.constants import (
|
||||
ENTERPRISE_FULFILLMENT_OPERATOR_ROLE,
|
||||
ENTERPRISE_REPORTING_CONFIG_ADMIN_ROLE,
|
||||
ENTERPRISE_SSO_ORCHESTRATOR_OPERATOR_ROLE,
|
||||
ENTERPRISE_OPERATOR_ROLE
|
||||
ENTERPRISE_OPERATOR_ROLE,
|
||||
SYSTEM_ENTERPRISE_PROVISIONING_ADMIN_ROLE,
|
||||
PROVISIONING_ENTERPRISE_CUSTOMER_ADMIN_ROLE,
|
||||
PROVISIONING_PENDING_ENTERPRISE_CUSTOMER_ADMIN_ROLE,
|
||||
)
|
||||
|
||||
from openedx.core.constants import COURSE_KEY_REGEX, COURSE_KEY_PATTERN, COURSE_ID_PATTERN
|
||||
@@ -1101,6 +1104,11 @@ DEFAULT_GROUPS = []
|
||||
# If this is true, random scores will be generated for the purpose of debugging the profile graphs
|
||||
GENERATE_PROFILE_SCORES = False
|
||||
|
||||
# .. setting_name: GRADEBOOK_FREEZE_DAYS
|
||||
# .. setting_default: 30
|
||||
# .. setting_description: Sets the number of days after which the gradebook will freeze following the course's end.
|
||||
GRADEBOOK_FREEZE_DAYS = 30
|
||||
|
||||
# Used with XQueue
|
||||
XQUEUE_WAITTIME_BETWEEN_REQUESTS = 5 # seconds
|
||||
XQUEUE_INTERFACE = {
|
||||
@@ -4740,6 +4748,10 @@ SYSTEM_TO_FEATURE_ROLE_MAPPING = {
|
||||
ENTERPRISE_FULFILLMENT_OPERATOR_ROLE,
|
||||
ENTERPRISE_SSO_ORCHESTRATOR_OPERATOR_ROLE,
|
||||
],
|
||||
SYSTEM_ENTERPRISE_PROVISIONING_ADMIN_ROLE: [
|
||||
PROVISIONING_ENTERPRISE_CUSTOMER_ADMIN_ROLE,
|
||||
PROVISIONING_PENDING_ENTERPRISE_CUSTOMER_ADMIN_ROLE,
|
||||
],
|
||||
}
|
||||
|
||||
DATA_CONSENT_SHARE_CACHE_TIMEOUT = 8 * 60 * 60 # 8 hours
|
||||
|
||||
@@ -739,8 +739,8 @@ describe('Program Details View', () => {
|
||||
);
|
||||
});
|
||||
|
||||
it('should render appropriate subscription text when subscription is active with trial', () => {
|
||||
testSubscriptionState(
|
||||
it('should not render appropriate subscription text when subscription is active with trial', () => {
|
||||
testSubscriptionSunsetting(
|
||||
'active',
|
||||
'Manage my subscription',
|
||||
'Trial ends',
|
||||
@@ -748,8 +748,8 @@ describe('Program Details View', () => {
|
||||
);
|
||||
});
|
||||
|
||||
it('should render appropriate subscription text when subscription is active', () => {
|
||||
testSubscriptionState(
|
||||
it('should not render appropriate subscription text when subscription is active', () => {
|
||||
testSubscriptionSunsetting(
|
||||
'active',
|
||||
'Manage my subscription',
|
||||
'Your next billing date is',
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
// LMS-specific variables
|
||||
|
||||
@import '_builtin-block-variables';
|
||||
|
||||
$text-width-readability-max: 1080px;
|
||||
|
||||
// LMS-only colors
|
||||
|
||||
@@ -46,64 +46,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<% } %>
|
||||
<% if (isSubscriptionEligible && (
|
||||
completedCount !== totalCount
|
||||
|| subscriptionState === 'active'
|
||||
)
|
||||
) { %>
|
||||
<div class="d-flex flex-column align-items-start flex-xl-row align-items-xl-center upgrade-subscription">
|
||||
<a
|
||||
href="<%- subscriptionUrl %>"
|
||||
class="js-subscription-cta btn-brand btn cta-primary upgrade-button"
|
||||
<% if (subscriptionState === 'active') { %>
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
<% } %>
|
||||
>
|
||||
<% if (subscriptionState === 'active') { %>
|
||||
<div class="d-flex align-items-center">
|
||||
<span><%- gettext('Manage my subscription') %></span>
|
||||
<div class="subscription-icon-launch">
|
||||
<% // xss-lint: disable=underscore-not-escaped %>
|
||||
<%= launchIcon %>
|
||||
</div>
|
||||
</div>
|
||||
<% } else if (subscriptionState === 'inactive') { %>
|
||||
<div class="d-flex align-items-center">
|
||||
<div class="subscription-icon-restart">
|
||||
<% // xss-lint: disable=underscore-not-escaped %>
|
||||
<%= restartIcon %>
|
||||
</div>
|
||||
<span><%- gettext('Restart my subscription') %></span>
|
||||
</div>
|
||||
<% } else { %>
|
||||
<%- StringUtils.interpolate(
|
||||
gettext('Start {trialLength}-day free trial'),
|
||||
{ trialLength }
|
||||
) %>
|
||||
<% } %>
|
||||
</a>
|
||||
<span class="subscription-info-brief">
|
||||
<%- StringUtils.interpolate(
|
||||
(
|
||||
hasActiveTrial
|
||||
? gettext('Trial ends {trialEndDate} at {trialEndTime}')
|
||||
: subscriptionState === 'active'
|
||||
? gettext('Your next billing date is {currentPeriodEnd}')
|
||||
: subscriptionState === 'inactive'
|
||||
? gettext('{subscriptionPrice} subscription. Cancel anytime.')
|
||||
: gettext('{subscriptionPrice} subscription after trial ends. Cancel anytime.')
|
||||
),
|
||||
{
|
||||
subscriptionPrice,
|
||||
currentPeriodEnd,
|
||||
trialEndDate,
|
||||
trialEndTime,
|
||||
}
|
||||
) %>
|
||||
</span>
|
||||
</div>
|
||||
<% } else if (
|
||||
<% if (
|
||||
!isSubscriptionEligible
|
||||
&& is_learner_eligible_for_one_click_purchase
|
||||
&& (typeof is_mobile_only === 'undefined' || is_mobile_only === false)
|
||||
|
||||
@@ -21,64 +21,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<% } %>
|
||||
<% if (isSubscriptionEligible && (
|
||||
completedCount !== totalCount
|
||||
|| subscriptionState === 'active'
|
||||
)
|
||||
) { %>
|
||||
<div class="d-flex flex-column align-items-start flex-xl-row align-items-xl-center upgrade-subscription">
|
||||
<a
|
||||
href="<%- subscriptionUrl %>"
|
||||
class="js-subscription-cta btn-brand btn cta-primary upgrade-button"
|
||||
<% if (subscriptionState === 'active') { %>
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
<% } %>
|
||||
>
|
||||
<% if (subscriptionState === 'active') { %>
|
||||
<div class="d-flex align-items-center">
|
||||
<span><%- gettext('Manage my subscription') %></span>
|
||||
<div class="subscription-icon-launch">
|
||||
<% // xss-lint: disable=underscore-not-escaped %>
|
||||
<%= launchIcon %>
|
||||
</div>
|
||||
</div>
|
||||
<% } else if (subscriptionState === 'inactive') { %>
|
||||
<div class="d-flex align-items-center">
|
||||
<div class="subscription-icon-restart">
|
||||
<% // xss-lint: disable=underscore-not-escaped %>
|
||||
<%= restartIcon %>
|
||||
</div>
|
||||
<span><%- gettext('Restart my subscription') %></span>
|
||||
</div>
|
||||
<% } else { %>
|
||||
<%- StringUtils.interpolate(
|
||||
gettext('Start {trialLength}-day free trial'),
|
||||
{ trialLength }
|
||||
) %>
|
||||
<% } %>
|
||||
</a>
|
||||
<span class="subscription-info-brief">
|
||||
<%- StringUtils.interpolate(
|
||||
(
|
||||
hasActiveTrial
|
||||
? gettext('Trial ends {trialEndDate} at {trialEndTime}')
|
||||
: subscriptionState === 'active'
|
||||
? gettext('Your next billing date is {currentPeriodEnd}')
|
||||
: subscriptionState === 'inactive'
|
||||
? gettext('{subscriptionPrice} subscription. Cancel anytime.')
|
||||
: gettext('{subscriptionPrice} subscription after trial ends. Cancel anytime.')
|
||||
),
|
||||
{
|
||||
subscriptionPrice,
|
||||
currentPeriodEnd,
|
||||
trialEndDate,
|
||||
trialEndTime,
|
||||
}
|
||||
) %>
|
||||
</span>
|
||||
</div>
|
||||
<% } else if (
|
||||
<% if (
|
||||
!isSubscriptionEligible
|
||||
&& is_learner_eligible_for_one_click_purchase
|
||||
&& (typeof is_mobile_only === 'undefined' || is_mobile_only === false)
|
||||
|
||||
@@ -467,6 +467,29 @@ def delete_index_doc(usage_key: UsageKey) -> None:
|
||||
_wait_for_meili_tasks(tasks)
|
||||
|
||||
|
||||
def delete_all_draft_docs_for_library(library_key: LibraryLocatorV2) -> None:
|
||||
"""
|
||||
Deletes draft documents for the given XBlocks from the search index
|
||||
"""
|
||||
current_rebuild_index_name = _get_running_rebuild_index_name()
|
||||
client = _get_meilisearch_client()
|
||||
# Delete all documents where last_published is null i.e. never published before.
|
||||
delete_filter = [
|
||||
f'{Fields.context_key}="{library_key}"',
|
||||
# This field should only be NULL or have a value, but we're also checking IS EMPTY just in case.
|
||||
# Inner arrays are connected by an OR
|
||||
[f'{Fields.last_published} IS EMPTY', f'{Fields.last_published} IS NULL'],
|
||||
]
|
||||
|
||||
tasks = []
|
||||
if current_rebuild_index_name:
|
||||
# If there is a rebuild in progress, the documents will also be deleted from the new index.
|
||||
tasks.append(client.index(current_rebuild_index_name).delete_documents(filter=delete_filter))
|
||||
tasks.append(client.index(STUDIO_INDEX_NAME).delete_documents(filter=delete_filter))
|
||||
|
||||
_wait_for_meili_tasks(tasks)
|
||||
|
||||
|
||||
def upsert_library_block_index_doc(usage_key: UsageKey) -> None:
|
||||
"""
|
||||
Creates or updates the document for the given Library Block in the search index
|
||||
|
||||
@@ -9,9 +9,9 @@ import logging
|
||||
from celery import shared_task
|
||||
from celery_utils.logged_task import LoggedTask
|
||||
from edx_django_utils.monitoring import set_code_owner_attribute
|
||||
from meilisearch.errors import MeilisearchError
|
||||
from opaque_keys.edx.keys import UsageKey
|
||||
from opaque_keys.edx.locator import LibraryLocatorV2, LibraryUsageLocatorV2
|
||||
from meilisearch.errors import MeilisearchError
|
||||
|
||||
from . import api
|
||||
|
||||
@@ -81,3 +81,6 @@ def update_content_library_index_docs(library_key_str: str) -> None:
|
||||
log.info("Updating content index documents for library with id: %s", library_key)
|
||||
|
||||
api.upsert_content_library_index_docs(library_key)
|
||||
# Delete all documents in this library that were not published by above function
|
||||
# as this task is also triggered on discard event.
|
||||
api.delete_all_draft_docs_for_library(library_key)
|
||||
|
||||
@@ -388,3 +388,18 @@ class TestSearchApi(ModuleStoreTestCase):
|
||||
mock_meilisearch.return_value.index.return_value.update_documents.assert_called_once_with(
|
||||
[self.doc_problem1, self.doc_problem2]
|
||||
)
|
||||
|
||||
@override_settings(MEILISEARCH_ENABLED=True)
|
||||
def test_delete_all_drafts(self, mock_meilisearch):
|
||||
"""
|
||||
Test deleting all draft documents from the index.
|
||||
"""
|
||||
api.delete_all_draft_docs_for_library(self.library.key)
|
||||
|
||||
delete_filter = [
|
||||
f'context_key="{self.library.key}"',
|
||||
['last_published IS EMPTY', 'last_published IS NULL'],
|
||||
]
|
||||
mock_meilisearch.return_value.index.return_value.delete_documents.assert_called_once_with(
|
||||
filter=delete_filter
|
||||
)
|
||||
|
||||
@@ -156,6 +156,9 @@ class ContentLibraryMetadata:
|
||||
version = attr.ib(0)
|
||||
type = attr.ib(default=COMPLEX)
|
||||
last_published = attr.ib(default=None, type=datetime)
|
||||
last_draft_created = attr.ib(default=None, type=datetime)
|
||||
last_draft_created_by = attr.ib(default=None, type=datetime)
|
||||
published_by = attr.ib("")
|
||||
has_unpublished_changes = attr.ib(False)
|
||||
# has_unpublished_deletes will be true when the draft version of the library's bundle
|
||||
# contains deletes of any XBlocks that were in the most recently published version
|
||||
@@ -168,6 +171,8 @@ class ContentLibraryMetadata:
|
||||
# Studio, use it in their courses, and copy content out of this library.
|
||||
allow_public_read = attr.ib(False)
|
||||
license = attr.ib("")
|
||||
created = attr.ib(default=None, type=datetime)
|
||||
updated = attr.ib(default=None, type=datetime)
|
||||
|
||||
|
||||
class AccessLevel:
|
||||
@@ -206,7 +211,7 @@ class LibraryXBlockMetadata:
|
||||
"""
|
||||
Construct a LibraryXBlockMetadata from a Component object.
|
||||
"""
|
||||
last_publish_log = authoring_api.get_last_publish(component.pk)
|
||||
last_publish_log = component.versioning.last_publish_log
|
||||
|
||||
return cls(
|
||||
usage_key=LibraryUsageLocatorV2(
|
||||
@@ -350,8 +355,11 @@ def get_library(library_key):
|
||||
learning_package = ref.learning_package
|
||||
num_blocks = authoring_api.get_all_drafts(learning_package.id).count()
|
||||
last_publish_log = authoring_api.get_last_publish(learning_package.id)
|
||||
has_unpublished_changes = authoring_api.get_entities_with_unpublished_changes(learning_package.id) \
|
||||
.exists()
|
||||
last_draft_log = authoring_api.get_entities_with_unpublished_changes(learning_package.id) \
|
||||
.order_by('-created').first()
|
||||
last_draft_created = last_draft_log.created if last_draft_log else None
|
||||
last_draft_created_by = last_draft_log.created_by.username if last_draft_log and last_draft_log.created_by else None
|
||||
has_unpublished_changes = last_draft_log is not None
|
||||
|
||||
# TODO: I'm doing this one to match already-existing behavior, but this is
|
||||
# something that we should remove. It exists to accomodate some complexities
|
||||
@@ -377,6 +385,9 @@ def get_library(library_key):
|
||||
# libraries. The top level version stays for now because LibraryContentBlock
|
||||
# uses it, but that should hopefully change before the Redwood release.
|
||||
version = 0 if last_publish_log is None else last_publish_log.pk
|
||||
published_by = None
|
||||
if last_publish_log and last_publish_log.published_by:
|
||||
published_by = last_publish_log.published_by.username
|
||||
|
||||
return ContentLibraryMetadata(
|
||||
key=library_key,
|
||||
@@ -386,12 +397,17 @@ def get_library(library_key):
|
||||
num_blocks=num_blocks,
|
||||
version=version,
|
||||
last_published=None if last_publish_log is None else last_publish_log.published_at,
|
||||
published_by=published_by,
|
||||
last_draft_created=last_draft_created,
|
||||
last_draft_created_by=last_draft_created_by,
|
||||
allow_lti=ref.allow_lti,
|
||||
allow_public_learning=ref.allow_public_learning,
|
||||
allow_public_read=ref.allow_public_read,
|
||||
has_unpublished_changes=has_unpublished_changes,
|
||||
has_unpublished_deletes=has_unpublished_deletes,
|
||||
license=ref.license,
|
||||
created=learning_package.created,
|
||||
updated=learning_package.updated,
|
||||
)
|
||||
|
||||
|
||||
@@ -735,27 +751,30 @@ def set_library_block_olx(usage_key, new_olx_str):
|
||||
)
|
||||
|
||||
|
||||
def create_library_block(library_key, block_type, definition_id):
|
||||
def validate_can_add_block_to_library(
|
||||
library_key: LibraryLocatorV2,
|
||||
block_type: str,
|
||||
block_id: str,
|
||||
) -> tuple[ContentLibrary, LibraryUsageLocatorV2]:
|
||||
"""
|
||||
Create a new XBlock in this library of the specified type (e.g. "html").
|
||||
"""
|
||||
# It's in the serializer as ``definition_id``, but for our purposes, it's
|
||||
# the block_id. See the comments in ``LibraryXBlockCreationSerializer`` for
|
||||
# more details. TODO: Change the param name once we change the serializer.
|
||||
block_id = definition_id
|
||||
Perform checks to validate whether a new block with `block_id` and type `block_type` can be added to
|
||||
the library with key `library_key`.
|
||||
|
||||
Returns the ContentLibrary that has the passed in `library_key` and newly created LibraryUsageLocatorV2 if
|
||||
validation successful, otherwise raises errors.
|
||||
"""
|
||||
assert isinstance(library_key, LibraryLocatorV2)
|
||||
ref = ContentLibrary.objects.get_by_key(library_key)
|
||||
if ref.type != COMPLEX:
|
||||
if block_type != ref.type:
|
||||
content_library = ContentLibrary.objects.get_by_key(library_key) # type: ignore[attr-defined]
|
||||
if content_library.type != COMPLEX:
|
||||
if block_type != content_library.type:
|
||||
raise IncompatibleTypesError(
|
||||
_('Block type "{block_type}" is not compatible with library type "{library_type}".').format(
|
||||
block_type=block_type, library_type=ref.type,
|
||||
block_type=block_type, library_type=content_library.type,
|
||||
)
|
||||
)
|
||||
|
||||
# If adding a component would take us over our max, return an error.
|
||||
component_count = authoring_api.get_all_drafts(ref.learning_package.id).count()
|
||||
component_count = authoring_api.get_all_drafts(content_library.learning_package.id).count()
|
||||
if component_count + 1 > settings.MAX_BLOCKS_PER_CONTENT_LIBRARY:
|
||||
raise BlockLimitReachedError(
|
||||
_("Library cannot have more than {} Components").format(
|
||||
@@ -768,7 +787,7 @@ def create_library_block(library_key, block_type, definition_id):
|
||||
# Ensure the XBlock type is valid and installed:
|
||||
XBlock.load_class(block_type) # Will raise an exception if invalid
|
||||
# Make sure the new ID is not taken already:
|
||||
usage_key = LibraryUsageLocatorV2(
|
||||
usage_key = LibraryUsageLocatorV2( # type: ignore[abstract]
|
||||
lib_key=library_key,
|
||||
block_type=block_type,
|
||||
usage_id=block_id,
|
||||
@@ -777,12 +796,26 @@ def create_library_block(library_key, block_type, definition_id):
|
||||
if _component_exists(usage_key):
|
||||
raise LibraryBlockAlreadyExists(f"An XBlock with ID '{usage_key}' already exists")
|
||||
|
||||
_create_component_for_block(ref, usage_key)
|
||||
return content_library, usage_key
|
||||
|
||||
|
||||
def create_library_block(library_key, block_type, definition_id, user_id=None):
|
||||
"""
|
||||
Create a new XBlock in this library of the specified type (e.g. "html").
|
||||
"""
|
||||
# It's in the serializer as ``definition_id``, but for our purposes, it's
|
||||
# the block_id. See the comments in ``LibraryXBlockCreationSerializer`` for
|
||||
# more details. TODO: Change the param name once we change the serializer.
|
||||
block_id = definition_id
|
||||
|
||||
content_library, usage_key = validate_can_add_block_to_library(library_key, block_type, block_id)
|
||||
|
||||
_create_component_for_block(content_library, usage_key, user_id)
|
||||
|
||||
# Now return the metadata about the new block:
|
||||
LIBRARY_BLOCK_CREATED.send_event(
|
||||
library_block=LibraryBlockData(
|
||||
library_key=ref.library_key,
|
||||
library_key=content_library.library_key,
|
||||
usage_key=usage_key
|
||||
)
|
||||
)
|
||||
@@ -804,6 +837,46 @@ def _component_exists(usage_key: UsageKeyV2) -> bool:
|
||||
return True
|
||||
|
||||
|
||||
def import_staged_content_from_user_clipboard(library_key: LibraryLocatorV2, user, block_id) -> XBlock:
|
||||
"""
|
||||
Create a new library block and populate it with staged content from clipboard
|
||||
|
||||
Returns the newly created library block
|
||||
"""
|
||||
from openedx.core.djangoapps.content_staging import api as content_staging_api
|
||||
if not content_staging_api:
|
||||
raise RuntimeError("The required content_staging app is not installed")
|
||||
|
||||
user_clipboard = content_staging_api.get_user_clipboard(user)
|
||||
if not user_clipboard:
|
||||
return None
|
||||
|
||||
olx_str = content_staging_api.get_staged_content_olx(user_clipboard.content.id)
|
||||
|
||||
# TODO: Handle importing over static assets
|
||||
|
||||
content_library, usage_key = validate_can_add_block_to_library(
|
||||
library_key,
|
||||
user_clipboard.content.block_type,
|
||||
block_id
|
||||
)
|
||||
|
||||
# Create component for block then populate it with clipboard data
|
||||
_create_component_for_block(content_library, usage_key, user.id)
|
||||
set_library_block_olx(usage_key, olx_str)
|
||||
|
||||
# Emit library block created event
|
||||
LIBRARY_BLOCK_CREATED.send_event(
|
||||
library_block=LibraryBlockData(
|
||||
library_key=content_library.library_key,
|
||||
usage_key=usage_key
|
||||
)
|
||||
)
|
||||
|
||||
# Now return the metadata about the new block
|
||||
return get_library_block(usage_key)
|
||||
|
||||
|
||||
def get_or_create_olx_media_type(block_type: str) -> MediaType:
|
||||
"""
|
||||
Get or create a MediaType for the block type.
|
||||
@@ -816,7 +889,7 @@ def get_or_create_olx_media_type(block_type: str) -> MediaType:
|
||||
)
|
||||
|
||||
|
||||
def _create_component_for_block(content_lib, usage_key):
|
||||
def _create_component_for_block(content_lib, usage_key, user_id=None):
|
||||
"""
|
||||
Create a Component for an XBlock type, and initialize it.
|
||||
|
||||
@@ -847,7 +920,7 @@ def _create_component_for_block(content_lib, usage_key):
|
||||
local_key=usage_key.block_id,
|
||||
title=display_name,
|
||||
created=now,
|
||||
created_by=None,
|
||||
created_by=user_id,
|
||||
)
|
||||
content = authoring_api.get_or_create_text_content(
|
||||
learning_package.id,
|
||||
@@ -951,13 +1024,13 @@ def get_allowed_block_types(library_key): # pylint: disable=unused-argument
|
||||
return info
|
||||
|
||||
|
||||
def publish_changes(library_key):
|
||||
def publish_changes(library_key, user_id=None):
|
||||
"""
|
||||
Publish all pending changes to the specified library.
|
||||
"""
|
||||
learning_package = ContentLibrary.objects.get_by_key(library_key).learning_package
|
||||
|
||||
authoring_api.publish_all_drafts(learning_package.id)
|
||||
authoring_api.publish_all_drafts(learning_package.id, published_by=user_id)
|
||||
|
||||
CONTENT_LIBRARY_UPDATED.send_event(
|
||||
content_library=ContentLibraryData(
|
||||
|
||||
@@ -36,12 +36,14 @@ class ContentLibraryMetadataSerializer(serializers.Serializer):
|
||||
org = serializers.SlugField(source="key.org")
|
||||
slug = serializers.CharField(source="key.slug", validators=(validate_unicode_slug, ))
|
||||
bundle_uuid = serializers.UUIDField(format='hex_verbose', read_only=True)
|
||||
#collection_uuid = serializers.UUIDField(format='hex_verbose', write_only=True)
|
||||
title = serializers.CharField()
|
||||
description = serializers.CharField(allow_blank=True)
|
||||
num_blocks = serializers.IntegerField(read_only=True)
|
||||
version = serializers.IntegerField(read_only=True)
|
||||
last_published = serializers.DateTimeField(format=DATETIME_FORMAT, read_only=True)
|
||||
published_by = serializers.CharField(read_only=True)
|
||||
last_draft_created = serializers.DateTimeField(format=DATETIME_FORMAT, read_only=True)
|
||||
last_draft_created_by = serializers.CharField(read_only=True)
|
||||
allow_lti = serializers.BooleanField(default=False, read_only=True)
|
||||
allow_public_learning = serializers.BooleanField(default=False)
|
||||
allow_public_read = serializers.BooleanField(default=False)
|
||||
@@ -49,6 +51,8 @@ class ContentLibraryMetadataSerializer(serializers.Serializer):
|
||||
has_unpublished_deletes = serializers.BooleanField(read_only=True)
|
||||
license = serializers.ChoiceField(choices=LICENSE_OPTIONS, default=ALL_RIGHTS_RESERVED)
|
||||
can_edit_library = serializers.SerializerMethodField()
|
||||
created = serializers.DateTimeField(format=DATETIME_FORMAT, read_only=True)
|
||||
updated = serializers.DateTimeField(format=DATETIME_FORMAT, read_only=True)
|
||||
|
||||
def get_can_edit_library(self, obj):
|
||||
"""
|
||||
@@ -175,6 +179,17 @@ class LibraryXBlockCreationSerializer(serializers.Serializer):
|
||||
# slugs at the moment, but hopefully we can change this soon.
|
||||
definition_id = serializers.CharField(validators=(validate_unicode_slug, ))
|
||||
|
||||
# Optional param specified when pasting data from clipboard instead of
|
||||
# creating new block from scratch
|
||||
staged_content = serializers.CharField(required=False)
|
||||
|
||||
|
||||
class LibraryPasteClipboardSerializer(serializers.Serializer):
|
||||
"""
|
||||
Serializer for pasting clipboard data into library
|
||||
"""
|
||||
block_id = serializers.CharField(validators=(validate_unicode_slug, ))
|
||||
|
||||
|
||||
class LibraryXBlockOlxSerializer(serializers.Serializer):
|
||||
"""
|
||||
|
||||
@@ -25,6 +25,7 @@ URL_LIB_BLOCKS = URL_LIB_DETAIL + 'blocks/' # Get the list of XBlocks in this l
|
||||
URL_LIB_TEAM = URL_LIB_DETAIL + 'team/' # Get the list of users/groups authorized to use this library
|
||||
URL_LIB_TEAM_USER = URL_LIB_TEAM + 'user/{username}/' # Add/edit/remove a user's permission to use this library
|
||||
URL_LIB_TEAM_GROUP = URL_LIB_TEAM + 'group/{group_name}/' # Add/edit/remove a group's permission to use this library
|
||||
URL_LIB_PASTE_CLIPBOARD = URL_LIB_DETAIL + 'paste_clipboard/' # Paste user clipboard (POST) containing Xblock data
|
||||
URL_LIB_BLOCK = URL_PREFIX + 'blocks/{block_key}/' # Get data about a block, or delete it
|
||||
URL_LIB_BLOCK_OLX = URL_LIB_BLOCK + 'olx/' # Get or set the OLX of the specified XBlock
|
||||
URL_LIB_BLOCK_ASSETS = URL_LIB_BLOCK + 'assets/' # List the static asset files of the specified XBlock
|
||||
@@ -284,6 +285,12 @@ class ContentLibrariesRestApiTest(APITransactionTestCase):
|
||||
url = URL_LIB_BLOCK_ASSET_FILE.format(block_key=block_key, file_name=file_name)
|
||||
return self._api('delete', url, None, expect_response)
|
||||
|
||||
def _paste_clipboard_content_in_library(self, lib_key, block_id, expect_response=200):
|
||||
""" Paste's the users clipboard content into Library """
|
||||
url = URL_LIB_PASTE_CLIPBOARD.format(lib_key=lib_key)
|
||||
data = {"block_id": block_id}
|
||||
return self._api('post', url, data, expect_response)
|
||||
|
||||
def _render_block_view(self, block_key, view_name, expect_response=200):
|
||||
"""
|
||||
Render an XBlock's view in the active application's runtime.
|
||||
|
||||
@@ -5,6 +5,7 @@ from unittest.mock import Mock, patch
|
||||
from unittest import skip
|
||||
|
||||
import ddt
|
||||
from uuid import uuid4
|
||||
from django.contrib.auth.models import Group
|
||||
from django.test.client import Client
|
||||
from organizations.models import Organization
|
||||
@@ -29,6 +30,7 @@ from openedx.core.djangoapps.content_libraries.tests.base import (
|
||||
URL_BLOCK_XBLOCK_HANDLER,
|
||||
)
|
||||
from openedx.core.djangoapps.content_libraries.constants import VIDEO, COMPLEX, PROBLEM, CC_4_BY
|
||||
from openedx.core.djangoapps.xblock import api as xblock_api
|
||||
from openedx.core.djangolib.testing.utils import skip_unless_cms
|
||||
from common.djangoapps.student.tests.factories import UserFactory
|
||||
|
||||
@@ -974,6 +976,52 @@ class ContentLibrariesTestCase(ContentLibrariesRestApiTest, OpenEdxEventsTestMix
|
||||
event_receiver.call_args.kwargs
|
||||
)
|
||||
|
||||
def test_library_paste_clipboard(self):
|
||||
"""
|
||||
Check the a new block is created in the library after pasting from clipboard.
|
||||
The content of the new block should match the content of the block in the clipboard.
|
||||
"""
|
||||
# Importing here since this was failing when tests ran in the LMS
|
||||
from openedx.core.djangoapps.content_staging.api import save_xblock_to_user_clipboard
|
||||
|
||||
# Create user to perform tests on
|
||||
author = UserFactory.create(username="Author", email="author@example.com")
|
||||
with self.as_user(author):
|
||||
lib = self._create_library(
|
||||
slug="test_lib_paste_clipboard",
|
||||
title="Paste Clipboard Test Library",
|
||||
description="Testing pasting clipboard in library"
|
||||
)
|
||||
lib_id = lib["id"]
|
||||
|
||||
# Add a 'problem' XBlock to the library:
|
||||
block_data = self._add_block_to_library(lib_id, "problem", "problem1")
|
||||
|
||||
# Get the usage_key of the created block
|
||||
library_key = LibraryLocatorV2.from_string(lib_id)
|
||||
usage_key = LibraryUsageLocatorV2(
|
||||
lib_key=library_key,
|
||||
block_type="problem",
|
||||
usage_id="problem1"
|
||||
)
|
||||
|
||||
# Get the XBlock created in the previous step
|
||||
block = xblock_api.load_block(usage_key, user=author)
|
||||
|
||||
# Copy the block to the user's clipboard
|
||||
save_xblock_to_user_clipboard(block, author.id)
|
||||
|
||||
# Paste the content of the clipboard into the library
|
||||
pasted_block_id = str(uuid4())
|
||||
paste_data = self._paste_clipboard_content_in_library(lib_id, pasted_block_id)
|
||||
|
||||
# Check that the new block was created after the paste and it's content matches
|
||||
# the the block in the clipboard
|
||||
self.assertDictContainsEntries(self._get_library_block(paste_data["id"]), {
|
||||
**block_data,
|
||||
"id": f"lb:CL-TEST:test_lib_paste_clipboard:problem:{pasted_block_id}",
|
||||
})
|
||||
|
||||
|
||||
@ddt.ddt
|
||||
class ContentLibraryXBlockValidationTest(APITestCase):
|
||||
|
||||
@@ -43,6 +43,8 @@ urlpatterns = [
|
||||
path('team/group/<str:group_name>/', views.LibraryTeamGroupView.as_view()),
|
||||
# Import blocks into this library.
|
||||
path('import_blocks/', include(import_blocks_router.urls)),
|
||||
# Paste contents of clipboard into library
|
||||
path('paste_clipboard/', views.LibraryPasteClipboardView.as_view()),
|
||||
])),
|
||||
path('blocks/<str:usage_key_str>/', include([
|
||||
# Get metadata about a specific XBlock in this library, or delete the block:
|
||||
|
||||
@@ -112,6 +112,7 @@ from openedx.core.djangoapps.content_libraries.serializers import (
|
||||
LibraryXBlockStaticFileSerializer,
|
||||
LibraryXBlockStaticFilesSerializer,
|
||||
ContentLibraryAddPermissionByEmailSerializer,
|
||||
LibraryPasteClipboardSerializer,
|
||||
)
|
||||
import openedx.core.djangoapps.site_configuration.helpers as configuration_helpers
|
||||
from openedx.core.lib.api.view_utils import view_auth_classes
|
||||
@@ -487,7 +488,7 @@ class LibraryCommitView(APIView):
|
||||
"""
|
||||
key = LibraryLocatorV2.from_string(lib_key_str)
|
||||
api.require_permission_for_library_key(key, request.user, permissions.CAN_EDIT_THIS_CONTENT_LIBRARY)
|
||||
api.publish_changes(key)
|
||||
api.publish_changes(key, request.user.id)
|
||||
return Response({})
|
||||
|
||||
@convert_exceptions
|
||||
@@ -502,6 +503,34 @@ class LibraryCommitView(APIView):
|
||||
return Response({})
|
||||
|
||||
|
||||
@method_decorator(non_atomic_requests, name="dispatch")
|
||||
@view_auth_classes()
|
||||
class LibraryPasteClipboardView(GenericAPIView):
|
||||
"""
|
||||
Paste content of clipboard into Library.
|
||||
"""
|
||||
@convert_exceptions
|
||||
def post(self, request, lib_key_str):
|
||||
"""
|
||||
Import the contents of the user's clipboard and paste them into the Library
|
||||
"""
|
||||
library_key = LibraryLocatorV2.from_string(lib_key_str)
|
||||
api.require_permission_for_library_key(library_key, request.user, permissions.CAN_EDIT_THIS_CONTENT_LIBRARY)
|
||||
serializer = LibraryPasteClipboardSerializer(data=request.data)
|
||||
serializer.is_valid(raise_exception=True)
|
||||
|
||||
try:
|
||||
result = api.import_staged_content_from_user_clipboard(
|
||||
library_key, request.user, **serializer.validated_data
|
||||
)
|
||||
except api.IncompatibleTypesError as err:
|
||||
raise ValidationError( # lint-amnesty, pylint: disable=raise-missing-from
|
||||
detail={'block_type': str(err)},
|
||||
)
|
||||
|
||||
return Response(LibraryXBlockMetadataSerializer(result).data)
|
||||
|
||||
|
||||
@method_decorator(non_atomic_requests, name="dispatch")
|
||||
@view_auth_classes()
|
||||
class LibraryBlocksView(GenericAPIView):
|
||||
@@ -556,7 +585,7 @@ class LibraryBlocksView(GenericAPIView):
|
||||
|
||||
# Create a new regular top-level block:
|
||||
try:
|
||||
result = api.create_library_block(library_key, **serializer.validated_data)
|
||||
result = api.create_library_block(library_key, user_id=request.user.id, **serializer.validated_data)
|
||||
except api.IncompatibleTypesError as err:
|
||||
raise ValidationError( # lint-amnesty, pylint: disable=raise-missing-from
|
||||
detail={'block_type': str(err)},
|
||||
|
||||
@@ -10,12 +10,14 @@ from django.utils.decorators import method_decorator
|
||||
import edx_api_doc_tools as apidocs
|
||||
from opaque_keys import InvalidKeyError
|
||||
from opaque_keys.edx.keys import UsageKey
|
||||
from opaque_keys.edx.locator import CourseLocator
|
||||
from opaque_keys.edx.locator import CourseLocator, LibraryLocatorV2
|
||||
from rest_framework.exceptions import NotFound, PermissionDenied, ValidationError
|
||||
from rest_framework.response import Response
|
||||
from rest_framework.views import APIView
|
||||
from common.djangoapps.student.auth import has_studio_read_access
|
||||
|
||||
from openedx.core.djangoapps.content_libraries import api as lib_api
|
||||
from openedx.core.djangoapps.xblock import api as xblock_api
|
||||
from openedx.core.lib.api.view_utils import view_auth_classes
|
||||
from xmodule.modulestore.django import modulestore
|
||||
from xmodule.modulestore.exceptions import ItemNotFoundError
|
||||
@@ -89,18 +91,31 @@ class ClipboardEndpoint(APIView):
|
||||
if usage_key.block_type in ('course', 'chapter', 'sequential'):
|
||||
raise ValidationError('Requested XBlock tree is too large')
|
||||
course_key = usage_key.context_key
|
||||
if not isinstance(course_key, CourseLocator):
|
||||
# In the future, we'll support libraries too but for now we don't.
|
||||
raise ValidationError('Invalid usage key: not a modulestore course')
|
||||
# Make sure the user has permission on that course
|
||||
if not has_studio_read_access(request.user, course_key):
|
||||
raise PermissionDenied("You must be a member of the course team in Studio to export OLX using this API.")
|
||||
|
||||
# Load the block and copy it to the user's clipboard
|
||||
try:
|
||||
block = modulestore().get_item(usage_key)
|
||||
if isinstance(course_key, CourseLocator):
|
||||
# Make sure the user has permission on that course
|
||||
if not has_studio_read_access(request.user, course_key):
|
||||
raise PermissionDenied(
|
||||
"You must be a member of the course team in Studio to export OLX using this API."
|
||||
)
|
||||
block = modulestore().get_item(usage_key)
|
||||
|
||||
elif isinstance(course_key, LibraryLocatorV2):
|
||||
lib_api.require_permission_for_library_key(
|
||||
course_key,
|
||||
request.user,
|
||||
lib_api.permissions.CAN_VIEW_THIS_CONTENT_LIBRARY
|
||||
)
|
||||
block = xblock_api.load_block(usage_key, user=None)
|
||||
|
||||
else:
|
||||
raise ValidationError("Invalid usage_key for the content.")
|
||||
|
||||
except ItemNotFoundError as exc:
|
||||
raise NotFound("The requested usage key does not exist.") from exc
|
||||
|
||||
clipboard = api.save_xblock_to_user_clipboard(block=block, user_id=request.user.id)
|
||||
|
||||
# Return the current clipboard exactly as if GET was called:
|
||||
|
||||
@@ -441,7 +441,7 @@ class TestContentTagChildrenExport(TaggedCourseMixin): # type: ignore[misc]
|
||||
"""
|
||||
Test if we can export a library
|
||||
"""
|
||||
with self.assertNumQueries(11):
|
||||
with self.assertNumQueries(8):
|
||||
tagged_library = build_object_tree_with_objecttags(self.library.key, self.all_library_object_tags)
|
||||
|
||||
assert tagged_library == self.expected_library_tagged_xblock
|
||||
|
||||
26
openedx/core/djangoapps/contentserver/test/test_views.py
Normal file
26
openedx/core/djangoapps/contentserver/test/test_views.py
Normal file
@@ -0,0 +1,26 @@
|
||||
"""
|
||||
Tests for the view version of course asset serving.
|
||||
"""
|
||||
|
||||
import ddt
|
||||
from django.test import TestCase
|
||||
from django.urls import resolve
|
||||
|
||||
|
||||
@ddt.ddt
|
||||
class UrlsTest(TestCase):
|
||||
"""
|
||||
Tests for ensuring that the urlpatterns registered to the view are
|
||||
appropriate for the URLs that the middleware historically handled.
|
||||
"""
|
||||
|
||||
@ddt.data(
|
||||
'/c4x/edX/Open_DemoX/asset/images_course_image.jpg',
|
||||
'/asset-v1:edX+DemoX.1+2T2019+type@asset+block/DemoX-poster.jpg',
|
||||
'/assets/courseware/v1/0123456789abcdef0123456789abcdef/asset-v1:edX+FAKE101+2024+type@asset+block/HW1.png',
|
||||
)
|
||||
def test_sample_urls(self, sample_url):
|
||||
"""
|
||||
Regression test -- c4x URL was previously incorrect in urls.py.
|
||||
"""
|
||||
assert resolve(sample_url).view_name == 'openedx.core.djangoapps.contentserver.views.course_assets_view'
|
||||
@@ -2,7 +2,7 @@
|
||||
URL patterns for course asset serving.
|
||||
"""
|
||||
|
||||
from django.urls import path, re_path
|
||||
from django.urls import re_path
|
||||
|
||||
from . import views
|
||||
|
||||
@@ -10,7 +10,7 @@ from . import views
|
||||
# components of the URLs. That's because the view itself is separately
|
||||
# parsing the paths, for historical reasons. See docstring on views.py.
|
||||
urlpatterns = [
|
||||
path("c4x/", views.course_assets_view),
|
||||
re_path("^c4x/", views.course_assets_view),
|
||||
re_path("^asset-v1:", views.course_assets_view),
|
||||
re_path("^assets/courseware/", views.course_assets_view),
|
||||
]
|
||||
|
||||
@@ -7,6 +7,7 @@ from .email_notifications import EmailCadence
|
||||
from common.djangoapps.student.roles import CourseInstructorRole, CourseStaffRole
|
||||
from .utils import find_app_in_normalized_apps, find_pref_in_normalized_prefs
|
||||
from ..django_comment_common.models import FORUM_ROLE_ADMINISTRATOR, FORUM_ROLE_MODERATOR, FORUM_ROLE_COMMUNITY_TA
|
||||
from .notification_content import get_notification_type_content_function
|
||||
|
||||
FILTER_AUDIT_EXPIRED_USERS_WITH_NO_ROLE = 'filter_audit_expired_users_with_no_role'
|
||||
|
||||
@@ -109,8 +110,9 @@ COURSE_NOTIFICATION_TYPES = {
|
||||
'is_core': True,
|
||||
'info': '',
|
||||
'non_editable': [],
|
||||
'content_template': _('<{p}><{strong}>{replier_name}</{strong}> commented on {author_name}\'s response in '
|
||||
'a post you’re following <{strong}>{post_title}</{strong}></{p}>'),
|
||||
'content_template': _('<{p}><{strong}>{replier_name}</{strong}> commented on <{strong}>{author_name}'
|
||||
'</{strong}> response in a post you’re following <{strong}>{post_title}'
|
||||
'</{strong}></{p}>'),
|
||||
'content_context': {
|
||||
'post_title': 'Post title',
|
||||
'author_name': 'author name',
|
||||
@@ -169,13 +171,13 @@ COURSE_NOTIFICATION_TYPES = {
|
||||
'email_template': '',
|
||||
'filters': [FILTER_AUDIT_EXPIRED_USERS_WITH_NO_ROLE]
|
||||
},
|
||||
'course_update': {
|
||||
'course_updates': {
|
||||
'notification_app': 'updates',
|
||||
'name': 'course_update',
|
||||
'name': 'course_updates',
|
||||
'is_core': False,
|
||||
'info': '',
|
||||
'web': True,
|
||||
'email': True,
|
||||
'email': False,
|
||||
'push': True,
|
||||
'email_cadence': EmailCadence.DAILY,
|
||||
'non_editable': [],
|
||||
@@ -197,7 +199,7 @@ COURSE_NOTIFICATION_TYPES = {
|
||||
'push': False,
|
||||
'email_cadence': EmailCadence.DAILY,
|
||||
'non_editable': [],
|
||||
'content_template': _('<{p}>You have a new open response submission awaiting for review for : '
|
||||
'content_template': _('<{p}>You have a new open response submission awaiting for review for '
|
||||
'<{strong}>{ora_name}</{strong}></{p}>'),
|
||||
'content_context': {
|
||||
'ora_name': 'Name of ORA in course',
|
||||
@@ -465,8 +467,13 @@ def get_notification_content(notification_type, context):
|
||||
'strong': 'strong',
|
||||
'p': 'p',
|
||||
}
|
||||
content_function = get_notification_type_content_function(notification_type)
|
||||
if notification_type == 'course_update':
|
||||
notification_type = 'course_updates'
|
||||
notification_type = NotificationTypeManager().notification_types.get(notification_type, None)
|
||||
if notification_type:
|
||||
if content_function:
|
||||
return content_function(notification_type, context)
|
||||
notification_type_content_template = notification_type.get('content_template', None)
|
||||
if notification_type_content_template:
|
||||
return notification_type_content_template.format(**context, **html_tags_context)
|
||||
|
||||
@@ -70,10 +70,12 @@ def get_user_preferences_for_courses(course_ids, user):
|
||||
return new_preferences
|
||||
|
||||
|
||||
def send_digest_email_to_user(user, cadence_type, course_language='en', courses_data=None):
|
||||
def send_digest_email_to_user(user, cadence_type, start_date, end_date, course_language='en', courses_data=None):
|
||||
"""
|
||||
Send [cadence_type] email to user.
|
||||
Cadence Type can be EmailCadence.DAILY or EmailCadence.WEEKLY
|
||||
start_date: Datetime object
|
||||
end_date: Datetime object
|
||||
"""
|
||||
if cadence_type not in [EmailCadence.DAILY, EmailCadence.WEEKLY]:
|
||||
raise ValueError('Invalid cadence_type')
|
||||
@@ -81,7 +83,6 @@ def send_digest_email_to_user(user, cadence_type, course_language='en', courses_
|
||||
if not is_email_notification_flag_enabled(user):
|
||||
logger.info(f'<Email Cadence> Flag disabled for {user.username} ==Temp Log==')
|
||||
return
|
||||
start_date, end_date = get_start_end_date(cadence_type)
|
||||
notifications = Notification.objects.filter(user=user, email=True,
|
||||
created__gte=start_date, created__lte=end_date)
|
||||
if not notifications:
|
||||
@@ -115,6 +116,7 @@ def send_digest_email_to_all_users(cadence_type):
|
||||
logger.info(f'<Email Cadence> Sending cadence email of type {cadence_type}')
|
||||
users = get_audience_for_cadence_email(cadence_type)
|
||||
courses_data = {}
|
||||
start_date, end_date = get_start_end_date(cadence_type)
|
||||
logger.info(f'<Email Cadence> Email Cadence Audience {len(users)}')
|
||||
for user in users:
|
||||
send_digest_email_to_user(user, cadence_type, courses_data=courses_data)
|
||||
send_digest_email_to_user(user, cadence_type, start_date, end_date, courses_data=courses_data)
|
||||
|
||||
@@ -16,6 +16,7 @@ from openedx.core.djangoapps.notifications.email.tasks import (
|
||||
send_digest_email_to_all_users,
|
||||
send_digest_email_to_user
|
||||
)
|
||||
from openedx.core.djangoapps.notifications.email.utils import get_start_end_date
|
||||
from openedx.core.djangoapps.notifications.models import CourseNotificationPreference
|
||||
from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase
|
||||
from xmodule.modulestore.tests.factories import CourseFactory
|
||||
@@ -42,8 +43,9 @@ class TestEmailDigestForUser(ModuleStoreTestCase):
|
||||
"""
|
||||
Tests email is sent iff waffle flag is enabled
|
||||
"""
|
||||
start_date, end_date = get_start_end_date(EmailCadence.DAILY)
|
||||
with override_waffle_flag(ENABLE_EMAIL_NOTIFICATIONS, True):
|
||||
send_digest_email_to_user(self.user, EmailCadence.DAILY)
|
||||
send_digest_email_to_user(self.user, EmailCadence.DAILY, start_date, end_date)
|
||||
assert not mock_func.called
|
||||
|
||||
@ddt.data(True, False)
|
||||
@@ -54,8 +56,9 @@ class TestEmailDigestForUser(ModuleStoreTestCase):
|
||||
"""
|
||||
created_date = datetime.datetime.now() - datetime.timedelta(days=1)
|
||||
create_notification(self.user, self.course.id, created=created_date)
|
||||
start_date, end_date = get_start_end_date(EmailCadence.DAILY)
|
||||
with override_waffle_flag(ENABLE_EMAIL_NOTIFICATIONS, flag_value):
|
||||
send_digest_email_to_user(self.user, EmailCadence.DAILY)
|
||||
send_digest_email_to_user(self.user, EmailCadence.DAILY, start_date, end_date)
|
||||
assert mock_func.called is flag_value
|
||||
|
||||
@patch('edx_ace.ace.send')
|
||||
@@ -63,9 +66,10 @@ class TestEmailDigestForUser(ModuleStoreTestCase):
|
||||
"""
|
||||
Tests email is not sent if notification is created on next day
|
||||
"""
|
||||
create_notification(self.user, self.course.id)
|
||||
start_date, end_date = get_start_end_date(EmailCadence.DAILY)
|
||||
create_notification(self.user, self.course.id, created=end_date + datetime.timedelta(minutes=2))
|
||||
with override_waffle_flag(ENABLE_EMAIL_NOTIFICATIONS, True):
|
||||
send_digest_email_to_user(self.user, EmailCadence.DAILY)
|
||||
send_digest_email_to_user(self.user, EmailCadence.DAILY, start_date, end_date)
|
||||
assert not mock_func.called
|
||||
|
||||
@patch('edx_ace.ace.send')
|
||||
@@ -73,12 +77,35 @@ class TestEmailDigestForUser(ModuleStoreTestCase):
|
||||
"""
|
||||
Tests email is not sent if notification is created day before yesterday
|
||||
"""
|
||||
created_date = datetime.datetime.now() - datetime.timedelta(days=2)
|
||||
start_date, end_date = get_start_end_date(EmailCadence.DAILY)
|
||||
created_date = datetime.datetime.now() - datetime.timedelta(days=1, minutes=18)
|
||||
create_notification(self.user, self.course.id, created=created_date)
|
||||
with override_waffle_flag(ENABLE_EMAIL_NOTIFICATIONS, True):
|
||||
send_digest_email_to_user(self.user, EmailCadence.DAILY)
|
||||
send_digest_email_to_user(self.user, EmailCadence.DAILY, start_date, end_date)
|
||||
assert not mock_func.called
|
||||
|
||||
@ddt.data(
|
||||
(EmailCadence.DAILY, datetime.datetime.now() - datetime.timedelta(days=1, minutes=30), False),
|
||||
(EmailCadence.DAILY, datetime.datetime.now() - datetime.timedelta(minutes=10), True),
|
||||
(EmailCadence.DAILY, datetime.datetime.now() - datetime.timedelta(days=1), True),
|
||||
(EmailCadence.DAILY, datetime.datetime.now() + datetime.timedelta(minutes=20), False),
|
||||
(EmailCadence.WEEKLY, datetime.datetime.now() - datetime.timedelta(days=7, minutes=30), False),
|
||||
(EmailCadence.WEEKLY, datetime.datetime.now() - datetime.timedelta(days=7), True),
|
||||
(EmailCadence.WEEKLY, datetime.datetime.now() - datetime.timedelta(minutes=20), True),
|
||||
(EmailCadence.WEEKLY, datetime.datetime.now() + datetime.timedelta(minutes=20), False),
|
||||
)
|
||||
@ddt.unpack
|
||||
@patch('edx_ace.ace.send')
|
||||
def test_notification_content(self, cadence_type, created_time, notification_created, mock_func):
|
||||
"""
|
||||
Tests email only contains notification created within date
|
||||
"""
|
||||
start_date, end_date = get_start_end_date(cadence_type)
|
||||
create_notification(self.user, self.course.id, created=created_time)
|
||||
with override_waffle_flag(ENABLE_EMAIL_NOTIFICATIONS, True):
|
||||
send_digest_email_to_user(self.user, EmailCadence.DAILY, start_date, end_date)
|
||||
assert mock_func.called is notification_created
|
||||
|
||||
|
||||
@ddt.ddt
|
||||
class TestEmailDigestAudience(ModuleStoreTestCase):
|
||||
@@ -146,10 +173,11 @@ class TestEmailDigestAudience(ModuleStoreTestCase):
|
||||
"""
|
||||
Tests email is sent only when notifications with email=True exists
|
||||
"""
|
||||
created_date = datetime.datetime.now() - datetime.timedelta(days=1)
|
||||
start_date, end_date = get_start_end_date(EmailCadence.DAILY)
|
||||
created_date = datetime.datetime.now() - datetime.timedelta(hours=23, minutes=59)
|
||||
create_notification(self.user, self.course.id, created=created_date, email=email_value)
|
||||
with override_waffle_flag(ENABLE_EMAIL_NOTIFICATIONS, True):
|
||||
send_digest_email_to_user(self.user, EmailCadence.DAILY)
|
||||
send_digest_email_to_user(self.user, EmailCadence.DAILY, start_date, end_date)
|
||||
assert mock_func.called is email_value
|
||||
|
||||
|
||||
@@ -166,7 +194,7 @@ class TestPreferences(ModuleStoreTestCase):
|
||||
self.user = UserFactory()
|
||||
self.course = CourseFactory.create(display_name='test course', run="Testing_course")
|
||||
self.preference = CourseNotificationPreference.objects.create(user=self.user, course_id=self.course.id)
|
||||
created_date = datetime.datetime.now() - datetime.timedelta(days=1)
|
||||
created_date = datetime.datetime.now() - datetime.timedelta(hours=23)
|
||||
create_notification(self.user, self.course.id, notification_type='new_discussion_post', created=created_date)
|
||||
|
||||
@patch('edx_ace.ace.send')
|
||||
@@ -174,13 +202,14 @@ class TestPreferences(ModuleStoreTestCase):
|
||||
"""
|
||||
Tests email is send for digest notification preference
|
||||
"""
|
||||
start_date, end_date = get_start_end_date(EmailCadence.DAILY)
|
||||
config = self.preference.notification_preference_config
|
||||
types = config['discussion']['notification_types']
|
||||
types['new_discussion_post']['email_cadence'] = EmailCadence.DAILY
|
||||
types['new_discussion_post']['email'] = True
|
||||
self.preference.save()
|
||||
with override_waffle_flag(ENABLE_EMAIL_NOTIFICATIONS, True):
|
||||
send_digest_email_to_user(self.user, EmailCadence.DAILY)
|
||||
send_digest_email_to_user(self.user, EmailCadence.DAILY, start_date, end_date)
|
||||
assert mock_func.called
|
||||
|
||||
@ddt.data(True, False)
|
||||
@@ -189,13 +218,14 @@ class TestPreferences(ModuleStoreTestCase):
|
||||
"""
|
||||
Tests email is sent iff preference value is True
|
||||
"""
|
||||
start_date, end_date = get_start_end_date(EmailCadence.DAILY)
|
||||
config = self.preference.notification_preference_config
|
||||
types = config['discussion']['notification_types']
|
||||
types['new_discussion_post']['email_cadence'] = EmailCadence.DAILY
|
||||
types['new_discussion_post']['email'] = pref_value
|
||||
self.preference.save()
|
||||
with override_waffle_flag(ENABLE_EMAIL_NOTIFICATIONS, True):
|
||||
send_digest_email_to_user(self.user, EmailCadence.DAILY)
|
||||
send_digest_email_to_user(self.user, EmailCadence.DAILY, start_date, end_date)
|
||||
assert mock_func.called is pref_value
|
||||
|
||||
@patch('edx_ace.ace.send')
|
||||
@@ -203,10 +233,11 @@ class TestPreferences(ModuleStoreTestCase):
|
||||
"""
|
||||
Tests email is not send if digest notification preference doesnot match
|
||||
"""
|
||||
start_date, end_date = get_start_end_date(EmailCadence.DAILY)
|
||||
config = self.preference.notification_preference_config
|
||||
types = config['discussion']['notification_types']
|
||||
types['new_discussion_post']['email_cadence'] = EmailCadence.WEEKLY
|
||||
self.preference.save()
|
||||
with override_waffle_flag(ENABLE_EMAIL_NOTIFICATIONS, True):
|
||||
send_digest_email_to_user(self.user, EmailCadence.DAILY)
|
||||
send_digest_email_to_user(self.user, EmailCadence.DAILY, start_date, end_date)
|
||||
assert not mock_func.called
|
||||
|
||||
@@ -70,7 +70,7 @@ class TestUtilFunctions(ModuleStoreTestCase):
|
||||
"""
|
||||
Notification.objects.all().delete()
|
||||
create_notification(self.user, self.course.id, app_name='discussion', notification_type='new_comment')
|
||||
create_notification(self.user, self.course.id, app_name='updates', notification_type='course_update')
|
||||
create_notification(self.user, self.course.id, app_name='updates', notification_type='course_updates')
|
||||
app_dict = create_app_notifications_dict(Notification.objects.all())
|
||||
assert len(app_dict.keys()) == 2
|
||||
for key in ['discussion', 'updates']:
|
||||
@@ -130,7 +130,7 @@ class TestContextFunctions(ModuleStoreTestCase):
|
||||
discussion_notification = create_notification(self.user, self.course.id, app_name='discussion',
|
||||
notification_type='new_comment')
|
||||
update_notification = create_notification(self.user, self.course.id, app_name='updates',
|
||||
notification_type='course_update')
|
||||
notification_type='course_updates')
|
||||
app_dict = create_app_notifications_dict(Notification.objects.all())
|
||||
end_date = datetime.datetime(2024, 3, 24, 12, 0)
|
||||
params = {
|
||||
|
||||
@@ -7,7 +7,6 @@ import json
|
||||
from django.conf import settings
|
||||
from django.contrib.auth import get_user_model
|
||||
from django.shortcuts import get_object_or_404
|
||||
from django.urls import reverse
|
||||
from pytz import utc
|
||||
from waffle import get_waffle_flag_model # pylint: disable=invalid-django-waffle-import
|
||||
|
||||
@@ -20,7 +19,10 @@ from openedx.core.djangoapps.notifications.base_notification import (
|
||||
)
|
||||
from openedx.core.djangoapps.notifications.config.waffle import ENABLE_EMAIL_NOTIFICATIONS
|
||||
from openedx.core.djangoapps.notifications.email_notifications import EmailCadence
|
||||
from openedx.core.djangoapps.notifications.models import CourseNotificationPreference
|
||||
from openedx.core.djangoapps.notifications.models import (
|
||||
CourseNotificationPreference,
|
||||
get_course_notification_preference_config_version
|
||||
)
|
||||
from xmodule.modulestore.django import modulestore
|
||||
|
||||
from .notification_icons import NotificationTypeIcons
|
||||
@@ -71,15 +73,7 @@ def get_unsubscribe_link(username, patch):
|
||||
"""
|
||||
encrypted_username = encrypt_string(username)
|
||||
encrypted_patch = encrypt_object(patch)
|
||||
kwargs = {
|
||||
'username': encrypted_username,
|
||||
'patch': encrypted_patch
|
||||
}
|
||||
relative_url = reverse('preference_update_from_encrypted_username_view', kwargs=kwargs)
|
||||
protocol = 'https://'
|
||||
if settings.DEBUG:
|
||||
protocol = 'http://'
|
||||
return f"{protocol}{settings.LMS_BASE}{relative_url}"
|
||||
return f"{settings.LEARNING_MICROFRONTEND_URL}/preferences-unsubscribe/{encrypted_username}/{encrypted_patch}"
|
||||
|
||||
|
||||
def create_email_template_context(username):
|
||||
@@ -171,13 +165,10 @@ def get_start_end_date(cadence_type):
|
||||
"""
|
||||
if cadence_type not in [EmailCadence.DAILY, EmailCadence.WEEKLY]:
|
||||
raise ValueError('Invalid cadence_type')
|
||||
date_today = datetime.datetime.now()
|
||||
yesterday = date_today - datetime.timedelta(days=1)
|
||||
end_date = datetime.datetime.combine(yesterday, datetime.time.max)
|
||||
start_date = end_date
|
||||
end_date = datetime.datetime.now()
|
||||
start_date = end_date - datetime.timedelta(days=1, minutes=15)
|
||||
if cadence_type == EmailCadence.WEEKLY:
|
||||
start_date = end_date - datetime.timedelta(days=6)
|
||||
start_date = datetime.datetime.combine(start_date, datetime.time.min)
|
||||
start_date = start_date - datetime.timedelta(days=6)
|
||||
return utc.localize(start_date), utc.localize(end_date)
|
||||
|
||||
|
||||
@@ -366,6 +357,14 @@ def update_user_preferences_from_patch(encrypted_username, encrypted_patch):
|
||||
return COURSE_NOTIFICATION_APPS[app_name]['core_email_cadence']
|
||||
return COURSE_NOTIFICATION_TYPES[notification_type]['email_cadence']
|
||||
|
||||
def get_updated_preference(pref):
|
||||
"""
|
||||
Update preference if config version doesn't match
|
||||
"""
|
||||
if pref.config_version != get_course_notification_preference_config_version():
|
||||
pref = pref.get_user_course_preference(pref.user_id, pref.course_id)
|
||||
return pref
|
||||
|
||||
course_ids = CourseEnrollment.objects.filter(user=user).values_list('course_id', flat=True)
|
||||
CourseNotificationPreference.objects.bulk_create(
|
||||
[
|
||||
@@ -378,6 +377,7 @@ def update_user_preferences_from_patch(encrypted_username, encrypted_patch):
|
||||
|
||||
# pylint: disable=too-many-nested-blocks
|
||||
for preference in preferences:
|
||||
preference = get_updated_preference(preference)
|
||||
preference_json = preference.notification_preference_config
|
||||
for app_name, app_prefs in preference_json.items():
|
||||
if not is_name_match(app_name, app_value):
|
||||
|
||||
@@ -23,7 +23,7 @@ NOTIFICATION_CHANNELS = ['web', 'push', 'email']
|
||||
ADDITIONAL_NOTIFICATION_CHANNEL_SETTINGS = ['email_cadence']
|
||||
|
||||
# Update this version when there is a change to any course specific notification type or app.
|
||||
COURSE_NOTIFICATION_CONFIG_VERSION = 10
|
||||
COURSE_NOTIFICATION_CONFIG_VERSION = 11
|
||||
|
||||
|
||||
def get_course_notification_preference_config():
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
"""
|
||||
Helper functions for overriding notification content for given notification type.
|
||||
"""
|
||||
|
||||
|
||||
def get_notification_type_content_function(notification_type):
|
||||
"""
|
||||
Returns the content function for the given notification if it exists.
|
||||
"""
|
||||
try:
|
||||
return globals()[f"get_{notification_type}_notification_content"]
|
||||
except KeyError:
|
||||
return None
|
||||
|
||||
|
||||
def get_notification_content_with_author_pronoun(notification_type, context):
|
||||
"""
|
||||
Helper function to get notification content with author's pronoun.
|
||||
"""
|
||||
html_tags_context = {
|
||||
'strong': 'strong',
|
||||
'p': 'p',
|
||||
}
|
||||
notification_type_content_template = notification_type.get('content_template', None)
|
||||
if 'author_pronoun' in context:
|
||||
context['author_name'] = context['author_pronoun']
|
||||
if notification_type_content_template:
|
||||
return notification_type_content_template.format(**context, **html_tags_context)
|
||||
return ''
|
||||
|
||||
|
||||
# Returns notification content for the new_comment notification.
|
||||
get_new_comment_notification_content = get_notification_content_with_author_pronoun
|
||||
# Returns notification content for the comment_on_followed_post notification.
|
||||
get_comment_on_followed_post_notification_content = get_notification_content_with_author_pronoun
|
||||
@@ -33,7 +33,7 @@
|
||||
</td>
|
||||
<td class="notification-content" width="100%" align="left" valign="top" style=" padding: 1rem 1rem 1rem 0.5rem">
|
||||
<p style="font-size: 0.875rem; font-weight:400; line-height:24px; color:#454545; margin: 0;">
|
||||
{{ notification.content | safe }}
|
||||
{{ notification.content | truncatechars_html:600 | safe }}
|
||||
</p>
|
||||
<p style="height: 0.5rem; margin: 0"></p>
|
||||
<p style="color:#707070; margin: 0">
|
||||
|
||||
@@ -38,7 +38,7 @@
|
||||
Notification Settings
|
||||
</a>
|
||||
<a href="{{unsubscribe_url}}" rel="noopener noreferrer" target="_blank" style="color: black; margin-left: 1rem">
|
||||
Unsubscribe
|
||||
Unsubscribe from email digest for learning activity
|
||||
</a>
|
||||
</p>
|
||||
<p>
|
||||
|
||||
@@ -5,6 +5,13 @@
|
||||
style="background: #00262b; color: white; width: 100%; padding: 1.5rem"
|
||||
>
|
||||
<tbody>
|
||||
<tr align="right">
|
||||
<td>
|
||||
<a href="{{unsubscribe_url}}" rel="noopener noreferrer" target="_blank" style="color: white; text-decoration: none; font-size: 12px; line-height: 10px">
|
||||
Unsubscribe
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr align="center">
|
||||
<td>
|
||||
<img src="{{ logo_url }}" style="width: 64px" height="auto" alt="logo_url" />
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>{{ _("Email Digest Preferences Updated") }}</title>
|
||||
</head>
|
||||
<body>
|
||||
<script>
|
||||
alert('{{ _("You have successfully unsubscribed from email digest for learning activity") }}');
|
||||
window.location.replace("{{ notification_preferences_url }}");
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -390,7 +390,7 @@ class TestDeleteNotificationTask(ModuleStoreTestCase):
|
||||
"""
|
||||
assert not Notification.objects.all()
|
||||
create_notification(self.user, self.course_1.id, app_name='discussion', notification_type='new_comment')
|
||||
create_notification(self.user, self.course_1.id, app_name='updates', notification_type='course_update')
|
||||
create_notification(self.user, self.course_1.id, app_name='updates', notification_type='course_updates')
|
||||
delete_notifications({'app_name': 'discussion'})
|
||||
assert not Notification.objects.filter(app_name='discussion')
|
||||
assert Notification.objects.filter(app_name='updates')
|
||||
|
||||
@@ -28,9 +28,13 @@ from openedx.core.djangoapps.django_comment_common.models import (
|
||||
)
|
||||
from openedx.core.djangoapps.notifications.config.waffle import ENABLE_NOTIFICATIONS
|
||||
from openedx.core.djangoapps.notifications.email_notifications import EmailCadence
|
||||
from openedx.core.djangoapps.notifications.models import CourseNotificationPreference, Notification
|
||||
from openedx.core.djangoapps.notifications.models import (
|
||||
CourseNotificationPreference,
|
||||
Notification,
|
||||
get_course_notification_preference_config_version
|
||||
)
|
||||
from openedx.core.djangoapps.notifications.serializers import NotificationCourseEnrollmentSerializer
|
||||
from openedx.core.djangoapps.notifications.email.utils import get_unsubscribe_link
|
||||
from openedx.core.djangoapps.notifications.email.utils import encrypt_object, encrypt_string
|
||||
from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase
|
||||
from xmodule.modulestore.tests.factories import CourseFactory
|
||||
|
||||
@@ -275,9 +279,9 @@ class UserNotificationPreferenceAPITest(ModuleStoreTestCase):
|
||||
'enabled': True,
|
||||
'core_notification_types': [],
|
||||
'notification_types': {
|
||||
'course_update': {
|
||||
'course_updates': {
|
||||
'web': True,
|
||||
'email': True,
|
||||
'email': False,
|
||||
'push': True,
|
||||
'email_cadence': 'Daily',
|
||||
'info': ''
|
||||
@@ -910,7 +914,13 @@ class UpdatePreferenceFromEncryptedDataView(ModuleStoreTestCase):
|
||||
"""
|
||||
Tests if preference is updated when url is hit
|
||||
"""
|
||||
url = get_unsubscribe_link(self.user.username, {'channel': 'email', 'value': False})
|
||||
user_hash = encrypt_string(self.user.username)
|
||||
patch_hash = encrypt_object({'channel': 'email', 'value': False})
|
||||
url_params = {
|
||||
"username": user_hash,
|
||||
"patch": patch_hash
|
||||
}
|
||||
url = reverse("preference_update_from_encrypted_username_view", kwargs=url_params)
|
||||
func = getattr(self.client, request_type)
|
||||
response = func(url)
|
||||
assert response.status_code == status.HTTP_200_OK
|
||||
@@ -921,6 +931,24 @@ class UpdatePreferenceFromEncryptedDataView(ModuleStoreTestCase):
|
||||
assert type_prefs['email'] is False
|
||||
assert type_prefs['email_cadence'] == EmailCadence.NEVER
|
||||
|
||||
def test_if_config_version_is_updated(self):
|
||||
"""
|
||||
Tests if preference version is updated before applying patch data
|
||||
"""
|
||||
preference = CourseNotificationPreference.objects.get(user=self.user, course_id=self.course.id)
|
||||
preference.config_version -= 1
|
||||
preference.save()
|
||||
user_hash = encrypt_string(self.user.username)
|
||||
patch_hash = encrypt_object({'channel': 'email', 'value': False})
|
||||
url_params = {
|
||||
"username": user_hash,
|
||||
"patch": patch_hash
|
||||
}
|
||||
url = reverse("preference_update_from_encrypted_username_view", kwargs=url_params)
|
||||
self.client.get(url)
|
||||
preference = CourseNotificationPreference.objects.get(user=self.user, course_id=self.course.id)
|
||||
assert preference.config_version == get_course_notification_preference_config_version()
|
||||
|
||||
|
||||
def remove_notifications_with_visibility_settings(expected_response):
|
||||
"""
|
||||
|
||||
@@ -5,7 +5,6 @@ from datetime import datetime, timedelta
|
||||
|
||||
from django.conf import settings
|
||||
from django.db.models import Count
|
||||
from django.http import HttpResponse
|
||||
from django.shortcuts import get_object_or_404
|
||||
from django.utils.translation import gettext as _
|
||||
from opaque_keys.edx.keys import CourseKey
|
||||
@@ -442,4 +441,4 @@ def preference_update_from_encrypted_username_view(request, username, patch):
|
||||
username and patch must be string
|
||||
"""
|
||||
update_user_preferences_from_patch(username, patch)
|
||||
return HttpResponse("<!DOCTYPE html><html><body>Success</body></html>", status=status.HTTP_200_OK)
|
||||
return Response({"result": "success"}, status=status.HTTP_200_OK)
|
||||
|
||||
@@ -257,7 +257,7 @@ class BlockFieldsView(APIView):
|
||||
|
||||
# Signal that we've modified this block
|
||||
context_impl = get_learning_context_impl(usage_key)
|
||||
context_impl.send_updated_event(usage_key)
|
||||
context_impl.send_block_updated_event(usage_key)
|
||||
|
||||
return Response({
|
||||
"id": str(block.location),
|
||||
|
||||
1511
package-lock.json
generated
1511
package-lock.json
generated
@@ -9,11 +9,11 @@
|
||||
"version": "0.1.0",
|
||||
"hasInstallScript": true,
|
||||
"dependencies": {
|
||||
"@babel/core": "7.19.0",
|
||||
"@babel/core": "7.25.2",
|
||||
"@babel/plugin-proposal-object-rest-spread": "^7.18.9",
|
||||
"@babel/plugin-transform-object-assign": "^7.18.6",
|
||||
"@babel/preset-env": "^7.19.0",
|
||||
"@babel/preset-react": "7.18.6",
|
||||
"@babel/preset-react": "7.24.7",
|
||||
"@edx/brand-edx.org": "^2.0.7",
|
||||
"@edx/edx-bootstrap": "1.0.4",
|
||||
"@edx/edx-proctoring": "^4.18.1",
|
||||
@@ -23,7 +23,7 @@
|
||||
"babel-loader": "^9.1.3",
|
||||
"babel-plugin-transform-class-properties": "6.24.1",
|
||||
"babel-polyfill": "6.26.0",
|
||||
"backbone": "1.4.1",
|
||||
"backbone": "1.6.0",
|
||||
"backbone-associations": "0.6.2",
|
||||
"backbone.paginator": "2.0.8",
|
||||
"bootstrap": "4.0.0",
|
||||
@@ -59,7 +59,7 @@
|
||||
"react-slick": "0.29.0",
|
||||
"redux": "3.7.2",
|
||||
"redux-thunk": "2.2.0",
|
||||
"requirejs": "2.3.6",
|
||||
"requirejs": "2.3.7",
|
||||
"rtlcss": "2.6.2",
|
||||
"sass": "^1.54.8",
|
||||
"sass-loader": "^14.1.1",
|
||||
@@ -79,29 +79,29 @@
|
||||
"@edx/eslint-config": "^3.1.1",
|
||||
"@edx/mockprock": "github:openedx/mockprock#3ad18c6888e6521e9bf7a4df0db6f8579b928235",
|
||||
"@edx/stylelint-config-edx": "2.3.3",
|
||||
"babel-jest": "26.0.0",
|
||||
"babel-jest": "26.6.3",
|
||||
"enzyme": "3.11.0",
|
||||
"enzyme-adapter-react-16": "1.15.8",
|
||||
"eslint-import-resolver-webpack": "0.13.8",
|
||||
"jasmine-core": "2.6.4",
|
||||
"jasmine-jquery": "git+https://git@github.com/velesin/jasmine-jquery.git#ebad463d592d3fea00c69f26ea18a930e09c7b58",
|
||||
"jest": "26.0.0",
|
||||
"jest-enzyme": "6.0.2",
|
||||
"jest": "26.6.3",
|
||||
"jest-enzyme": "6.1.2",
|
||||
"karma": "0.13.22",
|
||||
"karma-chrome-launcher": "0.2.3",
|
||||
"karma-coverage": "0.5.5",
|
||||
"karma-firefox-launcher": "0.1.7",
|
||||
"karma-jasmine": "0.3.8",
|
||||
"karma-jasmine-html-reporter": "0.2.2",
|
||||
"karma-junit-reporter": "1.1.0",
|
||||
"karma-junit-reporter": "1.2.0",
|
||||
"karma-requirejs": "0.2.6",
|
||||
"karma-selenium-webdriver-launcher": "github:openedx/karma-selenium-webdriver-launcher#0.0.4-openedx.0",
|
||||
"karma-sourcemap-loader": "0.3.7",
|
||||
"karma-sourcemap-loader": "0.4.0",
|
||||
"karma-spec-reporter": "0.0.36",
|
||||
"karma-webpack": "^5.0.1",
|
||||
"plato": "1.7.0",
|
||||
"react-test-renderer": "16.4.0",
|
||||
"selenium-webdriver": "3.4.0",
|
||||
"react-test-renderer": "16.14.0",
|
||||
"selenium-webdriver": "3.6.0",
|
||||
"sinon": "2.4.1",
|
||||
"squirejs": "0.1.0",
|
||||
"string-replace-loader": "^3.1.0",
|
||||
@@ -132,11 +132,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/code-frame": {
|
||||
"version": "7.24.2",
|
||||
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.2.tgz",
|
||||
"integrity": "sha512-y5+tLQyV8pg3fsiln67BVLD1P13Eg4lh5RW9mF0zUuvLrv9uIQ4MCL+CRT+FTsBlBjcIan6PGsLcBN0m3ClUyQ==",
|
||||
"version": "7.24.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.7.tgz",
|
||||
"integrity": "sha512-BcYH1CVJBO9tvyIZ2jVeXgSIMvGZ2FDRvDdOIVQyuklNKSsx+eppDEBq/g47Ayw+RqNFE+URvOShmf+f/qwAlA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/highlight": "^7.24.2",
|
||||
"@babel/highlight": "^7.24.7",
|
||||
"picocolors": "^1.0.0"
|
||||
},
|
||||
"engines": {
|
||||
@@ -144,33 +145,35 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/compat-data": {
|
||||
"version": "7.24.1",
|
||||
"resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.24.1.tgz",
|
||||
"integrity": "sha512-Pc65opHDliVpRHuKfzI+gSA4zcgr65O4cl64fFJIWEEh8JoHIHh0Oez1Eo8Arz8zq/JhgKodQaxEwUPRtZylVA==",
|
||||
"version": "7.25.2",
|
||||
"resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.25.2.tgz",
|
||||
"integrity": "sha512-bYcppcpKBvX4znYaPEeFau03bp89ShqNMLs+rmdptMw+heSZh9+z84d2YG+K7cYLbWwzdjtDoW/uqZmPjulClQ==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/core": {
|
||||
"version": "7.19.0",
|
||||
"resolved": "https://registry.npmjs.org/@babel/core/-/core-7.19.0.tgz",
|
||||
"integrity": "sha512-reM4+U7B9ss148rh2n1Qs9ASS+w94irYXga7c2jaQv9RVzpS7Mv1a9rnYYwuDa45G+DkORt9g6An2k/V4d9LbQ==",
|
||||
"version": "7.25.2",
|
||||
"resolved": "https://registry.npmjs.org/@babel/core/-/core-7.25.2.tgz",
|
||||
"integrity": "sha512-BBt3opiCOxUr9euZ5/ro/Xv8/V7yJ5bjYMqG/C1YAo8MIKAnumZalCN+msbci3Pigy4lIQfPUpfMM27HMGaYEA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@ampproject/remapping": "^2.1.0",
|
||||
"@babel/code-frame": "^7.18.6",
|
||||
"@babel/generator": "^7.19.0",
|
||||
"@babel/helper-compilation-targets": "^7.19.0",
|
||||
"@babel/helper-module-transforms": "^7.19.0",
|
||||
"@babel/helpers": "^7.19.0",
|
||||
"@babel/parser": "^7.19.0",
|
||||
"@babel/template": "^7.18.10",
|
||||
"@babel/traverse": "^7.19.0",
|
||||
"@babel/types": "^7.19.0",
|
||||
"convert-source-map": "^1.7.0",
|
||||
"@ampproject/remapping": "^2.2.0",
|
||||
"@babel/code-frame": "^7.24.7",
|
||||
"@babel/generator": "^7.25.0",
|
||||
"@babel/helper-compilation-targets": "^7.25.2",
|
||||
"@babel/helper-module-transforms": "^7.25.2",
|
||||
"@babel/helpers": "^7.25.0",
|
||||
"@babel/parser": "^7.25.0",
|
||||
"@babel/template": "^7.25.0",
|
||||
"@babel/traverse": "^7.25.2",
|
||||
"@babel/types": "^7.25.2",
|
||||
"convert-source-map": "^2.0.0",
|
||||
"debug": "^4.1.0",
|
||||
"gensync": "^1.0.0-beta.2",
|
||||
"json5": "^2.2.1",
|
||||
"semver": "^6.3.0"
|
||||
"json5": "^2.2.3",
|
||||
"semver": "^6.3.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
@@ -180,12 +183,19 @@
|
||||
"url": "https://opencollective.com/babel"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/core/node_modules/convert-source-map": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz",
|
||||
"integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@babel/generator": {
|
||||
"version": "7.24.1",
|
||||
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.24.1.tgz",
|
||||
"integrity": "sha512-DfCRfZsBcrPEHUfuBMgbJ1Ut01Y/itOs+hY2nFLgqsqXd52/iSiVq5TITtUasIUgm+IIKdY2/1I7auiQOEeC9A==",
|
||||
"version": "7.25.0",
|
||||
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.25.0.tgz",
|
||||
"integrity": "sha512-3LEEcj3PVW8pW2R1SR1M89g/qrYk/m/mB/tLqn7dn4sbBUQyTqnlod+II2U4dqiGtUmkcnAmkMDralTFZttRiw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/types": "^7.24.0",
|
||||
"@babel/types": "^7.25.0",
|
||||
"@jridgewell/gen-mapping": "^0.3.5",
|
||||
"@jridgewell/trace-mapping": "^0.3.25",
|
||||
"jsesc": "^2.5.1"
|
||||
@@ -195,35 +205,39 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/helper-annotate-as-pure": {
|
||||
"version": "7.22.5",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.22.5.tgz",
|
||||
"integrity": "sha512-LvBTxu8bQSQkcyKOU+a1btnNFQ1dMAd0R6PyW3arXes06F6QLWLIrd681bxRPIXlrMGR3XYnW9JyML7dP3qgxg==",
|
||||
"version": "7.24.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.24.7.tgz",
|
||||
"integrity": "sha512-BaDeOonYvhdKw+JoMVkAixAAJzG2jVPIwWoKBPdYuY9b452e2rPuI9QPYh3KpofZ3pW2akOmwZLOiOsHMiqRAg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/types": "^7.22.5"
|
||||
"@babel/types": "^7.24.7"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/helper-builder-binary-assignment-operator-visitor": {
|
||||
"version": "7.22.15",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.22.15.tgz",
|
||||
"integrity": "sha512-QkBXwGgaoC2GtGZRoma6kv7Szfv06khvhFav67ZExau2RaXzy8MpHSMO2PNoP2XtmQphJQRHFfg77Bq731Yizw==",
|
||||
"version": "7.24.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.24.7.tgz",
|
||||
"integrity": "sha512-xZeCVVdwb4MsDBkkyZ64tReWYrLRHlMN72vP7Bdm3OUOuyFZExhsHUUnuWnm2/XOlAJzR0LfPpB56WXZn0X/lA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/types": "^7.22.15"
|
||||
"@babel/traverse": "^7.24.7",
|
||||
"@babel/types": "^7.24.7"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/helper-compilation-targets": {
|
||||
"version": "7.23.6",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.23.6.tgz",
|
||||
"integrity": "sha512-9JB548GZoQVmzrFgp8o7KxdgkTGm6xs9DW0o/Pim72UDjzr5ObUQ6ZzYPqA+g9OTS2bBQoctLJrky0RDCAWRgQ==",
|
||||
"version": "7.25.2",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.25.2.tgz",
|
||||
"integrity": "sha512-U2U5LsSaZ7TAt3cfaymQ8WHh0pxvdHoEk6HVpaexxixjyEquMh0L0YNJNM6CTGKMXV1iksi0iZkGw4AcFkPaaw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/compat-data": "^7.23.5",
|
||||
"@babel/helper-validator-option": "^7.23.5",
|
||||
"browserslist": "^4.22.2",
|
||||
"@babel/compat-data": "^7.25.2",
|
||||
"@babel/helper-validator-option": "^7.24.8",
|
||||
"browserslist": "^4.23.1",
|
||||
"lru-cache": "^5.1.1",
|
||||
"semver": "^6.3.1"
|
||||
},
|
||||
@@ -232,18 +246,17 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/helper-create-class-features-plugin": {
|
||||
"version": "7.24.1",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.24.1.tgz",
|
||||
"integrity": "sha512-1yJa9dX9g//V6fDebXoEfEsxkZHk3Hcbm+zLhyu6qVgYFLvmTALTeV+jNU9e5RnYtioBrGEOdoI2joMSNQ/+aA==",
|
||||
"version": "7.25.0",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.25.0.tgz",
|
||||
"integrity": "sha512-GYM6BxeQsETc9mnct+nIIpf63SAyzvyYN7UB/IlTyd+MBg06afFGp0mIeUqGyWgS2mxad6vqbMrHVlaL3m70sQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/helper-annotate-as-pure": "^7.22.5",
|
||||
"@babel/helper-environment-visitor": "^7.22.20",
|
||||
"@babel/helper-function-name": "^7.23.0",
|
||||
"@babel/helper-member-expression-to-functions": "^7.23.0",
|
||||
"@babel/helper-optimise-call-expression": "^7.22.5",
|
||||
"@babel/helper-replace-supers": "^7.24.1",
|
||||
"@babel/helper-skip-transparent-expression-wrappers": "^7.22.5",
|
||||
"@babel/helper-split-export-declaration": "^7.22.6",
|
||||
"@babel/helper-annotate-as-pure": "^7.24.7",
|
||||
"@babel/helper-member-expression-to-functions": "^7.24.8",
|
||||
"@babel/helper-optimise-call-expression": "^7.24.7",
|
||||
"@babel/helper-replace-supers": "^7.25.0",
|
||||
"@babel/helper-skip-transparent-expression-wrappers": "^7.24.7",
|
||||
"@babel/traverse": "^7.25.0",
|
||||
"semver": "^6.3.1"
|
||||
},
|
||||
"engines": {
|
||||
@@ -254,11 +267,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/helper-create-regexp-features-plugin": {
|
||||
"version": "7.22.15",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.22.15.tgz",
|
||||
"integrity": "sha512-29FkPLFjn4TPEa3RE7GpW+qbE8tlsu3jntNYNfcGsc49LphF1PQIiD+vMZ1z1xVOKt+93khA9tc2JBs3kBjA7w==",
|
||||
"version": "7.25.2",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.25.2.tgz",
|
||||
"integrity": "sha512-+wqVGP+DFmqwFD3EH6TMTfUNeqDehV3E/dl+Sd54eaXqm17tEUNbEIn4sVivVowbvUpOtIGxdo3GoXyDH9N/9g==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/helper-annotate-as-pure": "^7.22.5",
|
||||
"@babel/helper-annotate-as-pure": "^7.24.7",
|
||||
"regexpu-core": "^5.3.1",
|
||||
"semver": "^6.3.1"
|
||||
},
|
||||
@@ -284,69 +298,42 @@
|
||||
"@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/helper-environment-visitor": {
|
||||
"version": "7.22.20",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz",
|
||||
"integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==",
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/helper-function-name": {
|
||||
"version": "7.23.0",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz",
|
||||
"integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==",
|
||||
"dependencies": {
|
||||
"@babel/template": "^7.22.15",
|
||||
"@babel/types": "^7.23.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/helper-hoist-variables": {
|
||||
"version": "7.22.5",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz",
|
||||
"integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==",
|
||||
"dependencies": {
|
||||
"@babel/types": "^7.22.5"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/helper-member-expression-to-functions": {
|
||||
"version": "7.23.0",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.23.0.tgz",
|
||||
"integrity": "sha512-6gfrPwh7OuT6gZyJZvd6WbTfrqAo7vm4xCzAXOusKqq/vWdKXphTpj5klHKNmRUU6/QRGlBsyU9mAIPaWHlqJA==",
|
||||
"version": "7.24.8",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.24.8.tgz",
|
||||
"integrity": "sha512-LABppdt+Lp/RlBxqrh4qgf1oEH/WxdzQNDJIu5gC/W1GyvPVrOBiItmmM8wan2fm4oYqFuFfkXmlGpLQhPY8CA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/types": "^7.23.0"
|
||||
"@babel/traverse": "^7.24.8",
|
||||
"@babel/types": "^7.24.8"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/helper-module-imports": {
|
||||
"version": "7.24.3",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.24.3.tgz",
|
||||
"integrity": "sha512-viKb0F9f2s0BCS22QSF308z/+1YWKV/76mwt61NBzS5izMzDPwdq1pTrzf+Li3npBWX9KdQbkeCt1jSAM7lZqg==",
|
||||
"version": "7.24.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.24.7.tgz",
|
||||
"integrity": "sha512-8AyH3C+74cgCVVXow/myrynrAGv+nTVg5vKu2nZph9x7RcRwzmh0VFallJuFTZ9mx6u4eSdXZfcOzSqTUm0HCA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/types": "^7.24.0"
|
||||
"@babel/traverse": "^7.24.7",
|
||||
"@babel/types": "^7.24.7"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/helper-module-transforms": {
|
||||
"version": "7.23.3",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.23.3.tgz",
|
||||
"integrity": "sha512-7bBs4ED9OmswdfDzpz4MpWgSrV7FXlc3zIagvLFjS5H+Mk7Snr21vQ6QwrsoCGMfNC4e4LQPdoULEt4ykz0SRQ==",
|
||||
"version": "7.25.2",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.25.2.tgz",
|
||||
"integrity": "sha512-BjyRAbix6j/wv83ftcVJmBt72QtHI56C7JXZoG2xATiLpmoC7dpd8WnkikExHDVPpi/3qCmO6WY1EaXOluiecQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/helper-environment-visitor": "^7.22.20",
|
||||
"@babel/helper-module-imports": "^7.22.15",
|
||||
"@babel/helper-simple-access": "^7.22.5",
|
||||
"@babel/helper-split-export-declaration": "^7.22.6",
|
||||
"@babel/helper-validator-identifier": "^7.22.20"
|
||||
"@babel/helper-module-imports": "^7.24.7",
|
||||
"@babel/helper-simple-access": "^7.24.7",
|
||||
"@babel/helper-validator-identifier": "^7.24.7",
|
||||
"@babel/traverse": "^7.25.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
@@ -356,32 +343,35 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/helper-optimise-call-expression": {
|
||||
"version": "7.22.5",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.22.5.tgz",
|
||||
"integrity": "sha512-HBwaojN0xFRx4yIvpwGqxiV2tUfl7401jlok564NgB9EHS1y6QT17FmKWm4ztqjeVdXLuC4fSvHc5ePpQjoTbw==",
|
||||
"version": "7.24.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.24.7.tgz",
|
||||
"integrity": "sha512-jKiTsW2xmWwxT1ixIdfXUZp+P5yURx2suzLZr5Hi64rURpDYdMW0pv+Uf17EYk2Rd428Lx4tLsnjGJzYKDM/6A==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/types": "^7.22.5"
|
||||
"@babel/types": "^7.24.7"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/helper-plugin-utils": {
|
||||
"version": "7.24.0",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.0.tgz",
|
||||
"integrity": "sha512-9cUznXMG0+FxRuJfvL82QlTqIzhVW9sL0KjMPHhAOOvpQGL8QtdxnBKILjBqxlHyliz0yCa1G903ZXI/FuHy2w==",
|
||||
"version": "7.24.8",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.8.tgz",
|
||||
"integrity": "sha512-FFWx5142D8h2Mgr/iPVGH5G7w6jDn4jUSpZTyDnQO0Yn7Ks2Kuz6Pci8H6MPCoUJegd/UZQ3tAvfLCxQSnWWwg==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/helper-remap-async-to-generator": {
|
||||
"version": "7.22.20",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.22.20.tgz",
|
||||
"integrity": "sha512-pBGyV4uBqOns+0UvhsTO8qgl8hO89PmiDYv+/COyp1aeMcmfrfruz+/nCMFiYyFF/Knn0yfrC85ZzNFjembFTw==",
|
||||
"version": "7.25.0",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.25.0.tgz",
|
||||
"integrity": "sha512-NhavI2eWEIz/H9dbrG0TuOicDhNexze43i5z7lEqwYm0WEZVTwnPpA0EafUTP7+6/W79HWIP2cTe3Z5NiSTVpw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/helper-annotate-as-pure": "^7.22.5",
|
||||
"@babel/helper-environment-visitor": "^7.22.20",
|
||||
"@babel/helper-wrap-function": "^7.22.20"
|
||||
"@babel/helper-annotate-as-pure": "^7.24.7",
|
||||
"@babel/helper-wrap-function": "^7.25.0",
|
||||
"@babel/traverse": "^7.25.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
@@ -391,13 +381,14 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/helper-replace-supers": {
|
||||
"version": "7.24.1",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.24.1.tgz",
|
||||
"integrity": "sha512-QCR1UqC9BzG5vZl8BMicmZ28RuUBnHhAMddD8yHFHDRH9lLTZ9uUPehX8ctVPT8l0TKblJidqcgUUKGVrePleQ==",
|
||||
"version": "7.25.0",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.25.0.tgz",
|
||||
"integrity": "sha512-q688zIvQVYtZu+i2PsdIu/uWGRpfxzr5WESsfpShfZECkO+d2o+WROWezCi/Q6kJ0tfPa5+pUGUlfx2HhrA3Bg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/helper-environment-visitor": "^7.22.20",
|
||||
"@babel/helper-member-expression-to-functions": "^7.23.0",
|
||||
"@babel/helper-optimise-call-expression": "^7.22.5"
|
||||
"@babel/helper-member-expression-to-functions": "^7.24.8",
|
||||
"@babel/helper-optimise-call-expression": "^7.24.7",
|
||||
"@babel/traverse": "^7.25.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
@@ -407,94 +398,92 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/helper-simple-access": {
|
||||
"version": "7.22.5",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.22.5.tgz",
|
||||
"integrity": "sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==",
|
||||
"version": "7.24.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.24.7.tgz",
|
||||
"integrity": "sha512-zBAIvbCMh5Ts+b86r/CjU+4XGYIs+R1j951gxI3KmmxBMhCg4oQMsv6ZXQ64XOm/cvzfU1FmoCyt6+owc5QMYg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/types": "^7.22.5"
|
||||
"@babel/traverse": "^7.24.7",
|
||||
"@babel/types": "^7.24.7"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/helper-skip-transparent-expression-wrappers": {
|
||||
"version": "7.22.5",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.22.5.tgz",
|
||||
"integrity": "sha512-tK14r66JZKiC43p8Ki33yLBVJKlQDFoA8GYN67lWCDCqoL6EMMSuM9b+Iff2jHaM/RRFYl7K+iiru7hbRqNx8Q==",
|
||||
"version": "7.24.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.24.7.tgz",
|
||||
"integrity": "sha512-IO+DLT3LQUElMbpzlatRASEyQtfhSE0+m465v++3jyyXeBTBUjtVZg28/gHeV5mrTJqvEKhKroBGAvhW+qPHiQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/types": "^7.22.5"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/helper-split-export-declaration": {
|
||||
"version": "7.22.6",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz",
|
||||
"integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==",
|
||||
"dependencies": {
|
||||
"@babel/types": "^7.22.5"
|
||||
"@babel/traverse": "^7.24.7",
|
||||
"@babel/types": "^7.24.7"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/helper-string-parser": {
|
||||
"version": "7.24.1",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.24.1.tgz",
|
||||
"integrity": "sha512-2ofRCjnnA9y+wk8b9IAREroeUP02KHp431N2mhKniy2yKIDKpbrHv9eXwm8cBeWQYcJmzv5qKCu65P47eCF7CQ==",
|
||||
"version": "7.24.8",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.24.8.tgz",
|
||||
"integrity": "sha512-pO9KhhRcuUyGnJWwyEgnRJTSIZHiT+vMD0kPeD+so0l7mxkMT19g3pjY9GTnHySck/hDzq+dtW/4VgnMkippsQ==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/helper-validator-identifier": {
|
||||
"version": "7.22.20",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz",
|
||||
"integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==",
|
||||
"version": "7.24.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.7.tgz",
|
||||
"integrity": "sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/helper-validator-option": {
|
||||
"version": "7.23.5",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.23.5.tgz",
|
||||
"integrity": "sha512-85ttAOMLsr53VgXkTbkx8oA6YTfT4q7/HzXSLEYmjcSTJPMPQtvq1BD79Byep5xMUYbGRzEpDsjUf3dyp54IKw==",
|
||||
"version": "7.24.8",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.24.8.tgz",
|
||||
"integrity": "sha512-xb8t9tD1MHLungh/AIoWYN+gVHaB9kwlu8gffXGSt3FFEIT7RjS+xWbc2vUD1UTZdIpKj/ab3rdqJ7ufngyi2Q==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/helper-wrap-function": {
|
||||
"version": "7.22.20",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.22.20.tgz",
|
||||
"integrity": "sha512-pms/UwkOpnQe/PDAEdV/d7dVCoBbB+R4FvYoHGZz+4VPcg7RtYy2KP7S2lbuWM6FCSgob5wshfGESbC/hzNXZw==",
|
||||
"version": "7.25.0",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.25.0.tgz",
|
||||
"integrity": "sha512-s6Q1ebqutSiZnEjaofc/UKDyC4SbzV5n5SrA2Gq8UawLycr3i04f1dX4OzoQVnexm6aOCh37SQNYlJ/8Ku+PMQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/helper-function-name": "^7.22.5",
|
||||
"@babel/template": "^7.22.15",
|
||||
"@babel/types": "^7.22.19"
|
||||
"@babel/template": "^7.25.0",
|
||||
"@babel/traverse": "^7.25.0",
|
||||
"@babel/types": "^7.25.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/helpers": {
|
||||
"version": "7.24.1",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.24.1.tgz",
|
||||
"integrity": "sha512-BpU09QqEe6ZCHuIHFphEFgvNSrubve1FtyMton26ekZ85gRGi6LrTF7zArARp2YvyFxloeiRmtSCq5sjh1WqIg==",
|
||||
"version": "7.25.0",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.25.0.tgz",
|
||||
"integrity": "sha512-MjgLZ42aCm0oGjJj8CtSM3DB8NOOf8h2l7DCTePJs29u+v7yO/RBX9nShlKMgFnRks/Q4tBAe7Hxnov9VkGwLw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/template": "^7.24.0",
|
||||
"@babel/traverse": "^7.24.1",
|
||||
"@babel/types": "^7.24.0"
|
||||
"@babel/template": "^7.25.0",
|
||||
"@babel/types": "^7.25.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/highlight": {
|
||||
"version": "7.24.2",
|
||||
"resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.2.tgz",
|
||||
"integrity": "sha512-Yac1ao4flkTxTteCDZLEvdxg2fZfz1v8M4QpaGypq/WPDqg3ijHYbDfs+LG5hvzSoqaSZ9/Z9lKSP3CjZjv+pA==",
|
||||
"version": "7.24.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.7.tgz",
|
||||
"integrity": "sha512-EStJpq4OuY8xYfhGVXngigBJRWxftKX9ksiGDnmlY3o7B/V7KIAc9X4oiK87uPJSc/vs5L869bem5fhZa8caZw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/helper-validator-identifier": "^7.22.20",
|
||||
"@babel/helper-validator-identifier": "^7.24.7",
|
||||
"chalk": "^2.4.2",
|
||||
"js-tokens": "^4.0.0",
|
||||
"picocolors": "^1.0.0"
|
||||
@@ -504,9 +493,13 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/parser": {
|
||||
"version": "7.24.1",
|
||||
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.1.tgz",
|
||||
"integrity": "sha512-Zo9c7N3xdOIQrNip7Lc9wvRPzlRtovHVE4lkz8WEDr7uYh/GMQhSiIgFxGIArRHYdJE5kxtZjAf8rT0xhdLCzg==",
|
||||
"version": "7.25.3",
|
||||
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.25.3.tgz",
|
||||
"integrity": "sha512-iLTJKDbJ4hMvFPgQwwsVoxtHyWpKKPBrxkANrSYewDPaPpT5py5yeVkgPIJ7XYXhndxJpaA3PyALSXQ7u8e/Dw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/types": "^7.25.2"
|
||||
},
|
||||
"bin": {
|
||||
"parser": "bin/babel-parser.js"
|
||||
},
|
||||
@@ -514,12 +507,44 @@
|
||||
"node": ">=6.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": {
|
||||
"version": "7.24.1",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.24.1.tgz",
|
||||
"integrity": "sha512-y4HqEnkelJIOQGd+3g1bTeKsA5c6qM7eOn7VggGVbBc0y8MLSKHacwcIE2PplNlQSj0PqS9rrXL/nkPVK+kUNg==",
|
||||
"node_modules/@babel/plugin-bugfix-firefox-class-in-computed-class-key": {
|
||||
"version": "7.25.3",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-firefox-class-in-computed-class-key/-/plugin-bugfix-firefox-class-in-computed-class-key-7.25.3.tgz",
|
||||
"integrity": "sha512-wUrcsxZg6rqBXG05HG1FPYgsP6EvwF4WpBbxIpWIIYnH8wG0gzx3yZY3dtEHas4sTAOGkbTsc9EGPxwff8lRoA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/helper-plugin-utils": "^7.24.0"
|
||||
"@babel/helper-plugin-utils": "^7.24.8",
|
||||
"@babel/traverse": "^7.25.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@babel/core": "^7.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/plugin-bugfix-safari-class-field-initializer-scope": {
|
||||
"version": "7.25.0",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-class-field-initializer-scope/-/plugin-bugfix-safari-class-field-initializer-scope-7.25.0.tgz",
|
||||
"integrity": "sha512-Bm4bH2qsX880b/3ziJ8KD711LT7z4u8CFudmjqle65AZj/HNUFhEf90dqYv6O86buWvSBmeQDjv0Tn2aF/bIBA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/helper-plugin-utils": "^7.24.8"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@babel/core": "^7.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": {
|
||||
"version": "7.25.0",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.25.0.tgz",
|
||||
"integrity": "sha512-lXwdNZtTmeVOOFtwM/WDe7yg1PL8sYhRk/XH0FzbR2HDQ0xC+EnQ/JHeoMYSavtU115tnUk0q9CDyq8si+LMAA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/helper-plugin-utils": "^7.24.8"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
@@ -529,13 +554,14 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": {
|
||||
"version": "7.24.1",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.24.1.tgz",
|
||||
"integrity": "sha512-Hj791Ii4ci8HqnaKHAlLNs+zaLXb0EzSDhiAWp5VNlyvCNymYfacs64pxTxbH1znW/NcArSmwpmG9IKE/TUVVQ==",
|
||||
"version": "7.24.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.24.7.tgz",
|
||||
"integrity": "sha512-+izXIbke1T33mY4MSNnrqhPXDz01WYhEf3yF5NbnUtkiNnm+XBZJl3kNfoK6NKmYlz/D07+l2GWVK/QfDkNCuQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/helper-plugin-utils": "^7.24.0",
|
||||
"@babel/helper-skip-transparent-expression-wrappers": "^7.22.5",
|
||||
"@babel/plugin-transform-optional-chaining": "^7.24.1"
|
||||
"@babel/helper-plugin-utils": "^7.24.7",
|
||||
"@babel/helper-skip-transparent-expression-wrappers": "^7.24.7",
|
||||
"@babel/plugin-transform-optional-chaining": "^7.24.7"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
@@ -545,12 +571,13 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": {
|
||||
"version": "7.24.1",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.24.1.tgz",
|
||||
"integrity": "sha512-m9m/fXsXLiHfwdgydIFnpk+7jlVbnvlK5B2EKiPdLUb6WX654ZaaEWJUjk8TftRbZpK0XibovlLWX4KIZhV6jw==",
|
||||
"version": "7.25.0",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.25.0.tgz",
|
||||
"integrity": "sha512-tggFrk1AIShG/RUQbEwt2Tr/E+ObkfwrPjR6BjbRvsx24+PSjK8zrq0GWPNCjo8qpRx4DuJzlcvWJqlm+0h3kw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/helper-environment-visitor": "^7.22.20",
|
||||
"@babel/helper-plugin-utils": "^7.24.0"
|
||||
"@babel/helper-plugin-utils": "^7.24.8",
|
||||
"@babel/traverse": "^7.25.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
@@ -660,11 +687,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/plugin-syntax-import-assertions": {
|
||||
"version": "7.24.1",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.24.1.tgz",
|
||||
"integrity": "sha512-IuwnI5XnuF189t91XbxmXeCDz3qs6iDRO7GJ++wcfgeXNs/8FmIlKcpDSXNVyuLQxlwvskmI3Ct73wUODkJBlQ==",
|
||||
"version": "7.24.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.24.7.tgz",
|
||||
"integrity": "sha512-Ec3NRUMoi8gskrkBe3fNmEQfxDvY8bgfQpz6jlk/41kX9eUjvpyqWU7PBP/pLAvMaSQjbMNKJmvX57jP+M6bPg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/helper-plugin-utils": "^7.24.0"
|
||||
"@babel/helper-plugin-utils": "^7.24.7"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
@@ -674,11 +702,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/plugin-syntax-import-attributes": {
|
||||
"version": "7.24.1",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.24.1.tgz",
|
||||
"integrity": "sha512-zhQTMH0X2nVLnb04tz+s7AMuasX8U0FnpE+nHTOhSOINjWMnopoZTxtIKsd45n4GQ/HIZLyfIpoul8e2m0DnRA==",
|
||||
"version": "7.24.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.24.7.tgz",
|
||||
"integrity": "sha512-hbX+lKKeUMGihnK8nvKqmXBInriT3GVjzXKFriV3YC6APGxMbP8RZNFwy91+hocLXq90Mta+HshoB31802bb8A==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/helper-plugin-utils": "^7.24.0"
|
||||
"@babel/helper-plugin-utils": "^7.24.7"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
@@ -710,11 +739,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/plugin-syntax-jsx": {
|
||||
"version": "7.24.1",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.24.1.tgz",
|
||||
"integrity": "sha512-2eCtxZXf+kbkMIsXS4poTvT4Yu5rXiRa+9xGVT56raghjmBTKMpFNc9R4IDiB4emao9eO22Ox7CxuJG7BgExqA==",
|
||||
"version": "7.24.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.24.7.tgz",
|
||||
"integrity": "sha512-6ddciUPe/mpMnOKv/U+RSd2vvVy+Yw/JfBB0ZHYjEZt9NLHmCUylNYlsbqCCS1Bffjlb0fCwC9Vqz+sBz6PsiQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/helper-plugin-utils": "^7.24.0"
|
||||
"@babel/helper-plugin-utils": "^7.24.7"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
@@ -833,11 +863,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/plugin-transform-arrow-functions": {
|
||||
"version": "7.24.1",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.24.1.tgz",
|
||||
"integrity": "sha512-ngT/3NkRhsaep9ck9uj2Xhv9+xB1zShY3tM3g6om4xxCELwCDN4g4Aq5dRn48+0hasAql7s2hdBOysCfNpr4fw==",
|
||||
"version": "7.24.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.24.7.tgz",
|
||||
"integrity": "sha512-Dt9LQs6iEY++gXUwY03DNFat5C2NbO48jj+j/bSAz6b3HgPs39qcPiYt77fDObIcFwj3/C2ICX9YMwGflUoSHQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/helper-plugin-utils": "^7.24.0"
|
||||
"@babel/helper-plugin-utils": "^7.24.7"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
@@ -847,14 +878,15 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/plugin-transform-async-generator-functions": {
|
||||
"version": "7.24.3",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.24.3.tgz",
|
||||
"integrity": "sha512-Qe26CMYVjpQxJ8zxM1340JFNjZaF+ISWpr1Kt/jGo+ZTUzKkfw/pphEWbRCb+lmSM6k/TOgfYLvmbHkUQ0asIg==",
|
||||
"version": "7.25.0",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.25.0.tgz",
|
||||
"integrity": "sha512-uaIi2FdqzjpAMvVqvB51S42oC2JEVgh0LDsGfZVDysWE8LrJtQC2jvKmOqEYThKyB7bDEb7BP1GYWDm7tABA0Q==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/helper-environment-visitor": "^7.22.20",
|
||||
"@babel/helper-plugin-utils": "^7.24.0",
|
||||
"@babel/helper-remap-async-to-generator": "^7.22.20",
|
||||
"@babel/plugin-syntax-async-generators": "^7.8.4"
|
||||
"@babel/helper-plugin-utils": "^7.24.8",
|
||||
"@babel/helper-remap-async-to-generator": "^7.25.0",
|
||||
"@babel/plugin-syntax-async-generators": "^7.8.4",
|
||||
"@babel/traverse": "^7.25.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
@@ -864,13 +896,14 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/plugin-transform-async-to-generator": {
|
||||
"version": "7.24.1",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.24.1.tgz",
|
||||
"integrity": "sha512-AawPptitRXp1y0n4ilKcGbRYWfbbzFWz2NqNu7dacYDtFtz0CMjG64b3LQsb3KIgnf4/obcUL78hfaOS7iCUfw==",
|
||||
"version": "7.24.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.24.7.tgz",
|
||||
"integrity": "sha512-SQY01PcJfmQ+4Ash7NE+rpbLFbmqA2GPIgqzxfFTL4t1FKRq4zTms/7htKpoCUI9OcFYgzqfmCdH53s6/jn5fA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/helper-module-imports": "^7.24.1",
|
||||
"@babel/helper-plugin-utils": "^7.24.0",
|
||||
"@babel/helper-remap-async-to-generator": "^7.22.20"
|
||||
"@babel/helper-module-imports": "^7.24.7",
|
||||
"@babel/helper-plugin-utils": "^7.24.7",
|
||||
"@babel/helper-remap-async-to-generator": "^7.24.7"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
@@ -880,11 +913,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/plugin-transform-block-scoped-functions": {
|
||||
"version": "7.24.1",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.24.1.tgz",
|
||||
"integrity": "sha512-TWWC18OShZutrv9C6mye1xwtam+uNi2bnTOCBUd5sZxyHOiWbU6ztSROofIMrK84uweEZC219POICK/sTYwfgg==",
|
||||
"version": "7.24.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.24.7.tgz",
|
||||
"integrity": "sha512-yO7RAz6EsVQDaBH18IDJcMB1HnrUn2FJ/Jslc/WtPPWcjhpUJXU/rjbwmluzp7v/ZzWcEhTMXELnnsz8djWDwQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/helper-plugin-utils": "^7.24.0"
|
||||
"@babel/helper-plugin-utils": "^7.24.7"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
@@ -894,11 +928,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/plugin-transform-block-scoping": {
|
||||
"version": "7.24.1",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.24.1.tgz",
|
||||
"integrity": "sha512-h71T2QQvDgM2SmT29UYU6ozjMlAt7s7CSs5Hvy8f8cf/GM/Z4a2zMfN+fjVGaieeCrXR3EdQl6C4gQG+OgmbKw==",
|
||||
"version": "7.25.0",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.25.0.tgz",
|
||||
"integrity": "sha512-yBQjYoOjXlFv9nlXb3f1casSHOZkWr29NX+zChVanLg5Nc157CrbEX9D7hxxtTpuFy7Q0YzmmWfJxzvps4kXrQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/helper-plugin-utils": "^7.24.0"
|
||||
"@babel/helper-plugin-utils": "^7.24.8"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
@@ -908,12 +943,13 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/plugin-transform-class-properties": {
|
||||
"version": "7.24.1",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.24.1.tgz",
|
||||
"integrity": "sha512-OMLCXi0NqvJfORTaPQBwqLXHhb93wkBKZ4aNwMl6WtehO7ar+cmp+89iPEQPqxAnxsOKTaMcs3POz3rKayJ72g==",
|
||||
"version": "7.24.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.24.7.tgz",
|
||||
"integrity": "sha512-vKbfawVYayKcSeSR5YYzzyXvsDFWU2mD8U5TFeXtbCPLFUqe7GyCgvO6XDHzje862ODrOwy6WCPmKeWHbCFJ4w==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/helper-create-class-features-plugin": "^7.24.1",
|
||||
"@babel/helper-plugin-utils": "^7.24.0"
|
||||
"@babel/helper-create-class-features-plugin": "^7.24.7",
|
||||
"@babel/helper-plugin-utils": "^7.24.7"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
@@ -923,12 +959,13 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/plugin-transform-class-static-block": {
|
||||
"version": "7.24.1",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.24.1.tgz",
|
||||
"integrity": "sha512-FUHlKCn6J3ERiu8Dv+4eoz7w8+kFLSyeVG4vDAikwADGjUCoHw/JHokyGtr8OR4UjpwPVivyF+h8Q5iv/JmrtA==",
|
||||
"version": "7.24.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.24.7.tgz",
|
||||
"integrity": "sha512-HMXK3WbBPpZQufbMG4B46A90PkuuhN9vBCb5T8+VAHqvAqvcLi+2cKoukcpmUYkszLhScU3l1iudhrks3DggRQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/helper-create-class-features-plugin": "^7.24.1",
|
||||
"@babel/helper-plugin-utils": "^7.24.0",
|
||||
"@babel/helper-create-class-features-plugin": "^7.24.7",
|
||||
"@babel/helper-plugin-utils": "^7.24.7",
|
||||
"@babel/plugin-syntax-class-static-block": "^7.14.5"
|
||||
},
|
||||
"engines": {
|
||||
@@ -939,17 +976,16 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/plugin-transform-classes": {
|
||||
"version": "7.24.1",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.24.1.tgz",
|
||||
"integrity": "sha512-ZTIe3W7UejJd3/3R4p7ScyyOoafetUShSf4kCqV0O7F/RiHxVj/wRaRnQlrGwflvcehNA8M42HkAiEDYZu2F1Q==",
|
||||
"version": "7.25.0",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.25.0.tgz",
|
||||
"integrity": "sha512-xyi6qjr/fYU304fiRwFbekzkqVJZ6A7hOjWZd+89FVcBqPV3S9Wuozz82xdpLspckeaafntbzglaW4pqpzvtSw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/helper-annotate-as-pure": "^7.22.5",
|
||||
"@babel/helper-compilation-targets": "^7.23.6",
|
||||
"@babel/helper-environment-visitor": "^7.22.20",
|
||||
"@babel/helper-function-name": "^7.23.0",
|
||||
"@babel/helper-plugin-utils": "^7.24.0",
|
||||
"@babel/helper-replace-supers": "^7.24.1",
|
||||
"@babel/helper-split-export-declaration": "^7.22.6",
|
||||
"@babel/helper-annotate-as-pure": "^7.24.7",
|
||||
"@babel/helper-compilation-targets": "^7.24.8",
|
||||
"@babel/helper-plugin-utils": "^7.24.8",
|
||||
"@babel/helper-replace-supers": "^7.25.0",
|
||||
"@babel/traverse": "^7.25.0",
|
||||
"globals": "^11.1.0"
|
||||
},
|
||||
"engines": {
|
||||
@@ -960,12 +996,13 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/plugin-transform-computed-properties": {
|
||||
"version": "7.24.1",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.24.1.tgz",
|
||||
"integrity": "sha512-5pJGVIUfJpOS+pAqBQd+QMaTD2vCL/HcePooON6pDpHgRp4gNRmzyHTPIkXntwKsq3ayUFVfJaIKPw2pOkOcTw==",
|
||||
"version": "7.24.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.24.7.tgz",
|
||||
"integrity": "sha512-25cS7v+707Gu6Ds2oY6tCkUwsJ9YIDbggd9+cu9jzzDgiNq7hR/8dkzxWfKWnTic26vsI3EsCXNd4iEB6e8esQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/helper-plugin-utils": "^7.24.0",
|
||||
"@babel/template": "^7.24.0"
|
||||
"@babel/helper-plugin-utils": "^7.24.7",
|
||||
"@babel/template": "^7.24.7"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
@@ -975,11 +1012,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/plugin-transform-destructuring": {
|
||||
"version": "7.24.1",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.24.1.tgz",
|
||||
"integrity": "sha512-ow8jciWqNxR3RYbSNVuF4U2Jx130nwnBnhRw6N6h1bOejNkABmcI5X5oz29K4alWX7vf1C+o6gtKXikzRKkVdw==",
|
||||
"version": "7.24.8",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.24.8.tgz",
|
||||
"integrity": "sha512-36e87mfY8TnRxc7yc6M9g9gOB7rKgSahqkIKwLpz4Ppk2+zC2Cy1is0uwtuSG6AE4zlTOUa+7JGz9jCJGLqQFQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/helper-plugin-utils": "^7.24.0"
|
||||
"@babel/helper-plugin-utils": "^7.24.8"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
@@ -989,12 +1027,13 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/plugin-transform-dotall-regex": {
|
||||
"version": "7.24.1",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.24.1.tgz",
|
||||
"integrity": "sha512-p7uUxgSoZwZ2lPNMzUkqCts3xlp8n+o05ikjy7gbtFJSt9gdU88jAmtfmOxHM14noQXBxfgzf2yRWECiNVhTCw==",
|
||||
"version": "7.24.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.24.7.tgz",
|
||||
"integrity": "sha512-ZOA3W+1RRTSWvyqcMJDLqbchh7U4NRGqwRfFSVbOLS/ePIP4vHB5e8T8eXcuqyN1QkgKyj5wuW0lcS85v4CrSw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/helper-create-regexp-features-plugin": "^7.22.15",
|
||||
"@babel/helper-plugin-utils": "^7.24.0"
|
||||
"@babel/helper-create-regexp-features-plugin": "^7.24.7",
|
||||
"@babel/helper-plugin-utils": "^7.24.7"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
@@ -1004,11 +1043,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/plugin-transform-duplicate-keys": {
|
||||
"version": "7.24.1",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.24.1.tgz",
|
||||
"integrity": "sha512-msyzuUnvsjsaSaocV6L7ErfNsa5nDWL1XKNnDePLgmz+WdU4w/J8+AxBMrWfi9m4IxfL5sZQKUPQKDQeeAT6lA==",
|
||||
"version": "7.24.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.24.7.tgz",
|
||||
"integrity": "sha512-JdYfXyCRihAe46jUIliuL2/s0x0wObgwwiGxw/UbgJBr20gQBThrokO4nYKgWkD7uBaqM7+9x5TU7NkExZJyzw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/helper-plugin-utils": "^7.24.0"
|
||||
"@babel/helper-plugin-utils": "^7.24.7"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
@@ -1017,12 +1057,29 @@
|
||||
"@babel/core": "^7.0.0-0"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/plugin-transform-dynamic-import": {
|
||||
"version": "7.24.1",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.24.1.tgz",
|
||||
"integrity": "sha512-av2gdSTyXcJVdI+8aFZsCAtR29xJt0S5tas+Ef8NvBNmD1a+N/3ecMLeMBgfcK+xzsjdLDT6oHt+DFPyeqUbDA==",
|
||||
"node_modules/@babel/plugin-transform-duplicate-named-capturing-groups-regex": {
|
||||
"version": "7.25.0",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-named-capturing-groups-regex/-/plugin-transform-duplicate-named-capturing-groups-regex-7.25.0.tgz",
|
||||
"integrity": "sha512-YLpb4LlYSc3sCUa35un84poXoraOiQucUTTu8X1j18JV+gNa8E0nyUf/CjZ171IRGr4jEguF+vzJU66QZhn29g==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/helper-plugin-utils": "^7.24.0",
|
||||
"@babel/helper-create-regexp-features-plugin": "^7.25.0",
|
||||
"@babel/helper-plugin-utils": "^7.24.8"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@babel/core": "^7.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/plugin-transform-dynamic-import": {
|
||||
"version": "7.24.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.24.7.tgz",
|
||||
"integrity": "sha512-sc3X26PhZQDb3JhORmakcbvkeInvxz+A8oda99lj7J60QRuPZvNAk9wQlTBS1ZynelDrDmTU4pw1tyc5d5ZMUg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/helper-plugin-utils": "^7.24.7",
|
||||
"@babel/plugin-syntax-dynamic-import": "^7.8.3"
|
||||
},
|
||||
"engines": {
|
||||
@@ -1033,12 +1090,13 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/plugin-transform-exponentiation-operator": {
|
||||
"version": "7.24.1",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.24.1.tgz",
|
||||
"integrity": "sha512-U1yX13dVBSwS23DEAqU+Z/PkwE9/m7QQy8Y9/+Tdb8UWYaGNDYwTLi19wqIAiROr8sXVum9A/rtiH5H0boUcTw==",
|
||||
"version": "7.24.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.24.7.tgz",
|
||||
"integrity": "sha512-Rqe/vSc9OYgDajNIK35u7ot+KeCoetqQYFXM4Epf7M7ez3lWlOjrDjrwMei6caCVhfdw+mIKD4cgdGNy5JQotQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/helper-builder-binary-assignment-operator-visitor": "^7.22.15",
|
||||
"@babel/helper-plugin-utils": "^7.24.0"
|
||||
"@babel/helper-builder-binary-assignment-operator-visitor": "^7.24.7",
|
||||
"@babel/helper-plugin-utils": "^7.24.7"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
@@ -1048,11 +1106,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/plugin-transform-export-namespace-from": {
|
||||
"version": "7.24.1",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.24.1.tgz",
|
||||
"integrity": "sha512-Ft38m/KFOyzKw2UaJFkWG9QnHPG/Q/2SkOrRk4pNBPg5IPZ+dOxcmkK5IyuBcxiNPyyYowPGUReyBvrvZs7IlQ==",
|
||||
"version": "7.24.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.24.7.tgz",
|
||||
"integrity": "sha512-v0K9uNYsPL3oXZ/7F9NNIbAj2jv1whUEtyA6aujhekLs56R++JDQuzRcP2/z4WX5Vg/c5lE9uWZA0/iUoFhLTA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/helper-plugin-utils": "^7.24.0",
|
||||
"@babel/helper-plugin-utils": "^7.24.7",
|
||||
"@babel/plugin-syntax-export-namespace-from": "^7.8.3"
|
||||
},
|
||||
"engines": {
|
||||
@@ -1063,12 +1122,13 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/plugin-transform-for-of": {
|
||||
"version": "7.24.1",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.24.1.tgz",
|
||||
"integrity": "sha512-OxBdcnF04bpdQdR3i4giHZNZQn7cm8RQKcSwA17wAAqEELo1ZOwp5FFgeptWUQXFyT9kwHo10aqqauYkRZPCAg==",
|
||||
"version": "7.24.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.24.7.tgz",
|
||||
"integrity": "sha512-wo9ogrDG1ITTTBsy46oGiN1dS9A7MROBTcYsfS8DtsImMkHk9JXJ3EWQM6X2SUw4x80uGPlwj0o00Uoc6nEE3g==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/helper-plugin-utils": "^7.24.0",
|
||||
"@babel/helper-skip-transparent-expression-wrappers": "^7.22.5"
|
||||
"@babel/helper-plugin-utils": "^7.24.7",
|
||||
"@babel/helper-skip-transparent-expression-wrappers": "^7.24.7"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
@@ -1078,13 +1138,14 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/plugin-transform-function-name": {
|
||||
"version": "7.24.1",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.24.1.tgz",
|
||||
"integrity": "sha512-BXmDZpPlh7jwicKArQASrj8n22/w6iymRnvHYYd2zO30DbE277JO20/7yXJT3QxDPtiQiOxQBbZH4TpivNXIxA==",
|
||||
"version": "7.25.1",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.25.1.tgz",
|
||||
"integrity": "sha512-TVVJVdW9RKMNgJJlLtHsKDTydjZAbwIsn6ySBPQaEAUU5+gVvlJt/9nRmqVbsV/IBanRjzWoaAQKLoamWVOUuA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/helper-compilation-targets": "^7.23.6",
|
||||
"@babel/helper-function-name": "^7.23.0",
|
||||
"@babel/helper-plugin-utils": "^7.24.0"
|
||||
"@babel/helper-compilation-targets": "^7.24.8",
|
||||
"@babel/helper-plugin-utils": "^7.24.8",
|
||||
"@babel/traverse": "^7.25.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
@@ -1094,11 +1155,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/plugin-transform-json-strings": {
|
||||
"version": "7.24.1",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.24.1.tgz",
|
||||
"integrity": "sha512-U7RMFmRvoasscrIFy5xA4gIp8iWnWubnKkKuUGJjsuOH7GfbMkB+XZzeslx2kLdEGdOJDamEmCqOks6e8nv8DQ==",
|
||||
"version": "7.24.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.24.7.tgz",
|
||||
"integrity": "sha512-2yFnBGDvRuxAaE/f0vfBKvtnvvqU8tGpMHqMNpTN2oWMKIR3NqFkjaAgGwawhqK/pIN2T3XdjGPdaG0vDhOBGw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/helper-plugin-utils": "^7.24.0",
|
||||
"@babel/helper-plugin-utils": "^7.24.7",
|
||||
"@babel/plugin-syntax-json-strings": "^7.8.3"
|
||||
},
|
||||
"engines": {
|
||||
@@ -1109,11 +1171,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/plugin-transform-literals": {
|
||||
"version": "7.24.1",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.24.1.tgz",
|
||||
"integrity": "sha512-zn9pwz8U7nCqOYIiBaOxoQOtYmMODXTJnkxG4AtX8fPmnCRYWBOHD0qcpwS9e2VDSp1zNJYpdnFMIKb8jmwu6g==",
|
||||
"version": "7.25.2",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.25.2.tgz",
|
||||
"integrity": "sha512-HQI+HcTbm9ur3Z2DkO+jgESMAMcYLuN/A7NRw9juzxAezN9AvqvUTnpKP/9kkYANz6u7dFlAyOu44ejuGySlfw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/helper-plugin-utils": "^7.24.0"
|
||||
"@babel/helper-plugin-utils": "^7.24.8"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
@@ -1123,11 +1186,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/plugin-transform-logical-assignment-operators": {
|
||||
"version": "7.24.1",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.24.1.tgz",
|
||||
"integrity": "sha512-OhN6J4Bpz+hIBqItTeWJujDOfNP+unqv/NJgyhlpSqgBTPm37KkMmZV6SYcOj+pnDbdcl1qRGV/ZiIjX9Iy34w==",
|
||||
"version": "7.24.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.24.7.tgz",
|
||||
"integrity": "sha512-4D2tpwlQ1odXmTEIFWy9ELJcZHqrStlzK/dAOWYyxX3zT0iXQB6banjgeOJQXzEc4S0E0a5A+hahxPaEFYftsw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/helper-plugin-utils": "^7.24.0",
|
||||
"@babel/helper-plugin-utils": "^7.24.7",
|
||||
"@babel/plugin-syntax-logical-assignment-operators": "^7.10.4"
|
||||
},
|
||||
"engines": {
|
||||
@@ -1138,11 +1202,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/plugin-transform-member-expression-literals": {
|
||||
"version": "7.24.1",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.24.1.tgz",
|
||||
"integrity": "sha512-4ojai0KysTWXzHseJKa1XPNXKRbuUrhkOPY4rEGeR+7ChlJVKxFa3H3Bz+7tWaGKgJAXUWKOGmltN+u9B3+CVg==",
|
||||
"version": "7.24.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.24.7.tgz",
|
||||
"integrity": "sha512-T/hRC1uqrzXMKLQ6UCwMT85S3EvqaBXDGf0FaMf4446Qx9vKwlghvee0+uuZcDUCZU5RuNi4781UQ7R308zzBw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/helper-plugin-utils": "^7.24.0"
|
||||
"@babel/helper-plugin-utils": "^7.24.7"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
@@ -1152,12 +1217,13 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/plugin-transform-modules-amd": {
|
||||
"version": "7.24.1",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.24.1.tgz",
|
||||
"integrity": "sha512-lAxNHi4HVtjnHd5Rxg3D5t99Xm6H7b04hUS7EHIXcUl2EV4yl1gWdqZrNzXnSrHveL9qMdbODlLF55mvgjAfaQ==",
|
||||
"version": "7.24.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.24.7.tgz",
|
||||
"integrity": "sha512-9+pB1qxV3vs/8Hdmz/CulFB8w2tuu6EB94JZFsjdqxQokwGa9Unap7Bo2gGBGIvPmDIVvQrom7r5m/TCDMURhg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/helper-module-transforms": "^7.23.3",
|
||||
"@babel/helper-plugin-utils": "^7.24.0"
|
||||
"@babel/helper-module-transforms": "^7.24.7",
|
||||
"@babel/helper-plugin-utils": "^7.24.7"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
@@ -1167,13 +1233,14 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/plugin-transform-modules-commonjs": {
|
||||
"version": "7.24.1",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.24.1.tgz",
|
||||
"integrity": "sha512-szog8fFTUxBfw0b98gEWPaEqF42ZUD/T3bkynW/wtgx2p/XCP55WEsb+VosKceRSd6njipdZvNogqdtI4Q0chw==",
|
||||
"version": "7.24.8",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.24.8.tgz",
|
||||
"integrity": "sha512-WHsk9H8XxRs3JXKWFiqtQebdh9b/pTk4EgueygFzYlTKAg0Ud985mSevdNjdXdFBATSKVJGQXP1tv6aGbssLKA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/helper-module-transforms": "^7.23.3",
|
||||
"@babel/helper-plugin-utils": "^7.24.0",
|
||||
"@babel/helper-simple-access": "^7.22.5"
|
||||
"@babel/helper-module-transforms": "^7.24.8",
|
||||
"@babel/helper-plugin-utils": "^7.24.8",
|
||||
"@babel/helper-simple-access": "^7.24.7"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
@@ -1183,14 +1250,15 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/plugin-transform-modules-systemjs": {
|
||||
"version": "7.24.1",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.24.1.tgz",
|
||||
"integrity": "sha512-mqQ3Zh9vFO1Tpmlt8QPnbwGHzNz3lpNEMxQb1kAemn/erstyqw1r9KeOlOfo3y6xAnFEcOv2tSyrXfmMk+/YZA==",
|
||||
"version": "7.25.0",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.25.0.tgz",
|
||||
"integrity": "sha512-YPJfjQPDXxyQWg/0+jHKj1llnY5f/R6a0p/vP4lPymxLu7Lvl4k2WMitqi08yxwQcCVUUdG9LCUj4TNEgAp3Jw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/helper-hoist-variables": "^7.22.5",
|
||||
"@babel/helper-module-transforms": "^7.23.3",
|
||||
"@babel/helper-plugin-utils": "^7.24.0",
|
||||
"@babel/helper-validator-identifier": "^7.22.20"
|
||||
"@babel/helper-module-transforms": "^7.25.0",
|
||||
"@babel/helper-plugin-utils": "^7.24.8",
|
||||
"@babel/helper-validator-identifier": "^7.24.7",
|
||||
"@babel/traverse": "^7.25.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
@@ -1200,12 +1268,13 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/plugin-transform-modules-umd": {
|
||||
"version": "7.24.1",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.24.1.tgz",
|
||||
"integrity": "sha512-tuA3lpPj+5ITfcCluy6nWonSL7RvaG0AOTeAuvXqEKS34lnLzXpDb0dcP6K8jD0zWZFNDVly90AGFJPnm4fOYg==",
|
||||
"version": "7.24.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.24.7.tgz",
|
||||
"integrity": "sha512-3aytQvqJ/h9z4g8AsKPLvD4Zqi2qT+L3j7XoFFu1XBlZWEl2/1kWnhmAbxpLgPrHSY0M6UA02jyTiwUVtiKR6A==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/helper-module-transforms": "^7.23.3",
|
||||
"@babel/helper-plugin-utils": "^7.24.0"
|
||||
"@babel/helper-module-transforms": "^7.24.7",
|
||||
"@babel/helper-plugin-utils": "^7.24.7"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
@@ -1215,12 +1284,13 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/plugin-transform-named-capturing-groups-regex": {
|
||||
"version": "7.22.5",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.22.5.tgz",
|
||||
"integrity": "sha512-YgLLKmS3aUBhHaxp5hi1WJTgOUb/NCuDHzGT9z9WTt3YG+CPRhJs6nprbStx6DnWM4dh6gt7SU3sZodbZ08adQ==",
|
||||
"version": "7.24.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.24.7.tgz",
|
||||
"integrity": "sha512-/jr7h/EWeJtk1U/uz2jlsCioHkZk1JJZVcc8oQsJ1dUlaJD83f4/6Zeh2aHt9BIFokHIsSeDfhUmju0+1GPd6g==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/helper-create-regexp-features-plugin": "^7.22.5",
|
||||
"@babel/helper-plugin-utils": "^7.22.5"
|
||||
"@babel/helper-create-regexp-features-plugin": "^7.24.7",
|
||||
"@babel/helper-plugin-utils": "^7.24.7"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
@@ -1230,11 +1300,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/plugin-transform-new-target": {
|
||||
"version": "7.24.1",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.24.1.tgz",
|
||||
"integrity": "sha512-/rurytBM34hYy0HKZQyA0nHbQgQNFm4Q/BOc9Hflxi2X3twRof7NaE5W46j4kQitm7SvACVRXsa6N/tSZxvPug==",
|
||||
"version": "7.24.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.24.7.tgz",
|
||||
"integrity": "sha512-RNKwfRIXg4Ls/8mMTza5oPF5RkOW8Wy/WgMAp1/F1yZ8mMbtwXW+HDoJiOsagWrAhI5f57Vncrmr9XeT4CVapA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/helper-plugin-utils": "^7.24.0"
|
||||
"@babel/helper-plugin-utils": "^7.24.7"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
@@ -1244,11 +1315,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/plugin-transform-nullish-coalescing-operator": {
|
||||
"version": "7.24.1",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.24.1.tgz",
|
||||
"integrity": "sha512-iQ+caew8wRrhCikO5DrUYx0mrmdhkaELgFa+7baMcVuhxIkN7oxt06CZ51D65ugIb1UWRQ8oQe+HXAVM6qHFjw==",
|
||||
"version": "7.24.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.24.7.tgz",
|
||||
"integrity": "sha512-Ts7xQVk1OEocqzm8rHMXHlxvsfZ0cEF2yomUqpKENHWMF4zKk175Y4q8H5knJes6PgYad50uuRmt3UJuhBw8pQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/helper-plugin-utils": "^7.24.0",
|
||||
"@babel/helper-plugin-utils": "^7.24.7",
|
||||
"@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3"
|
||||
},
|
||||
"engines": {
|
||||
@@ -1259,11 +1331,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/plugin-transform-numeric-separator": {
|
||||
"version": "7.24.1",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.24.1.tgz",
|
||||
"integrity": "sha512-7GAsGlK4cNL2OExJH1DzmDeKnRv/LXq0eLUSvudrehVA5Rgg4bIrqEUW29FbKMBRT0ztSqisv7kjP+XIC4ZMNw==",
|
||||
"version": "7.24.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.24.7.tgz",
|
||||
"integrity": "sha512-e6q1TiVUzvH9KRvicuxdBTUj4AdKSRwzIyFFnfnezpCfP2/7Qmbb8qbU2j7GODbl4JMkblitCQjKYUaX/qkkwA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/helper-plugin-utils": "^7.24.0",
|
||||
"@babel/helper-plugin-utils": "^7.24.7",
|
||||
"@babel/plugin-syntax-numeric-separator": "^7.10.4"
|
||||
},
|
||||
"engines": {
|
||||
@@ -1274,11 +1347,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/plugin-transform-object-assign": {
|
||||
"version": "7.24.1",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-assign/-/plugin-transform-object-assign-7.24.1.tgz",
|
||||
"integrity": "sha512-I1kctor9iKtupb7jv7FyjApHCuKLBKCblVAeHVK9PB6FW7GI0ac6RtobC3MwwJy8CZ1JxuhQmnbrsqI5G8hAIg==",
|
||||
"version": "7.24.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-assign/-/plugin-transform-object-assign-7.24.7.tgz",
|
||||
"integrity": "sha512-DOzAi77P9jSyPijHS7Z8vH0wLRcZH6wWxuIZgLAiy8FWOkcKMJmnyHjy2JM94k6A0QxlA/hlLh+R9T3GEryjNQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/helper-plugin-utils": "^7.24.0"
|
||||
"@babel/helper-plugin-utils": "^7.24.7"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
@@ -1288,14 +1362,15 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/plugin-transform-object-rest-spread": {
|
||||
"version": "7.24.1",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.24.1.tgz",
|
||||
"integrity": "sha512-XjD5f0YqOtebto4HGISLNfiNMTTs6tbkFf2TOqJlYKYmbo+mN9Dnpl4SRoofiziuOWMIyq3sZEUqLo3hLITFEA==",
|
||||
"version": "7.24.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.24.7.tgz",
|
||||
"integrity": "sha512-4QrHAr0aXQCEFni2q4DqKLD31n2DL+RxcwnNjDFkSG0eNQ/xCavnRkfCUjsyqGC2OviNJvZOF/mQqZBw7i2C5Q==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/helper-compilation-targets": "^7.23.6",
|
||||
"@babel/helper-plugin-utils": "^7.24.0",
|
||||
"@babel/helper-compilation-targets": "^7.24.7",
|
||||
"@babel/helper-plugin-utils": "^7.24.7",
|
||||
"@babel/plugin-syntax-object-rest-spread": "^7.8.3",
|
||||
"@babel/plugin-transform-parameters": "^7.24.1"
|
||||
"@babel/plugin-transform-parameters": "^7.24.7"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
@@ -1305,12 +1380,13 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/plugin-transform-object-super": {
|
||||
"version": "7.24.1",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.24.1.tgz",
|
||||
"integrity": "sha512-oKJqR3TeI5hSLRxudMjFQ9re9fBVUU0GICqM3J1mi8MqlhVr6hC/ZN4ttAyMuQR6EZZIY6h/exe5swqGNNIkWQ==",
|
||||
"version": "7.24.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.24.7.tgz",
|
||||
"integrity": "sha512-A/vVLwN6lBrMFmMDmPPz0jnE6ZGx7Jq7d6sT/Ev4H65RER6pZ+kczlf1DthF5N0qaPHBsI7UXiE8Zy66nmAovg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/helper-plugin-utils": "^7.24.0",
|
||||
"@babel/helper-replace-supers": "^7.24.1"
|
||||
"@babel/helper-plugin-utils": "^7.24.7",
|
||||
"@babel/helper-replace-supers": "^7.24.7"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
@@ -1320,11 +1396,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/plugin-transform-optional-catch-binding": {
|
||||
"version": "7.24.1",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.24.1.tgz",
|
||||
"integrity": "sha512-oBTH7oURV4Y+3EUrf6cWn1OHio3qG/PVwO5J03iSJmBg6m2EhKjkAu/xuaXaYwWW9miYtvbWv4LNf0AmR43LUA==",
|
||||
"version": "7.24.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.24.7.tgz",
|
||||
"integrity": "sha512-uLEndKqP5BfBbC/5jTwPxLh9kqPWWgzN/f8w6UwAIirAEqiIVJWWY312X72Eub09g5KF9+Zn7+hT7sDxmhRuKA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/helper-plugin-utils": "^7.24.0",
|
||||
"@babel/helper-plugin-utils": "^7.24.7",
|
||||
"@babel/plugin-syntax-optional-catch-binding": "^7.8.3"
|
||||
},
|
||||
"engines": {
|
||||
@@ -1335,12 +1412,13 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/plugin-transform-optional-chaining": {
|
||||
"version": "7.24.1",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.24.1.tgz",
|
||||
"integrity": "sha512-n03wmDt+987qXwAgcBlnUUivrZBPZ8z1plL0YvgQalLm+ZE5BMhGm94jhxXtA1wzv1Cu2aaOv1BM9vbVttrzSg==",
|
||||
"version": "7.24.8",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.24.8.tgz",
|
||||
"integrity": "sha512-5cTOLSMs9eypEy8JUVvIKOu6NgvbJMnpG62VpIHrTmROdQ+L5mDAaI40g25k5vXti55JWNX5jCkq3HZxXBQANw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/helper-plugin-utils": "^7.24.0",
|
||||
"@babel/helper-skip-transparent-expression-wrappers": "^7.22.5",
|
||||
"@babel/helper-plugin-utils": "^7.24.8",
|
||||
"@babel/helper-skip-transparent-expression-wrappers": "^7.24.7",
|
||||
"@babel/plugin-syntax-optional-chaining": "^7.8.3"
|
||||
},
|
||||
"engines": {
|
||||
@@ -1351,11 +1429,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/plugin-transform-parameters": {
|
||||
"version": "7.24.1",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.24.1.tgz",
|
||||
"integrity": "sha512-8Jl6V24g+Uw5OGPeWNKrKqXPDw2YDjLc53ojwfMcKwlEoETKU9rU0mHUtcg9JntWI/QYzGAXNWEcVHZ+fR+XXg==",
|
||||
"version": "7.24.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.24.7.tgz",
|
||||
"integrity": "sha512-yGWW5Rr+sQOhK0Ot8hjDJuxU3XLRQGflvT4lhlSY0DFvdb3TwKaY26CJzHtYllU0vT9j58hc37ndFPsqT1SrzA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/helper-plugin-utils": "^7.24.0"
|
||||
"@babel/helper-plugin-utils": "^7.24.7"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
@@ -1365,12 +1444,13 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/plugin-transform-private-methods": {
|
||||
"version": "7.24.1",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.24.1.tgz",
|
||||
"integrity": "sha512-tGvisebwBO5em4PaYNqt4fkw56K2VALsAbAakY0FjTYqJp7gfdrgr7YX76Or8/cpik0W6+tj3rZ0uHU9Oil4tw==",
|
||||
"version": "7.24.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.24.7.tgz",
|
||||
"integrity": "sha512-COTCOkG2hn4JKGEKBADkA8WNb35TGkkRbI5iT845dB+NyqgO8Hn+ajPbSnIQznneJTa3d30scb6iz/DhH8GsJQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/helper-create-class-features-plugin": "^7.24.1",
|
||||
"@babel/helper-plugin-utils": "^7.24.0"
|
||||
"@babel/helper-create-class-features-plugin": "^7.24.7",
|
||||
"@babel/helper-plugin-utils": "^7.24.7"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
@@ -1380,13 +1460,14 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/plugin-transform-private-property-in-object": {
|
||||
"version": "7.24.1",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.24.1.tgz",
|
||||
"integrity": "sha512-pTHxDVa0BpUbvAgX3Gat+7cSciXqUcY9j2VZKTbSB6+VQGpNgNO9ailxTGHSXlqOnX1Hcx1Enme2+yv7VqP9bg==",
|
||||
"version": "7.24.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.24.7.tgz",
|
||||
"integrity": "sha512-9z76mxwnwFxMyxZWEgdgECQglF2Q7cFLm0kMf8pGwt+GSJsY0cONKj/UuO4bOH0w/uAel3ekS4ra5CEAyJRmDA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/helper-annotate-as-pure": "^7.22.5",
|
||||
"@babel/helper-create-class-features-plugin": "^7.24.1",
|
||||
"@babel/helper-plugin-utils": "^7.24.0",
|
||||
"@babel/helper-annotate-as-pure": "^7.24.7",
|
||||
"@babel/helper-create-class-features-plugin": "^7.24.7",
|
||||
"@babel/helper-plugin-utils": "^7.24.7",
|
||||
"@babel/plugin-syntax-private-property-in-object": "^7.14.5"
|
||||
},
|
||||
"engines": {
|
||||
@@ -1397,11 +1478,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/plugin-transform-property-literals": {
|
||||
"version": "7.24.1",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.24.1.tgz",
|
||||
"integrity": "sha512-LetvD7CrHmEx0G442gOomRr66d7q8HzzGGr4PMHGr+5YIm6++Yke+jxj246rpvsbyhJwCLxcTn6zW1P1BSenqA==",
|
||||
"version": "7.24.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.24.7.tgz",
|
||||
"integrity": "sha512-EMi4MLQSHfd2nrCqQEWxFdha2gBCqU4ZcCng4WBGZ5CJL4bBRW0ptdqqDdeirGZcpALazVVNJqRmsO8/+oNCBA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/helper-plugin-utils": "^7.24.0"
|
||||
"@babel/helper-plugin-utils": "^7.24.7"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
@@ -1411,11 +1493,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/plugin-transform-react-display-name": {
|
||||
"version": "7.24.1",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.24.1.tgz",
|
||||
"integrity": "sha512-mvoQg2f9p2qlpDQRBC7M3c3XTr0k7cp/0+kFKKO/7Gtu0LSw16eKB+Fabe2bDT/UpsyasTBBkAnbdsLrkD5XMw==",
|
||||
"version": "7.24.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.24.7.tgz",
|
||||
"integrity": "sha512-H/Snz9PFxKsS1JLI4dJLtnJgCJRoo0AUm3chP6NYr+9En1JMKloheEiLIhlp5MDVznWo+H3AAC1Mc8lmUEpsgg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/helper-plugin-utils": "^7.24.0"
|
||||
"@babel/helper-plugin-utils": "^7.24.7"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
@@ -1425,15 +1508,16 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/plugin-transform-react-jsx": {
|
||||
"version": "7.23.4",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.23.4.tgz",
|
||||
"integrity": "sha512-5xOpoPguCZCRbo/JeHlloSkTA8Bld1J/E1/kLfD1nsuiW1m8tduTA1ERCgIZokDflX/IBzKcqR3l7VlRgiIfHA==",
|
||||
"version": "7.25.2",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.25.2.tgz",
|
||||
"integrity": "sha512-KQsqEAVBpU82NM/B/N9j9WOdphom1SZH3R+2V7INrQUH+V9EBFwZsEJl8eBIVeQE62FxJCc70jzEZwqU7RcVqA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/helper-annotate-as-pure": "^7.22.5",
|
||||
"@babel/helper-module-imports": "^7.22.15",
|
||||
"@babel/helper-plugin-utils": "^7.22.5",
|
||||
"@babel/plugin-syntax-jsx": "^7.23.3",
|
||||
"@babel/types": "^7.23.4"
|
||||
"@babel/helper-annotate-as-pure": "^7.24.7",
|
||||
"@babel/helper-module-imports": "^7.24.7",
|
||||
"@babel/helper-plugin-utils": "^7.24.8",
|
||||
"@babel/plugin-syntax-jsx": "^7.24.7",
|
||||
"@babel/types": "^7.25.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
@@ -1443,11 +1527,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/plugin-transform-react-jsx-development": {
|
||||
"version": "7.22.5",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.22.5.tgz",
|
||||
"integrity": "sha512-bDhuzwWMuInwCYeDeMzyi7TaBgRQei6DqxhbyniL7/VG4RSS7HtSL2QbY4eESy1KJqlWt8g3xeEBGPuo+XqC8A==",
|
||||
"version": "7.24.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.24.7.tgz",
|
||||
"integrity": "sha512-QG9EnzoGn+Qar7rxuW+ZOsbWOt56FvvI93xInqsZDC5fsekx1AlIO4KIJ5M+D0p0SqSH156EpmZyXq630B8OlQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/plugin-transform-react-jsx": "^7.22.5"
|
||||
"@babel/plugin-transform-react-jsx": "^7.24.7"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
@@ -1457,12 +1542,13 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/plugin-transform-react-pure-annotations": {
|
||||
"version": "7.24.1",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-pure-annotations/-/plugin-transform-react-pure-annotations-7.24.1.tgz",
|
||||
"integrity": "sha512-+pWEAaDJvSm9aFvJNpLiM2+ktl2Sn2U5DdyiWdZBxmLc6+xGt88dvFqsHiAiDS+8WqUwbDfkKz9jRxK3M0k+kA==",
|
||||
"version": "7.24.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-pure-annotations/-/plugin-transform-react-pure-annotations-7.24.7.tgz",
|
||||
"integrity": "sha512-PLgBVk3fzbmEjBJ/u8kFzOqS9tUeDjiaWud/rRym/yjCo/M9cASPlnrd2ZmmZpQT40fOOrvR8jh+n8jikrOhNA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/helper-annotate-as-pure": "^7.22.5",
|
||||
"@babel/helper-plugin-utils": "^7.24.0"
|
||||
"@babel/helper-annotate-as-pure": "^7.24.7",
|
||||
"@babel/helper-plugin-utils": "^7.24.7"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
@@ -1472,11 +1558,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/plugin-transform-regenerator": {
|
||||
"version": "7.24.1",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.24.1.tgz",
|
||||
"integrity": "sha512-sJwZBCzIBE4t+5Q4IGLaaun5ExVMRY0lYwos/jNecjMrVCygCdph3IKv0tkP5Fc87e/1+bebAmEAGBfnRD+cnw==",
|
||||
"version": "7.24.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.24.7.tgz",
|
||||
"integrity": "sha512-lq3fvXPdimDrlg6LWBoqj+r/DEWgONuwjuOuQCSYgRroXDH/IdM1C0IZf59fL5cHLpjEH/O6opIRBbqv7ELnuA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/helper-plugin-utils": "^7.24.0",
|
||||
"@babel/helper-plugin-utils": "^7.24.7",
|
||||
"regenerator-transform": "^0.15.2"
|
||||
},
|
||||
"engines": {
|
||||
@@ -1487,11 +1574,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/plugin-transform-reserved-words": {
|
||||
"version": "7.24.1",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.24.1.tgz",
|
||||
"integrity": "sha512-JAclqStUfIwKN15HrsQADFgeZt+wexNQ0uLhuqvqAUFoqPMjEcFCYZBhq0LUdz6dZK/mD+rErhW71fbx8RYElg==",
|
||||
"version": "7.24.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.24.7.tgz",
|
||||
"integrity": "sha512-0DUq0pHcPKbjFZCfTss/pGkYMfy3vFWydkUBd9r0GHpIyfs2eCDENvqadMycRS9wZCXR41wucAfJHJmwA0UmoQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/helper-plugin-utils": "^7.24.0"
|
||||
"@babel/helper-plugin-utils": "^7.24.7"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
@@ -1501,11 +1589,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/plugin-transform-shorthand-properties": {
|
||||
"version": "7.24.1",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.24.1.tgz",
|
||||
"integrity": "sha512-LyjVB1nsJ6gTTUKRjRWx9C1s9hE7dLfP/knKdrfeH9UPtAGjYGgxIbFfx7xyLIEWs7Xe1Gnf8EWiUqfjLhInZA==",
|
||||
"version": "7.24.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.24.7.tgz",
|
||||
"integrity": "sha512-KsDsevZMDsigzbA09+vacnLpmPH4aWjcZjXdyFKGzpplxhbeB4wYtury3vglQkg6KM/xEPKt73eCjPPf1PgXBA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/helper-plugin-utils": "^7.24.0"
|
||||
"@babel/helper-plugin-utils": "^7.24.7"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
@@ -1515,12 +1604,13 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/plugin-transform-spread": {
|
||||
"version": "7.24.1",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.24.1.tgz",
|
||||
"integrity": "sha512-KjmcIM+fxgY+KxPVbjelJC6hrH1CgtPmTvdXAfn3/a9CnWGSTY7nH4zm5+cjmWJybdcPSsD0++QssDsjcpe47g==",
|
||||
"version": "7.24.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.24.7.tgz",
|
||||
"integrity": "sha512-x96oO0I09dgMDxJaANcRyD4ellXFLLiWhuwDxKZX5g2rWP1bTPkBSwCYv96VDXVT1bD9aPj8tppr5ITIh8hBng==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/helper-plugin-utils": "^7.24.0",
|
||||
"@babel/helper-skip-transparent-expression-wrappers": "^7.22.5"
|
||||
"@babel/helper-plugin-utils": "^7.24.7",
|
||||
"@babel/helper-skip-transparent-expression-wrappers": "^7.24.7"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
@@ -1530,11 +1620,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/plugin-transform-sticky-regex": {
|
||||
"version": "7.24.1",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.24.1.tgz",
|
||||
"integrity": "sha512-9v0f1bRXgPVcPrngOQvLXeGNNVLc8UjMVfebo9ka0WF3/7+aVUHmaJVT3sa0XCzEFioPfPHZiOcYG9qOsH63cw==",
|
||||
"version": "7.24.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.24.7.tgz",
|
||||
"integrity": "sha512-kHPSIJc9v24zEml5geKg9Mjx5ULpfncj0wRpYtxbvKyTtHCYDkVE3aHQ03FrpEo4gEe2vrJJS1Y9CJTaThA52g==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/helper-plugin-utils": "^7.24.0"
|
||||
"@babel/helper-plugin-utils": "^7.24.7"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
@@ -1544,11 +1635,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/plugin-transform-template-literals": {
|
||||
"version": "7.24.1",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.24.1.tgz",
|
||||
"integrity": "sha512-WRkhROsNzriarqECASCNu/nojeXCDTE/F2HmRgOzi7NGvyfYGq1NEjKBK3ckLfRgGc6/lPAqP0vDOSw3YtG34g==",
|
||||
"version": "7.24.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.24.7.tgz",
|
||||
"integrity": "sha512-AfDTQmClklHCOLxtGoP7HkeMw56k1/bTQjwsfhL6pppo/M4TOBSq+jjBUBLmV/4oeFg4GWMavIl44ZeCtmmZTw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/helper-plugin-utils": "^7.24.0"
|
||||
"@babel/helper-plugin-utils": "^7.24.7"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
@@ -1558,11 +1650,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/plugin-transform-typeof-symbol": {
|
||||
"version": "7.24.1",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.24.1.tgz",
|
||||
"integrity": "sha512-CBfU4l/A+KruSUoW+vTQthwcAdwuqbpRNB8HQKlZABwHRhsdHZ9fezp4Sn18PeAlYxTNiLMlx4xUBV3AWfg1BA==",
|
||||
"version": "7.24.8",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.24.8.tgz",
|
||||
"integrity": "sha512-adNTUpDCVnmAE58VEqKlAA6ZBlNkMnWD0ZcW76lyNFN3MJniyGFZfNwERVk8Ap56MCnXztmDr19T4mPTztcuaw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/helper-plugin-utils": "^7.24.0"
|
||||
"@babel/helper-plugin-utils": "^7.24.8"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
@@ -1572,11 +1665,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/plugin-transform-unicode-escapes": {
|
||||
"version": "7.24.1",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.24.1.tgz",
|
||||
"integrity": "sha512-RlkVIcWT4TLI96zM660S877E7beKlQw7Ig+wqkKBiWfj0zH5Q4h50q6er4wzZKRNSYpfo6ILJ+hrJAGSX2qcNw==",
|
||||
"version": "7.24.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.24.7.tgz",
|
||||
"integrity": "sha512-U3ap1gm5+4edc2Q/P+9VrBNhGkfnf+8ZqppY71Bo/pzZmXhhLdqgaUl6cuB07O1+AQJtCLfaOmswiNbSQ9ivhw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/helper-plugin-utils": "^7.24.0"
|
||||
"@babel/helper-plugin-utils": "^7.24.7"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
@@ -1586,12 +1680,13 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/plugin-transform-unicode-property-regex": {
|
||||
"version": "7.24.1",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.24.1.tgz",
|
||||
"integrity": "sha512-Ss4VvlfYV5huWApFsF8/Sq0oXnGO+jB+rijFEFugTd3cwSObUSnUi88djgR5528Csl0uKlrI331kRqe56Ov2Ng==",
|
||||
"version": "7.24.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.24.7.tgz",
|
||||
"integrity": "sha512-uH2O4OV5M9FZYQrwc7NdVmMxQJOCCzFeYudlZSzUAHRFeOujQefa92E74TQDVskNHCzOXoigEuoyzHDhaEaK5w==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/helper-create-regexp-features-plugin": "^7.22.15",
|
||||
"@babel/helper-plugin-utils": "^7.24.0"
|
||||
"@babel/helper-create-regexp-features-plugin": "^7.24.7",
|
||||
"@babel/helper-plugin-utils": "^7.24.7"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
@@ -1601,12 +1696,13 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/plugin-transform-unicode-regex": {
|
||||
"version": "7.24.1",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.24.1.tgz",
|
||||
"integrity": "sha512-2A/94wgZgxfTsiLaQ2E36XAOdcZmGAaEEgVmxQWwZXWkGhvoHbaqXcKnU8zny4ycpu3vNqg0L/PcCiYtHtA13g==",
|
||||
"version": "7.24.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.24.7.tgz",
|
||||
"integrity": "sha512-hlQ96MBZSAXUq7ltkjtu3FJCCSMx/j629ns3hA3pXnBXjanNP0LHi+JpPeA81zaWgVK1VGH95Xuy7u0RyQ8kMg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/helper-create-regexp-features-plugin": "^7.22.15",
|
||||
"@babel/helper-plugin-utils": "^7.24.0"
|
||||
"@babel/helper-create-regexp-features-plugin": "^7.24.7",
|
||||
"@babel/helper-plugin-utils": "^7.24.7"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
@@ -1616,12 +1712,13 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/plugin-transform-unicode-sets-regex": {
|
||||
"version": "7.24.1",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.24.1.tgz",
|
||||
"integrity": "sha512-fqj4WuzzS+ukpgerpAoOnMfQXwUHFxXUZUE84oL2Kao2N8uSlvcpnAidKASgsNgzZHBsHWvcm8s9FPWUhAb8fA==",
|
||||
"version": "7.24.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.24.7.tgz",
|
||||
"integrity": "sha512-2G8aAvF4wy1w/AGZkemprdGMRg5o6zPNhbHVImRz3lss55TYCBd6xStN19rt8XJHq20sqV0JbyWjOWwQRwV/wg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/helper-create-regexp-features-plugin": "^7.22.15",
|
||||
"@babel/helper-plugin-utils": "^7.24.0"
|
||||
"@babel/helper-create-regexp-features-plugin": "^7.24.7",
|
||||
"@babel/helper-plugin-utils": "^7.24.7"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
@@ -1641,25 +1738,28 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/preset-env": {
|
||||
"version": "7.24.3",
|
||||
"resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.24.3.tgz",
|
||||
"integrity": "sha512-fSk430k5c2ff8536JcPvPWK4tZDwehWLGlBp0wrsBUjZVdeQV6lePbwKWZaZfK2vnh/1kQX1PzAJWsnBmVgGJA==",
|
||||
"version": "7.25.3",
|
||||
"resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.25.3.tgz",
|
||||
"integrity": "sha512-QsYW7UeAaXvLPX9tdVliMJE7MD7M6MLYVTovRTIwhoYQVFHR1rM4wO8wqAezYi3/BpSD+NzVCZ69R6smWiIi8g==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/compat-data": "^7.24.1",
|
||||
"@babel/helper-compilation-targets": "^7.23.6",
|
||||
"@babel/helper-plugin-utils": "^7.24.0",
|
||||
"@babel/helper-validator-option": "^7.23.5",
|
||||
"@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.24.1",
|
||||
"@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.24.1",
|
||||
"@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.24.1",
|
||||
"@babel/compat-data": "^7.25.2",
|
||||
"@babel/helper-compilation-targets": "^7.25.2",
|
||||
"@babel/helper-plugin-utils": "^7.24.8",
|
||||
"@babel/helper-validator-option": "^7.24.8",
|
||||
"@babel/plugin-bugfix-firefox-class-in-computed-class-key": "^7.25.3",
|
||||
"@babel/plugin-bugfix-safari-class-field-initializer-scope": "^7.25.0",
|
||||
"@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.25.0",
|
||||
"@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.24.7",
|
||||
"@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.25.0",
|
||||
"@babel/plugin-proposal-private-property-in-object": "7.21.0-placeholder-for-preset-env.2",
|
||||
"@babel/plugin-syntax-async-generators": "^7.8.4",
|
||||
"@babel/plugin-syntax-class-properties": "^7.12.13",
|
||||
"@babel/plugin-syntax-class-static-block": "^7.14.5",
|
||||
"@babel/plugin-syntax-dynamic-import": "^7.8.3",
|
||||
"@babel/plugin-syntax-export-namespace-from": "^7.8.3",
|
||||
"@babel/plugin-syntax-import-assertions": "^7.24.1",
|
||||
"@babel/plugin-syntax-import-attributes": "^7.24.1",
|
||||
"@babel/plugin-syntax-import-assertions": "^7.24.7",
|
||||
"@babel/plugin-syntax-import-attributes": "^7.24.7",
|
||||
"@babel/plugin-syntax-import-meta": "^7.10.4",
|
||||
"@babel/plugin-syntax-json-strings": "^7.8.3",
|
||||
"@babel/plugin-syntax-logical-assignment-operators": "^7.10.4",
|
||||
@@ -1671,59 +1771,60 @@
|
||||
"@babel/plugin-syntax-private-property-in-object": "^7.14.5",
|
||||
"@babel/plugin-syntax-top-level-await": "^7.14.5",
|
||||
"@babel/plugin-syntax-unicode-sets-regex": "^7.18.6",
|
||||
"@babel/plugin-transform-arrow-functions": "^7.24.1",
|
||||
"@babel/plugin-transform-async-generator-functions": "^7.24.3",
|
||||
"@babel/plugin-transform-async-to-generator": "^7.24.1",
|
||||
"@babel/plugin-transform-block-scoped-functions": "^7.24.1",
|
||||
"@babel/plugin-transform-block-scoping": "^7.24.1",
|
||||
"@babel/plugin-transform-class-properties": "^7.24.1",
|
||||
"@babel/plugin-transform-class-static-block": "^7.24.1",
|
||||
"@babel/plugin-transform-classes": "^7.24.1",
|
||||
"@babel/plugin-transform-computed-properties": "^7.24.1",
|
||||
"@babel/plugin-transform-destructuring": "^7.24.1",
|
||||
"@babel/plugin-transform-dotall-regex": "^7.24.1",
|
||||
"@babel/plugin-transform-duplicate-keys": "^7.24.1",
|
||||
"@babel/plugin-transform-dynamic-import": "^7.24.1",
|
||||
"@babel/plugin-transform-exponentiation-operator": "^7.24.1",
|
||||
"@babel/plugin-transform-export-namespace-from": "^7.24.1",
|
||||
"@babel/plugin-transform-for-of": "^7.24.1",
|
||||
"@babel/plugin-transform-function-name": "^7.24.1",
|
||||
"@babel/plugin-transform-json-strings": "^7.24.1",
|
||||
"@babel/plugin-transform-literals": "^7.24.1",
|
||||
"@babel/plugin-transform-logical-assignment-operators": "^7.24.1",
|
||||
"@babel/plugin-transform-member-expression-literals": "^7.24.1",
|
||||
"@babel/plugin-transform-modules-amd": "^7.24.1",
|
||||
"@babel/plugin-transform-modules-commonjs": "^7.24.1",
|
||||
"@babel/plugin-transform-modules-systemjs": "^7.24.1",
|
||||
"@babel/plugin-transform-modules-umd": "^7.24.1",
|
||||
"@babel/plugin-transform-named-capturing-groups-regex": "^7.22.5",
|
||||
"@babel/plugin-transform-new-target": "^7.24.1",
|
||||
"@babel/plugin-transform-nullish-coalescing-operator": "^7.24.1",
|
||||
"@babel/plugin-transform-numeric-separator": "^7.24.1",
|
||||
"@babel/plugin-transform-object-rest-spread": "^7.24.1",
|
||||
"@babel/plugin-transform-object-super": "^7.24.1",
|
||||
"@babel/plugin-transform-optional-catch-binding": "^7.24.1",
|
||||
"@babel/plugin-transform-optional-chaining": "^7.24.1",
|
||||
"@babel/plugin-transform-parameters": "^7.24.1",
|
||||
"@babel/plugin-transform-private-methods": "^7.24.1",
|
||||
"@babel/plugin-transform-private-property-in-object": "^7.24.1",
|
||||
"@babel/plugin-transform-property-literals": "^7.24.1",
|
||||
"@babel/plugin-transform-regenerator": "^7.24.1",
|
||||
"@babel/plugin-transform-reserved-words": "^7.24.1",
|
||||
"@babel/plugin-transform-shorthand-properties": "^7.24.1",
|
||||
"@babel/plugin-transform-spread": "^7.24.1",
|
||||
"@babel/plugin-transform-sticky-regex": "^7.24.1",
|
||||
"@babel/plugin-transform-template-literals": "^7.24.1",
|
||||
"@babel/plugin-transform-typeof-symbol": "^7.24.1",
|
||||
"@babel/plugin-transform-unicode-escapes": "^7.24.1",
|
||||
"@babel/plugin-transform-unicode-property-regex": "^7.24.1",
|
||||
"@babel/plugin-transform-unicode-regex": "^7.24.1",
|
||||
"@babel/plugin-transform-unicode-sets-regex": "^7.24.1",
|
||||
"@babel/plugin-transform-arrow-functions": "^7.24.7",
|
||||
"@babel/plugin-transform-async-generator-functions": "^7.25.0",
|
||||
"@babel/plugin-transform-async-to-generator": "^7.24.7",
|
||||
"@babel/plugin-transform-block-scoped-functions": "^7.24.7",
|
||||
"@babel/plugin-transform-block-scoping": "^7.25.0",
|
||||
"@babel/plugin-transform-class-properties": "^7.24.7",
|
||||
"@babel/plugin-transform-class-static-block": "^7.24.7",
|
||||
"@babel/plugin-transform-classes": "^7.25.0",
|
||||
"@babel/plugin-transform-computed-properties": "^7.24.7",
|
||||
"@babel/plugin-transform-destructuring": "^7.24.8",
|
||||
"@babel/plugin-transform-dotall-regex": "^7.24.7",
|
||||
"@babel/plugin-transform-duplicate-keys": "^7.24.7",
|
||||
"@babel/plugin-transform-duplicate-named-capturing-groups-regex": "^7.25.0",
|
||||
"@babel/plugin-transform-dynamic-import": "^7.24.7",
|
||||
"@babel/plugin-transform-exponentiation-operator": "^7.24.7",
|
||||
"@babel/plugin-transform-export-namespace-from": "^7.24.7",
|
||||
"@babel/plugin-transform-for-of": "^7.24.7",
|
||||
"@babel/plugin-transform-function-name": "^7.25.1",
|
||||
"@babel/plugin-transform-json-strings": "^7.24.7",
|
||||
"@babel/plugin-transform-literals": "^7.25.2",
|
||||
"@babel/plugin-transform-logical-assignment-operators": "^7.24.7",
|
||||
"@babel/plugin-transform-member-expression-literals": "^7.24.7",
|
||||
"@babel/plugin-transform-modules-amd": "^7.24.7",
|
||||
"@babel/plugin-transform-modules-commonjs": "^7.24.8",
|
||||
"@babel/plugin-transform-modules-systemjs": "^7.25.0",
|
||||
"@babel/plugin-transform-modules-umd": "^7.24.7",
|
||||
"@babel/plugin-transform-named-capturing-groups-regex": "^7.24.7",
|
||||
"@babel/plugin-transform-new-target": "^7.24.7",
|
||||
"@babel/plugin-transform-nullish-coalescing-operator": "^7.24.7",
|
||||
"@babel/plugin-transform-numeric-separator": "^7.24.7",
|
||||
"@babel/plugin-transform-object-rest-spread": "^7.24.7",
|
||||
"@babel/plugin-transform-object-super": "^7.24.7",
|
||||
"@babel/plugin-transform-optional-catch-binding": "^7.24.7",
|
||||
"@babel/plugin-transform-optional-chaining": "^7.24.8",
|
||||
"@babel/plugin-transform-parameters": "^7.24.7",
|
||||
"@babel/plugin-transform-private-methods": "^7.24.7",
|
||||
"@babel/plugin-transform-private-property-in-object": "^7.24.7",
|
||||
"@babel/plugin-transform-property-literals": "^7.24.7",
|
||||
"@babel/plugin-transform-regenerator": "^7.24.7",
|
||||
"@babel/plugin-transform-reserved-words": "^7.24.7",
|
||||
"@babel/plugin-transform-shorthand-properties": "^7.24.7",
|
||||
"@babel/plugin-transform-spread": "^7.24.7",
|
||||
"@babel/plugin-transform-sticky-regex": "^7.24.7",
|
||||
"@babel/plugin-transform-template-literals": "^7.24.7",
|
||||
"@babel/plugin-transform-typeof-symbol": "^7.24.8",
|
||||
"@babel/plugin-transform-unicode-escapes": "^7.24.7",
|
||||
"@babel/plugin-transform-unicode-property-regex": "^7.24.7",
|
||||
"@babel/plugin-transform-unicode-regex": "^7.24.7",
|
||||
"@babel/plugin-transform-unicode-sets-regex": "^7.24.7",
|
||||
"@babel/preset-modules": "0.1.6-no-external-plugins",
|
||||
"babel-plugin-polyfill-corejs2": "^0.4.10",
|
||||
"babel-plugin-polyfill-corejs3": "^0.10.4",
|
||||
"babel-plugin-polyfill-regenerator": "^0.6.1",
|
||||
"core-js-compat": "^3.31.0",
|
||||
"core-js-compat": "^3.37.1",
|
||||
"semver": "^6.3.1"
|
||||
},
|
||||
"engines": {
|
||||
@@ -1747,16 +1848,17 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/preset-react": {
|
||||
"version": "7.18.6",
|
||||
"resolved": "https://registry.npmjs.org/@babel/preset-react/-/preset-react-7.18.6.tgz",
|
||||
"integrity": "sha512-zXr6atUmyYdiWRVLOZahakYmOBHtWc2WGCkP8PYTgZi0iJXDY2CN180TdrIW4OGOAdLc7TifzDIvtx6izaRIzg==",
|
||||
"version": "7.24.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/preset-react/-/preset-react-7.24.7.tgz",
|
||||
"integrity": "sha512-AAH4lEkpmzFWrGVlHaxJB7RLH21uPQ9+He+eFLWHmF9IuFQVugz8eAsamaW0DXRrTfco5zj1wWtpdcXJUOfsag==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/helper-plugin-utils": "^7.18.6",
|
||||
"@babel/helper-validator-option": "^7.18.6",
|
||||
"@babel/plugin-transform-react-display-name": "^7.18.6",
|
||||
"@babel/plugin-transform-react-jsx": "^7.18.6",
|
||||
"@babel/plugin-transform-react-jsx-development": "^7.18.6",
|
||||
"@babel/plugin-transform-react-pure-annotations": "^7.18.6"
|
||||
"@babel/helper-plugin-utils": "^7.24.7",
|
||||
"@babel/helper-validator-option": "^7.24.7",
|
||||
"@babel/plugin-transform-react-display-name": "^7.24.7",
|
||||
"@babel/plugin-transform-react-jsx": "^7.24.7",
|
||||
"@babel/plugin-transform-react-jsx-development": "^7.24.7",
|
||||
"@babel/plugin-transform-react-pure-annotations": "^7.24.7"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
@@ -1787,31 +1889,30 @@
|
||||
"integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw=="
|
||||
},
|
||||
"node_modules/@babel/template": {
|
||||
"version": "7.24.0",
|
||||
"resolved": "https://registry.npmjs.org/@babel/template/-/template-7.24.0.tgz",
|
||||
"integrity": "sha512-Bkf2q8lMB0AFpX0NFEqSbx1OkTHf0f+0j82mkw+ZpzBnkk7e9Ql0891vlfgi+kHwOk8tQjiQHpqh4LaSa0fKEA==",
|
||||
"version": "7.25.0",
|
||||
"resolved": "https://registry.npmjs.org/@babel/template/-/template-7.25.0.tgz",
|
||||
"integrity": "sha512-aOOgh1/5XzKvg1jvVz7AVrx2piJ2XBi227DHmbY6y+bM9H2FlN+IfecYu4Xl0cNiiVejlsCri89LUsbj8vJD9Q==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/code-frame": "^7.23.5",
|
||||
"@babel/parser": "^7.24.0",
|
||||
"@babel/types": "^7.24.0"
|
||||
"@babel/code-frame": "^7.24.7",
|
||||
"@babel/parser": "^7.25.0",
|
||||
"@babel/types": "^7.25.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/traverse": {
|
||||
"version": "7.24.1",
|
||||
"resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.24.1.tgz",
|
||||
"integrity": "sha512-xuU6o9m68KeqZbQuDt2TcKSxUw/mrsvavlEqQ1leZ/B+C9tk6E4sRWy97WaXgvq5E+nU3cXMxv3WKOCanVMCmQ==",
|
||||
"version": "7.25.3",
|
||||
"resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.25.3.tgz",
|
||||
"integrity": "sha512-HefgyP1x754oGCsKmV5reSmtV7IXj/kpaE1XYY+D9G5PvKKoFfSbiS4M77MdjuwlZKDIKFCffq9rPU+H/s3ZdQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/code-frame": "^7.24.1",
|
||||
"@babel/generator": "^7.24.1",
|
||||
"@babel/helper-environment-visitor": "^7.22.20",
|
||||
"@babel/helper-function-name": "^7.23.0",
|
||||
"@babel/helper-hoist-variables": "^7.22.5",
|
||||
"@babel/helper-split-export-declaration": "^7.22.6",
|
||||
"@babel/parser": "^7.24.1",
|
||||
"@babel/types": "^7.24.0",
|
||||
"@babel/code-frame": "^7.24.7",
|
||||
"@babel/generator": "^7.25.0",
|
||||
"@babel/parser": "^7.25.3",
|
||||
"@babel/template": "^7.25.0",
|
||||
"@babel/types": "^7.25.2",
|
||||
"debug": "^4.3.1",
|
||||
"globals": "^11.1.0"
|
||||
},
|
||||
@@ -1820,12 +1921,13 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/types": {
|
||||
"version": "7.24.0",
|
||||
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.24.0.tgz",
|
||||
"integrity": "sha512-+j7a5c253RfKh8iABBhywc8NSfP5LURe7Uh4qpsh6jc+aLJguvmIUBdjSdEMQv2bENrCR5MfRdjGo7vzS/ob7w==",
|
||||
"version": "7.25.2",
|
||||
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.25.2.tgz",
|
||||
"integrity": "sha512-YTnYtra7W9e6/oAZEHj0bJehPRUlLH9/fbpT5LfB0NhQXyALCRkRs3zH9v07IYhkgpqX6Z78FnuccZr/l4Fs4Q==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/helper-string-parser": "^7.23.4",
|
||||
"@babel/helper-validator-identifier": "^7.22.20",
|
||||
"@babel/helper-string-parser": "^7.24.8",
|
||||
"@babel/helper-validator-identifier": "^7.24.7",
|
||||
"to-fast-properties": "^2.0.0"
|
||||
},
|
||||
"engines": {
|
||||
@@ -4552,15 +4654,6 @@
|
||||
"node": ">=0.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/adm-zip": {
|
||||
"version": "0.4.16",
|
||||
"resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.4.16.tgz",
|
||||
"integrity": "sha512-TFi4HBKSGfIKsK5YCkKaaFG2m4PEDyViZmEwof3MTIgzimHLto6muaHVpbrljdIvIrFZzEq/p4nafOeLcYegrg==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=0.3.0"
|
||||
}
|
||||
},
|
||||
"node_modules/after": {
|
||||
"version": "0.8.2",
|
||||
"resolved": "https://registry.npmjs.org/after/-/after-0.8.2.tgz",
|
||||
@@ -5439,16 +5532,17 @@
|
||||
"integrity": "sha512-m2CvfDW4+1qfDdsrtf4dwOslQC3yhbgyBFptncp4wvtdrDHqueW7slsYv4gArie056phvQFhT2nRcGS4bnm6mA=="
|
||||
},
|
||||
"node_modules/babel-jest": {
|
||||
"version": "26.0.0",
|
||||
"resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-26.0.0.tgz",
|
||||
"integrity": "sha512-2AtcYOP4xhFn6TkvGmbEArNBcYLm/cTOIXB1a5j2juPOIC2U0nHEouMqYzgnPXgWC+CBK5RmYoGnwRt6eV4E8A==",
|
||||
"version": "26.6.3",
|
||||
"resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-26.6.3.tgz",
|
||||
"integrity": "sha512-pl4Q+GAVOHwvjrck6jKjvmGhnO3jHX/xuB9d27f+EJZ/6k+6nMuPjorrYp7s++bKKdANwzElBWnLWaObvTnaZA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@jest/transform": "^26.0.0",
|
||||
"@jest/types": "^26.0.0",
|
||||
"@jest/transform": "^26.6.2",
|
||||
"@jest/types": "^26.6.2",
|
||||
"@types/babel__core": "^7.1.7",
|
||||
"babel-plugin-istanbul": "^6.0.0",
|
||||
"babel-preset-jest": "^26.0.0",
|
||||
"babel-preset-jest": "^26.6.2",
|
||||
"chalk": "^4.0.0",
|
||||
"graceful-fs": "^4.2.4",
|
||||
"slash": "^3.0.0"
|
||||
@@ -5465,6 +5559,7 @@
|
||||
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
|
||||
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"color-convert": "^2.0.1"
|
||||
},
|
||||
@@ -5480,6 +5575,7 @@
|
||||
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
|
||||
"integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"ansi-styles": "^4.1.0",
|
||||
"supports-color": "^7.1.0"
|
||||
@@ -5496,6 +5592,7 @@
|
||||
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
|
||||
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"color-name": "~1.1.4"
|
||||
},
|
||||
@@ -5507,13 +5604,15 @@
|
||||
"version": "1.1.4",
|
||||
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
|
||||
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
|
||||
"dev": true
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/babel-jest/node_modules/has-flag": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
|
||||
"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
@@ -5523,6 +5622,7 @@
|
||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
|
||||
"integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"has-flag": "^4.0.0"
|
||||
},
|
||||
@@ -5956,9 +6056,10 @@
|
||||
}
|
||||
},
|
||||
"node_modules/backbone": {
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmjs.org/backbone/-/backbone-1.4.1.tgz",
|
||||
"integrity": "sha512-ADy1ztN074YkWbHi8ojJVFe3vAanO/lrzMGZWUClIP7oDD/Pjy2vrASraUP+2EVCfIiTtCW4FChVow01XneivA==",
|
||||
"version": "1.6.0",
|
||||
"resolved": "https://registry.npmjs.org/backbone/-/backbone-1.6.0.tgz",
|
||||
"integrity": "sha512-13PUjmsgw/49EowNcQvfG4gmczz1ximTMhUktj0Jfrjth0MVaTxehpU+qYYX4MxnuIuhmvBLC6/ayxuAGnOhbA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"underscore": ">=1.8.3"
|
||||
}
|
||||
@@ -6199,9 +6300,9 @@
|
||||
"integrity": "sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow=="
|
||||
},
|
||||
"node_modules/browserslist": {
|
||||
"version": "4.23.0",
|
||||
"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.0.tgz",
|
||||
"integrity": "sha512-QW8HiM1shhT2GuzkvklfjcKDiWFXHOeFCIA/huJPwHsslwcydgk7X+z2zXpEijP98UCY7HbubZt5J2Zgvf0CaQ==",
|
||||
"version": "4.23.3",
|
||||
"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.3.tgz",
|
||||
"integrity": "sha512-btwCFJVjI4YWDNfau8RhZ+B1Q/VLoUITrm3RlP6y1tYGWIOa+InuYiRGXUBXo8nA1qKmHMyLB/iVQg5TT4eFoA==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "opencollective",
|
||||
@@ -6216,11 +6317,12 @@
|
||||
"url": "https://github.com/sponsors/ai"
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"caniuse-lite": "^1.0.30001587",
|
||||
"electron-to-chromium": "^1.4.668",
|
||||
"node-releases": "^2.0.14",
|
||||
"update-browserslist-db": "^1.0.13"
|
||||
"caniuse-lite": "^1.0.30001646",
|
||||
"electron-to-chromium": "^1.5.4",
|
||||
"node-releases": "^2.0.18",
|
||||
"update-browserslist-db": "^1.1.0"
|
||||
},
|
||||
"bin": {
|
||||
"browserslist": "cli.js"
|
||||
@@ -6499,9 +6601,9 @@
|
||||
"integrity": "sha512-BS+RAD1DggiDlE2KaBUWKsMDuVmmh3hCM5LI0OW25mGlPttGLeOjDUa1DmZvJVFCXvtshY4BTyFgv31eFTLg8g=="
|
||||
},
|
||||
"node_modules/caniuse-lite": {
|
||||
"version": "1.0.30001600",
|
||||
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001600.tgz",
|
||||
"integrity": "sha512-+2S9/2JFhYmYaDpZvo0lKkfvuKIglrx68MwOBqMGHhQsNkLjB5xtc/TGoEPs+MxjSyN/72qer2g97nzR641mOQ==",
|
||||
"version": "1.0.30001651",
|
||||
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001651.tgz",
|
||||
"integrity": "sha512-9Cf+Xv1jJNe1xPZLGuUXLNkE1BoDkqRqYyFJ9TDYSqhduqA4hu4oR9HluGoWYQC/aj8WHjsGVV+bwkh0+tegRg==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "opencollective",
|
||||
@@ -6515,7 +6617,8 @@
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ai"
|
||||
}
|
||||
]
|
||||
],
|
||||
"license": "CC-BY-4.0"
|
||||
},
|
||||
"node_modules/capture-exit": {
|
||||
"version": "2.0.0",
|
||||
@@ -7288,7 +7391,8 @@
|
||||
"node_modules/convert-source-map": {
|
||||
"version": "1.9.0",
|
||||
"resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz",
|
||||
"integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A=="
|
||||
"integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/cookie": {
|
||||
"version": "0.3.1",
|
||||
@@ -7324,11 +7428,12 @@
|
||||
"hasInstallScript": true
|
||||
},
|
||||
"node_modules/core-js-compat": {
|
||||
"version": "3.36.1",
|
||||
"resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.36.1.tgz",
|
||||
"integrity": "sha512-Dk997v9ZCt3X/npqzyGdTlq6t7lDBhZwGvV94PKzDArjp7BTRm7WlDAXYd/OWdeFHO8OChQYRJNJvUCqCbrtKA==",
|
||||
"version": "3.38.0",
|
||||
"resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.38.0.tgz",
|
||||
"integrity": "sha512-75LAicdLa4OJVwFxFbQR3NdnZjNgX6ILpVcVzcC4T2smerB5lELMrJQQQoWV6TiuC/vlaFqgU2tKQx9w5s0e0A==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"browserslist": "^4.23.0"
|
||||
"browserslist": "^4.23.3"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
@@ -8130,15 +8235,6 @@
|
||||
"urijs": "1.19.11"
|
||||
}
|
||||
},
|
||||
"node_modules/edx-ui-toolkit/node_modules/backbone": {
|
||||
"version": "1.6.0",
|
||||
"resolved": "https://registry.npmjs.org/backbone/-/backbone-1.6.0.tgz",
|
||||
"integrity": "sha512-13PUjmsgw/49EowNcQvfG4gmczz1ximTMhUktj0Jfrjth0MVaTxehpU+qYYX4MxnuIuhmvBLC6/ayxuAGnOhbA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"underscore": ">=1.8.3"
|
||||
}
|
||||
},
|
||||
"node_modules/edx-ui-toolkit/node_modules/formatio": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/formatio/-/formatio-1.1.1.tgz",
|
||||
@@ -8204,9 +8300,10 @@
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/electron-to-chromium": {
|
||||
"version": "1.4.717",
|
||||
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.717.tgz",
|
||||
"integrity": "sha512-6Fmg8QkkumNOwuZ/5mIbMU9WI3H2fmn5ajcVya64I5Yr5CcNmO7vcLt0Y7c96DCiMO5/9G+4sI2r6eEvdg1F7A=="
|
||||
"version": "1.5.6",
|
||||
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.6.tgz",
|
||||
"integrity": "sha512-jwXWsM5RPf6j9dPYzaorcBSUg6AiqocPEyMpkchkvntaH9HGfOOMZwxMJjDY/XEs3T5dM7uyH1VhRMkqUU9qVw==",
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/email-prop-type": {
|
||||
"version": "1.1.7",
|
||||
@@ -8861,6 +8958,7 @@
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz",
|
||||
"integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
@@ -11419,6 +11517,13 @@
|
||||
"node": ">= 4"
|
||||
}
|
||||
},
|
||||
"node_modules/immediate": {
|
||||
"version": "3.0.6",
|
||||
"resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz",
|
||||
"integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/immutable": {
|
||||
"version": "4.3.5",
|
||||
"resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.5.tgz",
|
||||
@@ -12746,14 +12851,15 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/jest": {
|
||||
"version": "26.0.0",
|
||||
"resolved": "https://registry.npmjs.org/jest/-/jest-26.0.0.tgz",
|
||||
"integrity": "sha512-OtoG+cpcP+UXx+pQ7rzoQ11Pfb5+OUkrsNn5YPc0GU2HeBktgTANonUZEgT6cCgUHX7jUiuDIusDNTL4iNcWGQ==",
|
||||
"version": "26.6.3",
|
||||
"resolved": "https://registry.npmjs.org/jest/-/jest-26.6.3.tgz",
|
||||
"integrity": "sha512-lGS5PXGAzR4RF7V5+XObhqz2KZIDUA1yD0DG6pBVmy10eh0ZIXQImRuzocsI/N2XZ1GrLFwTS27In2i2jlpq1Q==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@jest/core": "^26.0.0",
|
||||
"@jest/core": "^26.6.3",
|
||||
"import-local": "^3.0.2",
|
||||
"jest-cli": "^26.0.0"
|
||||
"jest-cli": "^26.6.3"
|
||||
},
|
||||
"bin": {
|
||||
"jest": "bin/jest.js"
|
||||
@@ -12925,28 +13031,6 @@
|
||||
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/jest-config/node_modules/babel-jest": {
|
||||
"version": "26.6.3",
|
||||
"resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-26.6.3.tgz",
|
||||
"integrity": "sha512-pl4Q+GAVOHwvjrck6jKjvmGhnO3jHX/xuB9d27f+EJZ/6k+6nMuPjorrYp7s++bKKdANwzElBWnLWaObvTnaZA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@jest/transform": "^26.6.2",
|
||||
"@jest/types": "^26.6.2",
|
||||
"@types/babel__core": "^7.1.7",
|
||||
"babel-plugin-istanbul": "^6.0.0",
|
||||
"babel-preset-jest": "^26.6.2",
|
||||
"chalk": "^4.0.0",
|
||||
"graceful-fs": "^4.2.4",
|
||||
"slash": "^3.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 10.14.2"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@babel/core": "^7.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/jest-config/node_modules/chalk": {
|
||||
"version": "4.1.2",
|
||||
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
|
||||
@@ -13709,14 +13793,15 @@
|
||||
}
|
||||
},
|
||||
"node_modules/jest-enzyme": {
|
||||
"version": "6.0.2",
|
||||
"resolved": "https://registry.npmjs.org/jest-enzyme/-/jest-enzyme-6.0.2.tgz",
|
||||
"integrity": "sha512-lf6tjFA5Lthcazqx1acwo/rTjIKIsOp2jbZCZSi1WmRX0JHOJXa5NfioaaJ4wJeIWoIShU/9Go0OjKCXiAzCAg==",
|
||||
"version": "6.1.2",
|
||||
"resolved": "https://registry.npmjs.org/jest-enzyme/-/jest-enzyme-6.1.2.tgz",
|
||||
"integrity": "sha512-+ds7r2ru3QkNJxelQ2tnC6d33pjUSsZHPD3v4TlnHlNMuGX3UKdxm5C46yZBvJICYBvIF+RFKBhLMM4evNM95Q==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"enzyme-matchers": "^6.0.2",
|
||||
"enzyme-matchers": "^6.1.2",
|
||||
"enzyme-to-json": "^3.3.0",
|
||||
"jest-environment-enzyme": "^6.0.2"
|
||||
"jest-environment-enzyme": "^6.1.2"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"enzyme": "3.x",
|
||||
@@ -15251,6 +15336,59 @@
|
||||
"node": ">=4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/jszip": {
|
||||
"version": "3.10.1",
|
||||
"resolved": "https://registry.npmjs.org/jszip/-/jszip-3.10.1.tgz",
|
||||
"integrity": "sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==",
|
||||
"dev": true,
|
||||
"license": "(MIT OR GPL-3.0-or-later)",
|
||||
"dependencies": {
|
||||
"lie": "~3.3.0",
|
||||
"pako": "~1.0.2",
|
||||
"readable-stream": "~2.3.6",
|
||||
"setimmediate": "^1.0.5"
|
||||
}
|
||||
},
|
||||
"node_modules/jszip/node_modules/isarray": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
|
||||
"integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/jszip/node_modules/readable-stream": {
|
||||
"version": "2.3.8",
|
||||
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz",
|
||||
"integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"core-util-is": "~1.0.0",
|
||||
"inherits": "~2.0.3",
|
||||
"isarray": "~1.0.0",
|
||||
"process-nextick-args": "~2.0.0",
|
||||
"safe-buffer": "~5.1.1",
|
||||
"string_decoder": "~1.1.1",
|
||||
"util-deprecate": "~1.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/jszip/node_modules/safe-buffer": {
|
||||
"version": "5.1.2",
|
||||
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
|
||||
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/jszip/node_modules/string_decoder": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
|
||||
"integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"safe-buffer": "~5.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/karma": {
|
||||
"version": "0.13.22",
|
||||
"resolved": "https://registry.npmjs.org/karma/-/karma-0.13.22.tgz",
|
||||
@@ -15555,10 +15693,11 @@
|
||||
}
|
||||
},
|
||||
"node_modules/karma-junit-reporter": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/karma-junit-reporter/-/karma-junit-reporter-1.1.0.tgz",
|
||||
"integrity": "sha512-Iucb7SsKqYxn7azHltDHSI2wNzZ7MEzCQjZPNStEAlxyJMkX5OBWd0D6Sesy/mMKh9FltLDqe23hsZFyNvIKxQ==",
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/karma-junit-reporter/-/karma-junit-reporter-1.2.0.tgz",
|
||||
"integrity": "sha512-FeuLOKlXNtJhIQK3oQASbO5QOib762CEHV8+L9wwTQpiZJgp7xKg3sNno66rL5bQPV2soG6fJdAFWqqnMJuh2w==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"path-is-absolute": "^1.0.0",
|
||||
"xmlbuilder": "8.2.2"
|
||||
@@ -15591,12 +15730,13 @@
|
||||
}
|
||||
},
|
||||
"node_modules/karma-sourcemap-loader": {
|
||||
"version": "0.3.7",
|
||||
"resolved": "https://registry.npmjs.org/karma-sourcemap-loader/-/karma-sourcemap-loader-0.3.7.tgz",
|
||||
"integrity": "sha512-zu99gTgKf6KhLg14c+e+SHb297A8MX9TRxjW+USEmk/xq2ULnyvkfZuOZOLHU6522QfJai1SZznP/brNwivtDg==",
|
||||
"version": "0.4.0",
|
||||
"resolved": "https://registry.npmjs.org/karma-sourcemap-loader/-/karma-sourcemap-loader-0.4.0.tgz",
|
||||
"integrity": "sha512-xCRL3/pmhAYF3I6qOrcn0uhbQevitc2DERMPH82FMnG+4WReoGcGFZb1pURf2a5apyrOHRdvD+O6K7NljqKHyA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"graceful-fs": "^4.1.2"
|
||||
"graceful-fs": "^4.2.10"
|
||||
}
|
||||
},
|
||||
"node_modules/karma-spec-reporter": {
|
||||
@@ -15790,6 +15930,16 @@
|
||||
"node": ">= 0.8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/lie": {
|
||||
"version": "3.3.0",
|
||||
"resolved": "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz",
|
||||
"integrity": "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"immediate": "~3.0.5"
|
||||
}
|
||||
},
|
||||
"node_modules/lines-and-columns": {
|
||||
"version": "1.2.4",
|
||||
"resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz",
|
||||
@@ -17143,9 +17293,10 @@
|
||||
"optional": true
|
||||
},
|
||||
"node_modules/node-releases": {
|
||||
"version": "2.0.14",
|
||||
"resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz",
|
||||
"integrity": "sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw=="
|
||||
"version": "2.0.18",
|
||||
"resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.18.tgz",
|
||||
"integrity": "sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/nopt": {
|
||||
"version": "3.0.6",
|
||||
@@ -17713,6 +17864,13 @@
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/pako": {
|
||||
"version": "1.0.11",
|
||||
"resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz",
|
||||
"integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==",
|
||||
"dev": true,
|
||||
"license": "(MIT AND Zlib)"
|
||||
},
|
||||
"node_modules/parent-module": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
|
||||
@@ -17946,9 +18104,10 @@
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/picocolors": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz",
|
||||
"integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ=="
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.1.tgz",
|
||||
"integrity": "sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==",
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/picomatch": {
|
||||
"version": "2.3.1",
|
||||
@@ -19971,18 +20130,31 @@
|
||||
}
|
||||
},
|
||||
"node_modules/react-test-renderer": {
|
||||
"version": "16.4.0",
|
||||
"resolved": "https://registry.npmjs.org/react-test-renderer/-/react-test-renderer-16.4.0.tgz",
|
||||
"integrity": "sha512-Seh1t9xFY6TKiV/hRlPzUkqX1xHOiKIMsctfU0cggo1ajsLjoIJFL520LlrxV+4/VIj+clrCeH6s/aVv/vTStg==",
|
||||
"version": "16.14.0",
|
||||
"resolved": "https://registry.npmjs.org/react-test-renderer/-/react-test-renderer-16.14.0.tgz",
|
||||
"integrity": "sha512-L8yPjqPE5CZO6rKsKXRO/rVPiaCOy0tQQJbC+UjPNlobl5mad59lvPjwFsQHTvL03caVDIVr9x9/OSgDe6I5Eg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"fbjs": "^0.8.16",
|
||||
"object-assign": "^4.1.1",
|
||||
"prop-types": "^15.6.0",
|
||||
"react-is": "^16.4.0"
|
||||
"prop-types": "^15.6.2",
|
||||
"react-is": "^16.8.6",
|
||||
"scheduler": "^0.19.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "^16.0.0"
|
||||
"react": "^16.14.0"
|
||||
}
|
||||
},
|
||||
"node_modules/react-test-renderer/node_modules/prop-types": {
|
||||
"version": "15.8.1",
|
||||
"resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz",
|
||||
"integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"loose-envify": "^1.4.0",
|
||||
"object-assign": "^4.1.1",
|
||||
"react-is": "^16.13.1"
|
||||
}
|
||||
},
|
||||
"node_modules/react-transition-group": {
|
||||
@@ -20862,9 +21034,10 @@
|
||||
}
|
||||
},
|
||||
"node_modules/requirejs": {
|
||||
"version": "2.3.6",
|
||||
"resolved": "https://registry.npmjs.org/requirejs/-/requirejs-2.3.6.tgz",
|
||||
"integrity": "sha512-ipEzlWQe6RK3jkzikgCupiTbTvm4S0/CAU5GlgptkN5SO6F3u0UD0K18wy6ErDqiCyP4J4YYe1HuAShvsxePLg==",
|
||||
"version": "2.3.7",
|
||||
"resolved": "https://registry.npmjs.org/requirejs/-/requirejs-2.3.7.tgz",
|
||||
"integrity": "sha512-DouTG8T1WanGok6Qjg2SXuCMzszOo0eHeH9hDZ5Y4x8Je+9JB38HdTLT4/VA8OaUhBa0JPVHJ0pyBkM1z+pDsw==",
|
||||
"license": "MIT",
|
||||
"bin": {
|
||||
"r_js": "bin/r.js",
|
||||
"r.js": "bin/r.js"
|
||||
@@ -21968,12 +22141,13 @@
|
||||
"integrity": "sha512-qGVDoreyYiP1pkQnbnFAUIS5AjenNwwQBdl7zeos9etl+hYKWahjRTfzAZZYBv5xNHx7vNKCmaLDQZ6Fr2AEXg=="
|
||||
},
|
||||
"node_modules/selenium-webdriver": {
|
||||
"version": "3.4.0",
|
||||
"resolved": "https://registry.npmjs.org/selenium-webdriver/-/selenium-webdriver-3.4.0.tgz",
|
||||
"integrity": "sha512-Bfq9FX33fFSj0F26BaaZllQBZl3d9FykVaH4CEJfwtN43+V8jrTpuhfiR5Zm9nkXjMbcEQz2EKWAjNzV8Hkqbw==",
|
||||
"version": "3.6.0",
|
||||
"resolved": "https://registry.npmjs.org/selenium-webdriver/-/selenium-webdriver-3.6.0.tgz",
|
||||
"integrity": "sha512-WH7Aldse+2P5bbFBO4Gle/nuQOdVwpHMTL6raL3uuBj/vPG07k6uzt3aiahu352ONBr5xXh0hDlM3LhtXPOC4Q==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"adm-zip": "^0.4.7",
|
||||
"jszip": "^3.1.3",
|
||||
"rimraf": "^2.5.4",
|
||||
"tmp": "0.0.30",
|
||||
"xml2js": "^0.4.17"
|
||||
@@ -21986,7 +22160,9 @@
|
||||
"version": "2.7.1",
|
||||
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz",
|
||||
"integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==",
|
||||
"deprecated": "Rimraf versions prior to v4 are no longer supported",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"glob": "^7.1.3"
|
||||
},
|
||||
@@ -24613,9 +24789,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/update-browserslist-db": {
|
||||
"version": "1.0.13",
|
||||
"resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz",
|
||||
"integrity": "sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==",
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.0.tgz",
|
||||
"integrity": "sha512-EdRAaAyk2cUE1wOf2DkEhzxqOQvFOoRJFNS6NeyJ01Gp2beMRpBAINjM2iDXE3KCuKhwnvHIQCJm6ThL2Z+HzQ==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "opencollective",
|
||||
@@ -24630,9 +24806,10 @@
|
||||
"url": "https://github.com/sponsors/ai"
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"escalade": "^3.1.1",
|
||||
"picocolors": "^1.0.0"
|
||||
"escalade": "^3.1.2",
|
||||
"picocolors": "^1.0.1"
|
||||
},
|
||||
"bin": {
|
||||
"update-browserslist-db": "cli.js"
|
||||
|
||||
22
package.json
22
package.json
@@ -15,11 +15,11 @@
|
||||
"watch-sass": "scripts/watch_sass.sh"
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/core": "7.19.0",
|
||||
"@babel/core": "7.25.2",
|
||||
"@babel/plugin-proposal-object-rest-spread": "^7.18.9",
|
||||
"@babel/plugin-transform-object-assign": "^7.18.6",
|
||||
"@babel/preset-env": "^7.19.0",
|
||||
"@babel/preset-react": "7.18.6",
|
||||
"@babel/preset-react": "7.24.7",
|
||||
"@edx/brand-edx.org": "^2.0.7",
|
||||
"@edx/edx-bootstrap": "1.0.4",
|
||||
"@edx/edx-proctoring": "^4.18.1",
|
||||
@@ -29,7 +29,7 @@
|
||||
"babel-loader": "^9.1.3",
|
||||
"babel-plugin-transform-class-properties": "6.24.1",
|
||||
"babel-polyfill": "6.26.0",
|
||||
"backbone": "1.4.1",
|
||||
"backbone": "1.6.0",
|
||||
"backbone-associations": "0.6.2",
|
||||
"backbone.paginator": "2.0.8",
|
||||
"bootstrap": "4.0.0",
|
||||
@@ -65,7 +65,7 @@
|
||||
"react-slick": "0.29.0",
|
||||
"redux": "3.7.2",
|
||||
"redux-thunk": "2.2.0",
|
||||
"requirejs": "2.3.6",
|
||||
"requirejs": "2.3.7",
|
||||
"rtlcss": "2.6.2",
|
||||
"sass": "^1.54.8",
|
||||
"sass-loader": "^14.1.1",
|
||||
@@ -85,29 +85,29 @@
|
||||
"@edx/eslint-config": "^3.1.1",
|
||||
"@edx/mockprock": "github:openedx/mockprock#3ad18c6888e6521e9bf7a4df0db6f8579b928235",
|
||||
"@edx/stylelint-config-edx": "2.3.3",
|
||||
"babel-jest": "26.0.0",
|
||||
"babel-jest": "26.6.3",
|
||||
"enzyme": "3.11.0",
|
||||
"enzyme-adapter-react-16": "1.15.8",
|
||||
"eslint-import-resolver-webpack": "0.13.8",
|
||||
"jasmine-core": "2.6.4",
|
||||
"jasmine-jquery": "git+https://git@github.com/velesin/jasmine-jquery.git#ebad463d592d3fea00c69f26ea18a930e09c7b58",
|
||||
"jest": "26.0.0",
|
||||
"jest-enzyme": "6.0.2",
|
||||
"jest": "26.6.3",
|
||||
"jest-enzyme": "6.1.2",
|
||||
"karma": "0.13.22",
|
||||
"karma-chrome-launcher": "0.2.3",
|
||||
"karma-coverage": "0.5.5",
|
||||
"karma-firefox-launcher": "0.1.7",
|
||||
"karma-jasmine": "0.3.8",
|
||||
"karma-jasmine-html-reporter": "0.2.2",
|
||||
"karma-junit-reporter": "1.1.0",
|
||||
"karma-junit-reporter": "1.2.0",
|
||||
"karma-requirejs": "0.2.6",
|
||||
"karma-selenium-webdriver-launcher": "github:openedx/karma-selenium-webdriver-launcher#0.0.4-openedx.0",
|
||||
"karma-sourcemap-loader": "0.3.7",
|
||||
"karma-sourcemap-loader": "0.4.0",
|
||||
"karma-spec-reporter": "0.0.36",
|
||||
"karma-webpack": "^5.0.1",
|
||||
"plato": "1.7.0",
|
||||
"react-test-renderer": "16.4.0",
|
||||
"selenium-webdriver": "3.4.0",
|
||||
"react-test-renderer": "16.14.0",
|
||||
"selenium-webdriver": "3.6.0",
|
||||
"sinon": "2.4.1",
|
||||
"squirejs": "0.1.0",
|
||||
"string-replace-loader": "^3.1.0",
|
||||
|
||||
@@ -26,15 +26,6 @@ elasticsearch<7.14.0
|
||||
|
||||
# django-simple-history>3.0.0 adds indexing and causes a lot of migrations to be affected
|
||||
|
||||
# opentelemetry requires version 6.x at the moment:
|
||||
# https://github.com/open-telemetry/opentelemetry-python/issues/3570
|
||||
# Normally this could be added as a constraint in edx-django-utils, where we're
|
||||
# adding the opentelemetry dependency. However, when we compile pip-tools.txt,
|
||||
# that uses version 7.x, and then there's no undoing that when compiling base.txt.
|
||||
# So we need to pin it globally, for now.
|
||||
# Ticket for unpinning: https://github.com/openedx/edx-lint/issues/407
|
||||
importlib-metadata<7
|
||||
|
||||
# Cause: https://github.com/openedx/event-tracking/pull/290
|
||||
# event-tracking 2.4.1 upgrades to pymongo 4.4.0 which is not supported on edx-platform.
|
||||
# We will pin event-tracking to do not break existing installations
|
||||
|
||||
@@ -12,6 +12,12 @@
|
||||
# This file contains all common constraints for edx-repos
|
||||
-c common_constraints.txt
|
||||
|
||||
# Date: 2024-08-21
|
||||
# Description: This is the major upgrade of algoliasearch python client and it will
|
||||
# break one of the edX' platform plugin, so we need to make that compatible first.
|
||||
# Ticket: https://github.com/openedx/edx-platform/issues/35334
|
||||
algoliasearch<4.0.0
|
||||
|
||||
# As it is not clarified what exact breaking changes will be introduced as per
|
||||
# the next major release, ensure the installed version is within boundaries.
|
||||
celery>=5.2.2,<6.0.0
|
||||
@@ -20,7 +26,7 @@ celery>=5.2.2,<6.0.0
|
||||
# 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.21.9
|
||||
edx-enterprise==4.23.9
|
||||
|
||||
# Stay on LTS version, remove once this is added to common constraint
|
||||
Django<5.0
|
||||
@@ -87,7 +93,7 @@ libsass==0.10.0
|
||||
click==8.1.6
|
||||
|
||||
# pinning this version to avoid updates while the library is being developed
|
||||
openedx-learning==0.10.0
|
||||
openedx-learning==0.10.1
|
||||
|
||||
# Open AI version 1.0.0 dropped support for openai.ChatCompletion which is currently in use in enterprise.
|
||||
openai<=0.28.1
|
||||
@@ -130,3 +136,13 @@ numpy<2.0.0
|
||||
# Two lines were added in 1.14.4 that make file_exists_in_storage function always return False,
|
||||
# as the default value of AWS_S3_FILE_OVERWRITE is True
|
||||
django-storages<1.14.4
|
||||
|
||||
# social-auth-app-django 5.4.2 introduces a new migration that will not play nicely with large installations. This will touch
|
||||
# user tables, which are quite large, especially on instances like edx.org.
|
||||
# We are pinning this until after all the smaller migrations get handled and then we can migrate this all at once.
|
||||
# Ticket to unpin: https://github.com/edx/edx-arch-experiments/issues/760
|
||||
social-auth-app-django<=5.4.1
|
||||
|
||||
# Xblock==5.0.0 changed how entrypoints were loaded, breaking a workaround for overriding blocks.
|
||||
# See ticket: https://github.com/openedx/XBlock/issues/777
|
||||
xblock[django]==4.0.1
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
#
|
||||
# make upgrade
|
||||
#
|
||||
cffi==1.16.0
|
||||
cffi==1.17.0
|
||||
# via cryptography
|
||||
chem==1.3.0
|
||||
# via -r requirements/edx-sandbox/base.in
|
||||
@@ -16,7 +16,7 @@ codejail-includes==1.0.0
|
||||
# via -r requirements/edx-sandbox/base.in
|
||||
contourpy==1.2.1
|
||||
# via matplotlib
|
||||
cryptography==42.0.8
|
||||
cryptography==43.0.0
|
||||
# via -r requirements/edx-sandbox/base.in
|
||||
cycler==0.12.1
|
||||
# via matplotlib
|
||||
@@ -35,13 +35,13 @@ markupsafe==2.1.5
|
||||
# via
|
||||
# chem
|
||||
# openedx-calc
|
||||
matplotlib==3.9.1
|
||||
matplotlib==3.9.2
|
||||
# via -r requirements/edx-sandbox/base.in
|
||||
mpmath==1.3.0
|
||||
# via sympy
|
||||
networkx==3.3
|
||||
# via -r requirements/edx-sandbox/base.in
|
||||
nltk==3.8.1
|
||||
nltk==3.9.1
|
||||
# via
|
||||
# -r requirements/edx-sandbox/base.in
|
||||
# chem
|
||||
@@ -71,7 +71,7 @@ python-dateutil==2.9.0.post0
|
||||
# via matplotlib
|
||||
random2==1.0.2
|
||||
# via -r requirements/edx-sandbox/base.in
|
||||
regex==2024.5.15
|
||||
regex==2024.7.24
|
||||
# via nltk
|
||||
scipy==1.14.0
|
||||
# via
|
||||
@@ -82,9 +82,9 @@ six==1.16.0
|
||||
# via
|
||||
# codejail-includes
|
||||
# python-dateutil
|
||||
sympy==1.13.0
|
||||
sympy==1.13.2
|
||||
# via
|
||||
# -r requirements/edx-sandbox/base.in
|
||||
# openedx-calc
|
||||
tqdm==4.66.4
|
||||
tqdm==4.66.5
|
||||
# via nltk
|
||||
|
||||
@@ -8,14 +8,18 @@
|
||||
# via -r requirements/edx/github.in
|
||||
acid-xblock==0.3.1
|
||||
# via -r requirements/edx/kernel.in
|
||||
aiohttp==3.9.5
|
||||
aiohappyeyeballs==2.4.0
|
||||
# via aiohttp
|
||||
aiohttp==3.10.5
|
||||
# via
|
||||
# geoip2
|
||||
# openai
|
||||
aiosignal==1.3.1
|
||||
# via aiohttp
|
||||
algoliasearch==3.0.0
|
||||
# via -r requirements/edx/bundled.in
|
||||
# via
|
||||
# -c requirements/edx/../constraints.txt
|
||||
# -r requirements/edx/bundled.in
|
||||
amqp==5.2.0
|
||||
# via kombu
|
||||
analytics-python==1.4.post1
|
||||
@@ -33,7 +37,7 @@ asgiref==3.8.1
|
||||
# django-countries
|
||||
asn1crypto==1.5.1
|
||||
# via snowflake-connector-python
|
||||
attrs==23.2.0
|
||||
attrs==24.2.0
|
||||
# via
|
||||
# -r requirements/edx/kernel.in
|
||||
# aiohttp
|
||||
@@ -43,14 +47,14 @@ attrs==23.2.0
|
||||
# openedx-events
|
||||
# openedx-learning
|
||||
# referencing
|
||||
babel==2.15.0
|
||||
babel==2.16.0
|
||||
# via
|
||||
# -r requirements/edx/kernel.in
|
||||
# enmerkar
|
||||
# enmerkar-underscore
|
||||
backoff==1.10.0
|
||||
# via analytics-python
|
||||
bcrypt==4.1.3
|
||||
bcrypt==4.2.0
|
||||
# via paramiko
|
||||
beautifulsoup4==4.12.3
|
||||
# via pynliner
|
||||
@@ -66,19 +70,23 @@ bleach[css]==6.1.0
|
||||
# xblock-poll
|
||||
boto==2.49.0
|
||||
# via -r requirements/edx/kernel.in
|
||||
boto3==1.34.144
|
||||
boto3==1.35.1
|
||||
# via
|
||||
# -r requirements/edx/kernel.in
|
||||
# django-ses
|
||||
# fs-s3fs
|
||||
# ora2
|
||||
botocore==1.34.144
|
||||
botocore==1.35.1
|
||||
# via
|
||||
# -r requirements/edx/kernel.in
|
||||
# boto3
|
||||
# s3transfer
|
||||
bridgekeeper==0.9
|
||||
# via -r requirements/edx/kernel.in
|
||||
cachecontrol==0.14.0
|
||||
# via firebase-admin
|
||||
cachetools==5.5.0
|
||||
# via google-auth
|
||||
camel-converter[pydantic]==3.1.2
|
||||
# via meilisearch
|
||||
celery==5.4.0
|
||||
@@ -98,7 +106,7 @@ certifi==2024.7.4
|
||||
# py2neo
|
||||
# requests
|
||||
# snowflake-connector-python
|
||||
cffi==1.16.0
|
||||
cffi==1.17.0
|
||||
# via
|
||||
# cryptography
|
||||
# pynacl
|
||||
@@ -160,7 +168,7 @@ defusedxml==0.7.1
|
||||
# ora2
|
||||
# python3-openid
|
||||
# social-auth-core
|
||||
django==4.2.14
|
||||
django==4.2.15
|
||||
# via
|
||||
# -c requirements/edx/../common_constraints.txt
|
||||
# -c requirements/edx/../constraints.txt
|
||||
@@ -179,6 +187,7 @@ django==4.2.14
|
||||
# django-multi-email-field
|
||||
# django-mysql
|
||||
# django-oauth-toolkit
|
||||
# django-push-notifications
|
||||
# django-sekizai
|
||||
# django-ses
|
||||
# django-statici18n
|
||||
@@ -262,7 +271,7 @@ django-crum==0.7.9
|
||||
# super-csv
|
||||
django-fernet-fields-v2==0.9
|
||||
# via edx-enterprise
|
||||
django-filter==24.2
|
||||
django-filter==24.3
|
||||
# via
|
||||
# -r requirements/edx/kernel.in
|
||||
# edx-enterprise
|
||||
@@ -311,6 +320,8 @@ django-object-actions==4.2.0
|
||||
# via edx-enterprise
|
||||
django-pipeline==3.1.0
|
||||
# via -r requirements/edx/kernel.in
|
||||
django-push-notifications==3.1.0
|
||||
# via edx-ace
|
||||
django-ratelimit==4.1.0
|
||||
# via -r requirements/edx/kernel.in
|
||||
django-sekizai==4.1.0
|
||||
@@ -390,7 +401,7 @@ drf-yasg==1.21.7
|
||||
# via
|
||||
# django-user-tasks
|
||||
# edx-api-doc-tools
|
||||
edx-ace==1.9.1
|
||||
edx-ace==1.11.1
|
||||
# via -r requirements/edx/kernel.in
|
||||
edx-api-doc-tools==1.8.0
|
||||
# via
|
||||
@@ -418,7 +429,7 @@ edx-celeryutils==1.3.0
|
||||
# super-csv
|
||||
edx-codejail==3.4.1
|
||||
# via -r requirements/edx/kernel.in
|
||||
edx-completion==4.6.6
|
||||
edx-completion==4.6.7
|
||||
# via -r requirements/edx/kernel.in
|
||||
edx-django-release-util==1.4.0
|
||||
# via
|
||||
@@ -427,7 +438,7 @@ edx-django-release-util==1.4.0
|
||||
# edxval
|
||||
edx-django-sites-extensions==4.2.0
|
||||
# via -r requirements/edx/kernel.in
|
||||
edx-django-utils==5.14.2
|
||||
edx-django-utils==5.15.0
|
||||
# via
|
||||
# -r requirements/edx/kernel.in
|
||||
# django-config-models
|
||||
@@ -456,11 +467,11 @@ edx-drf-extensions==10.3.0
|
||||
# edx-when
|
||||
# edxval
|
||||
# openedx-learning
|
||||
edx-enterprise==4.21.9
|
||||
edx-enterprise==4.23.9
|
||||
# via
|
||||
# -c requirements/edx/../constraints.txt
|
||||
# -r requirements/edx/kernel.in
|
||||
edx-event-bus-kafka==5.7.0
|
||||
edx-event-bus-kafka==5.8.1
|
||||
# via -r requirements/edx/kernel.in
|
||||
edx-event-bus-redis==0.5.0
|
||||
# via -r requirements/edx/kernel.in
|
||||
@@ -502,11 +513,11 @@ edx-rest-api-client==5.7.1
|
||||
# -r requirements/edx/kernel.in
|
||||
# edx-enterprise
|
||||
# edx-proctoring
|
||||
edx-search==3.9.1
|
||||
edx-search==4.0.0
|
||||
# via -r requirements/edx/kernel.in
|
||||
edx-sga==0.25.0
|
||||
# via -r requirements/edx/bundled.in
|
||||
edx-submissions==3.7.5
|
||||
edx-submissions==3.7.7
|
||||
# via
|
||||
# -r requirements/edx/kernel.in
|
||||
# ora2
|
||||
@@ -551,6 +562,8 @@ fastavro==1.9.5
|
||||
# via openedx-events
|
||||
filelock==3.15.4
|
||||
# via snowflake-connector-python
|
||||
firebase-admin==6.5.0
|
||||
# via edx-ace
|
||||
frozenlist==1.4.1
|
||||
# via
|
||||
# aiohttp
|
||||
@@ -571,7 +584,50 @@ geoip2==4.8.0
|
||||
# via -r requirements/edx/kernel.in
|
||||
glob2==0.7
|
||||
# via -r requirements/edx/kernel.in
|
||||
gunicorn==22.0.0
|
||||
google-api-core[grpc]==2.19.1
|
||||
# via
|
||||
# firebase-admin
|
||||
# google-api-python-client
|
||||
# google-cloud-core
|
||||
# google-cloud-firestore
|
||||
# google-cloud-storage
|
||||
google-api-python-client==2.141.0
|
||||
# via firebase-admin
|
||||
google-auth==2.34.0
|
||||
# via
|
||||
# google-api-core
|
||||
# google-api-python-client
|
||||
# google-auth-httplib2
|
||||
# google-cloud-core
|
||||
# google-cloud-firestore
|
||||
# google-cloud-storage
|
||||
google-auth-httplib2==0.2.0
|
||||
# via google-api-python-client
|
||||
google-cloud-core==2.4.1
|
||||
# via
|
||||
# google-cloud-firestore
|
||||
# google-cloud-storage
|
||||
google-cloud-firestore==2.17.2
|
||||
# via firebase-admin
|
||||
google-cloud-storage==2.18.2
|
||||
# via firebase-admin
|
||||
google-crc32c==1.5.0
|
||||
# via
|
||||
# google-cloud-storage
|
||||
# google-resumable-media
|
||||
google-resumable-media==2.7.2
|
||||
# via google-cloud-storage
|
||||
googleapis-common-protos==1.63.2
|
||||
# via
|
||||
# google-api-core
|
||||
# grpcio-status
|
||||
grpcio==1.65.5
|
||||
# via
|
||||
# google-api-core
|
||||
# grpcio-status
|
||||
grpcio-status==1.65.5
|
||||
# via google-api-core
|
||||
gunicorn==23.0.0
|
||||
# via -r requirements/edx/kernel.in
|
||||
help-tokens==2.4.0
|
||||
# via -r requirements/edx/kernel.in
|
||||
@@ -579,6 +635,10 @@ html5lib==1.1
|
||||
# via
|
||||
# -r requirements/edx/kernel.in
|
||||
# ora2
|
||||
httplib2==0.22.0
|
||||
# via
|
||||
# google-api-python-client
|
||||
# google-auth-httplib2
|
||||
icalendar==5.0.13
|
||||
# via -r requirements/edx/kernel.in
|
||||
idna==3.7
|
||||
@@ -588,10 +648,8 @@ idna==3.7
|
||||
# requests
|
||||
# snowflake-connector-python
|
||||
# yarl
|
||||
importlib-metadata==6.11.0
|
||||
# via
|
||||
# -c requirements/edx/../common_constraints.txt
|
||||
# -r requirements/edx/kernel.in
|
||||
importlib-metadata==8.3.0
|
||||
# via -r requirements/edx/kernel.in
|
||||
inflection==0.5.1
|
||||
# via
|
||||
# drf-spectacular
|
||||
@@ -610,7 +668,7 @@ jmespath==1.0.1
|
||||
# botocore
|
||||
joblib==1.4.2
|
||||
# via nltk
|
||||
jsondiff==2.1.2
|
||||
jsondiff==2.2.0
|
||||
# via edx-enterprise
|
||||
jsonfield==3.1.0
|
||||
# via
|
||||
@@ -631,7 +689,7 @@ jwcrypto==1.5.6
|
||||
# via
|
||||
# django-oauth-toolkit
|
||||
# pylti1p3
|
||||
kombu==5.3.7
|
||||
kombu==5.4.0
|
||||
# via celery
|
||||
laboratory==1.0.2
|
||||
# via -r requirements/edx/kernel.in
|
||||
@@ -699,23 +757,25 @@ monotonic==1.6
|
||||
# via
|
||||
# analytics-python
|
||||
# py2neo
|
||||
more-itertools==10.3.0
|
||||
more-itertools==10.4.0
|
||||
# via cssutils
|
||||
mpmath==1.3.0
|
||||
# via sympy
|
||||
msgpack==1.0.8
|
||||
# via cachecontrol
|
||||
multidict==6.0.5
|
||||
# via
|
||||
# aiohttp
|
||||
# yarl
|
||||
mysqlclient==2.2.4
|
||||
# via -r requirements/edx/kernel.in
|
||||
newrelic==9.12.0
|
||||
newrelic==9.13.0
|
||||
# via
|
||||
# -r requirements/edx/bundled.in
|
||||
# edx-django-utils
|
||||
nh3==0.2.18
|
||||
# via -r requirements/edx/kernel.in
|
||||
nltk==3.8.1
|
||||
nltk==3.9.1
|
||||
# via chem
|
||||
nodeenv==1.9.1
|
||||
# via -r requirements/edx/kernel.in
|
||||
@@ -763,7 +823,7 @@ openedx-filters==1.9.0
|
||||
# -r requirements/edx/kernel.in
|
||||
# lti-consumer-xblock
|
||||
# ora2
|
||||
openedx-learning==0.10.0
|
||||
openedx-learning==0.10.1
|
||||
# via
|
||||
# -c requirements/edx/../constraints.txt
|
||||
# -r requirements/edx/kernel.in
|
||||
@@ -773,7 +833,7 @@ optimizely-sdk==4.1.1
|
||||
# via
|
||||
# -c requirements/edx/../constraints.txt
|
||||
# -r requirements/edx/bundled.in
|
||||
ora2==6.11.1
|
||||
ora2==6.11.2
|
||||
# via -r requirements/edx/bundled.in
|
||||
packaging==24.1
|
||||
# via
|
||||
@@ -783,7 +843,7 @@ packaging==24.1
|
||||
# snowflake-connector-python
|
||||
pansi==2020.7.3
|
||||
# via py2neo
|
||||
paramiko==3.4.0
|
||||
paramiko==3.4.1
|
||||
# via edx-enterprise
|
||||
path==16.11.0
|
||||
# via
|
||||
@@ -819,6 +879,17 @@ polib==1.2.0
|
||||
# via edx-i18n-tools
|
||||
prompt-toolkit==3.0.47
|
||||
# via click-repl
|
||||
proto-plus==1.24.0
|
||||
# via
|
||||
# google-api-core
|
||||
# google-cloud-firestore
|
||||
protobuf==5.27.3
|
||||
# via
|
||||
# google-api-core
|
||||
# google-cloud-firestore
|
||||
# googleapis-common-protos
|
||||
# grpcio-status
|
||||
# proto-plus
|
||||
psutil==6.0.0
|
||||
# via
|
||||
# -r requirements/edx/paver.txt
|
||||
@@ -828,7 +899,12 @@ py2neo @ https://github.com/overhangio/py2neo/releases/download/2021.2.3/py2neo-
|
||||
# -c requirements/edx/../constraints.txt
|
||||
# -r requirements/edx/bundled.in
|
||||
pyasn1==0.6.0
|
||||
# via pgpy
|
||||
# via
|
||||
# pgpy
|
||||
# pyasn1-modules
|
||||
# rsa
|
||||
pyasn1-modules==0.4.0
|
||||
# via google-auth
|
||||
pycountry==24.6.1
|
||||
# via -r requirements/edx/kernel.in
|
||||
pycparser==2.22
|
||||
@@ -852,7 +928,7 @@ pyjwkest==1.4.2
|
||||
# -r requirements/edx/kernel.in
|
||||
# edx-token-utils
|
||||
# lti-consumer-xblock
|
||||
pyjwt[crypto]==2.8.0
|
||||
pyjwt[crypto]==2.9.0
|
||||
# via
|
||||
# -r requirements/edx/kernel.in
|
||||
# drf-jwt
|
||||
@@ -860,6 +936,7 @@ pyjwt[crypto]==2.8.0
|
||||
# edx-drf-extensions
|
||||
# edx-proctoring
|
||||
# edx-rest-api-client
|
||||
# firebase-admin
|
||||
# pylti1p3
|
||||
# snowflake-connector-python
|
||||
# social-auth-core
|
||||
@@ -884,13 +961,14 @@ pynacl==1.5.0
|
||||
# paramiko
|
||||
pynliner==0.8.0
|
||||
# via -r requirements/edx/kernel.in
|
||||
pyopenssl==24.1.0
|
||||
pyopenssl==24.2.1
|
||||
# via
|
||||
# optimizely-sdk
|
||||
# snowflake-connector-python
|
||||
pyparsing==3.1.2
|
||||
# via
|
||||
# chem
|
||||
# httplib2
|
||||
# openedx-calc
|
||||
pyrsistent==0.20.0
|
||||
# via optimizely-sdk
|
||||
@@ -946,7 +1024,7 @@ pytz==2024.1
|
||||
# xblock
|
||||
pyuca==1.2
|
||||
# via -r requirements/edx/kernel.in
|
||||
pyyaml==6.0.1
|
||||
pyyaml==6.0.2
|
||||
# via
|
||||
# -r requirements/edx/kernel.in
|
||||
# code-annotations
|
||||
@@ -960,7 +1038,7 @@ random2==1.0.2
|
||||
# via -r requirements/edx/kernel.in
|
||||
recommender-xblock==2.2.0
|
||||
# via -r requirements/edx/bundled.in
|
||||
redis==5.0.7
|
||||
redis==5.0.8
|
||||
# via
|
||||
# -r requirements/edx/kernel.in
|
||||
# walrus
|
||||
@@ -968,19 +1046,22 @@ referencing==0.35.1
|
||||
# via
|
||||
# jsonschema
|
||||
# jsonschema-specifications
|
||||
regex==2024.5.15
|
||||
regex==2024.7.24
|
||||
# via nltk
|
||||
requests==2.32.3
|
||||
# via
|
||||
# -r requirements/edx/paver.txt
|
||||
# algoliasearch
|
||||
# analytics-python
|
||||
# cachecontrol
|
||||
# django-oauth-toolkit
|
||||
# edx-bulk-grades
|
||||
# edx-drf-extensions
|
||||
# edx-enterprise
|
||||
# edx-rest-api-client
|
||||
# geoip2
|
||||
# google-api-core
|
||||
# google-cloud-storage
|
||||
# mailsnake
|
||||
# meilisearch
|
||||
# openai
|
||||
@@ -998,10 +1079,12 @@ requests-oauthlib==2.0.0
|
||||
# via
|
||||
# -r requirements/edx/kernel.in
|
||||
# social-auth-core
|
||||
rpds-py==0.19.0
|
||||
rpds-py==0.20.0
|
||||
# via
|
||||
# jsonschema
|
||||
# referencing
|
||||
rsa==4.9
|
||||
# via google-auth
|
||||
rules==3.4
|
||||
# via
|
||||
# -r requirements/edx/kernel.in
|
||||
@@ -1018,9 +1101,9 @@ scipy==1.14.0
|
||||
# openedx-calc
|
||||
semantic-version==2.10.0
|
||||
# via edx-drf-extensions
|
||||
shapely==2.0.5
|
||||
shapely==2.0.6
|
||||
# via -r requirements/edx/kernel.in
|
||||
simplejson==3.19.2
|
||||
simplejson==3.19.3
|
||||
# via
|
||||
# -r requirements/edx/kernel.in
|
||||
# sailthru-client
|
||||
@@ -1061,10 +1144,11 @@ slumber==0.7.1
|
||||
# edx-bulk-grades
|
||||
# edx-enterprise
|
||||
# edx-rest-api-client
|
||||
snowflake-connector-python==3.11.0
|
||||
snowflake-connector-python==3.12.0
|
||||
# via edx-enterprise
|
||||
social-auth-app-django==5.4.1
|
||||
# via
|
||||
# -c requirements/edx/../constraints.txt
|
||||
# -r requirements/edx/kernel.in
|
||||
# edx-auth-backends
|
||||
social-auth-core==4.5.4
|
||||
@@ -1080,7 +1164,7 @@ sortedcontainers==2.4.0
|
||||
# via
|
||||
# -r requirements/edx/kernel.in
|
||||
# snowflake-connector-python
|
||||
soupsieve==2.5
|
||||
soupsieve==2.6
|
||||
# via beautifulsoup4
|
||||
sqlparse==0.5.1
|
||||
# via django
|
||||
@@ -1097,7 +1181,7 @@ stevedore==5.2.0
|
||||
# edx-opaque-keys
|
||||
super-csv==3.2.0
|
||||
# via edx-bulk-grades
|
||||
sympy==1.13.0
|
||||
sympy==1.13.2
|
||||
# via openedx-calc
|
||||
testfixtures==8.3.0
|
||||
# via edx-enterprise
|
||||
@@ -1105,9 +1189,9 @@ text-unidecode==1.3
|
||||
# via python-slugify
|
||||
tinycss2==1.2.1
|
||||
# via bleach
|
||||
tomlkit==0.13.0
|
||||
tomlkit==0.13.2
|
||||
# via snowflake-connector-python
|
||||
tqdm==4.66.4
|
||||
tqdm==4.66.5
|
||||
# via
|
||||
# nltk
|
||||
# openai
|
||||
@@ -1131,6 +1215,7 @@ uritemplate==4.1.1
|
||||
# via
|
||||
# drf-spectacular
|
||||
# drf-yasg
|
||||
# google-api-python-client
|
||||
urllib3==1.26.19
|
||||
# via
|
||||
# -c requirements/edx/../constraints.txt
|
||||
@@ -1150,7 +1235,7 @@ voluptuous==0.15.2
|
||||
# via ora2
|
||||
walrus==0.9.4
|
||||
# via edx-event-bus-redis
|
||||
watchdog==4.0.1
|
||||
watchdog==4.0.2
|
||||
# via -r requirements/edx/paver.txt
|
||||
wcwidth==0.2.13
|
||||
# via prompt-toolkit
|
||||
@@ -1167,7 +1252,7 @@ webencodings==0.5.1
|
||||
# bleach
|
||||
# html5lib
|
||||
# tinycss2
|
||||
webob==1.8.7
|
||||
webob==1.8.8
|
||||
# via
|
||||
# -r requirements/edx/kernel.in
|
||||
# xblock
|
||||
@@ -1175,6 +1260,7 @@ wrapt==1.16.0
|
||||
# via -r requirements/edx/paver.txt
|
||||
xblock[django]==4.0.1
|
||||
# via
|
||||
# -c requirements/edx/../constraints.txt
|
||||
# -r requirements/edx/kernel.in
|
||||
# acid-xblock
|
||||
# crowdsourcehinter-xblock
|
||||
@@ -1206,7 +1292,7 @@ xss-utils==0.6.0
|
||||
# via -r requirements/edx/kernel.in
|
||||
yarl==1.9.4
|
||||
# via aiohttp
|
||||
zipp==3.19.2
|
||||
zipp==3.20.0
|
||||
# via importlib-metadata
|
||||
|
||||
# The following packages are considered to be unsafe in a requirements file:
|
||||
|
||||
@@ -6,9 +6,9 @@
|
||||
#
|
||||
chardet==5.2.0
|
||||
# via diff-cover
|
||||
coverage==7.6.0
|
||||
coverage==7.6.1
|
||||
# via -r requirements/edx/coverage.in
|
||||
diff-cover==9.1.0
|
||||
diff-cover==9.1.1
|
||||
# via -r requirements/edx/coverage.in
|
||||
jinja2==3.1.4
|
||||
# via diff-cover
|
||||
|
||||
@@ -16,7 +16,12 @@ acid-xblock==0.3.1
|
||||
# via
|
||||
# -r requirements/edx/doc.txt
|
||||
# -r requirements/edx/testing.txt
|
||||
aiohttp==3.9.5
|
||||
aiohappyeyeballs==2.4.0
|
||||
# via
|
||||
# -r requirements/edx/doc.txt
|
||||
# -r requirements/edx/testing.txt
|
||||
# aiohttp
|
||||
aiohttp==3.10.5
|
||||
# via
|
||||
# -r requirements/edx/doc.txt
|
||||
# -r requirements/edx/testing.txt
|
||||
@@ -27,12 +32,13 @@ aiosignal==1.3.1
|
||||
# -r requirements/edx/doc.txt
|
||||
# -r requirements/edx/testing.txt
|
||||
# aiohttp
|
||||
alabaster==0.7.16
|
||||
alabaster==1.0.0
|
||||
# via
|
||||
# -r requirements/edx/doc.txt
|
||||
# sphinx
|
||||
algoliasearch==3.0.0
|
||||
# via
|
||||
# -c requirements/edx/../constraints.txt
|
||||
# -r requirements/edx/doc.txt
|
||||
# -r requirements/edx/testing.txt
|
||||
amqp==5.2.0
|
||||
@@ -57,9 +63,7 @@ annotated-types==0.7.0
|
||||
anyio==4.4.0
|
||||
# via
|
||||
# -r requirements/edx/testing.txt
|
||||
# httpcore
|
||||
# starlette
|
||||
# watchfiles
|
||||
appdirs==1.4.4
|
||||
# via
|
||||
# -r requirements/edx/doc.txt
|
||||
@@ -82,7 +86,7 @@ astroid==2.13.5
|
||||
# -r requirements/edx/testing.txt
|
||||
# pylint
|
||||
# pylint-celery
|
||||
attrs==23.2.0
|
||||
attrs==24.2.0
|
||||
# via
|
||||
# -r requirements/edx/doc.txt
|
||||
# -r requirements/edx/testing.txt
|
||||
@@ -93,7 +97,7 @@ attrs==23.2.0
|
||||
# openedx-events
|
||||
# openedx-learning
|
||||
# referencing
|
||||
babel==2.15.0
|
||||
babel==2.16.0
|
||||
# via
|
||||
# -r requirements/edx/doc.txt
|
||||
# -r requirements/edx/testing.txt
|
||||
@@ -106,7 +110,7 @@ backoff==1.10.0
|
||||
# -r requirements/edx/doc.txt
|
||||
# -r requirements/edx/testing.txt
|
||||
# analytics-python
|
||||
bcrypt==4.1.3
|
||||
bcrypt==4.2.0
|
||||
# via
|
||||
# -r requirements/edx/doc.txt
|
||||
# -r requirements/edx/testing.txt
|
||||
@@ -136,14 +140,14 @@ boto==2.49.0
|
||||
# via
|
||||
# -r requirements/edx/doc.txt
|
||||
# -r requirements/edx/testing.txt
|
||||
boto3==1.34.144
|
||||
boto3==1.35.1
|
||||
# via
|
||||
# -r requirements/edx/doc.txt
|
||||
# -r requirements/edx/testing.txt
|
||||
# django-ses
|
||||
# fs-s3fs
|
||||
# ora2
|
||||
botocore==1.34.144
|
||||
botocore==1.35.1
|
||||
# via
|
||||
# -r requirements/edx/doc.txt
|
||||
# -r requirements/edx/testing.txt
|
||||
@@ -157,9 +161,16 @@ build==1.2.1
|
||||
# via
|
||||
# -r requirements/edx/../pip-tools.txt
|
||||
# pip-tools
|
||||
cachetools==5.4.0
|
||||
cachecontrol==0.14.0
|
||||
# via
|
||||
# -r requirements/edx/doc.txt
|
||||
# -r requirements/edx/testing.txt
|
||||
# firebase-admin
|
||||
cachetools==5.5.0
|
||||
# via
|
||||
# -r requirements/edx/doc.txt
|
||||
# -r requirements/edx/testing.txt
|
||||
# google-auth
|
||||
# tox
|
||||
camel-converter[pydantic]==3.1.2
|
||||
# via
|
||||
@@ -182,16 +193,15 @@ certifi==2024.7.4
|
||||
# -r requirements/edx/doc.txt
|
||||
# -r requirements/edx/testing.txt
|
||||
# elasticsearch
|
||||
# httpcore
|
||||
# httpx
|
||||
# py2neo
|
||||
# requests
|
||||
# snowflake-connector-python
|
||||
cffi==1.16.0
|
||||
cffi==1.17.0
|
||||
# via
|
||||
# -r requirements/edx/doc.txt
|
||||
# -r requirements/edx/testing.txt
|
||||
# cryptography
|
||||
# pact-python
|
||||
# pynacl
|
||||
# snowflake-connector-python
|
||||
chardet==5.2.0
|
||||
@@ -232,7 +242,6 @@ click==8.1.6
|
||||
# nltk
|
||||
# pact-python
|
||||
# pip-tools
|
||||
# typer
|
||||
# user-util
|
||||
# uvicorn
|
||||
click-didyoumean==0.3.1
|
||||
@@ -269,7 +278,7 @@ colorama==0.4.6
|
||||
# via
|
||||
# -r requirements/edx/testing.txt
|
||||
# tox
|
||||
coverage[toml]==7.6.0
|
||||
coverage[toml]==7.6.1
|
||||
# via
|
||||
# -r requirements/edx/testing.txt
|
||||
# pytest-cov
|
||||
@@ -314,7 +323,7 @@ defusedxml==0.7.1
|
||||
# ora2
|
||||
# python3-openid
|
||||
# social-auth-core
|
||||
diff-cover==9.1.0
|
||||
diff-cover==9.1.1
|
||||
# via -r requirements/edx/testing.txt
|
||||
dill==0.3.8
|
||||
# via
|
||||
@@ -324,7 +333,7 @@ distlib==0.3.8
|
||||
# via
|
||||
# -r requirements/edx/testing.txt
|
||||
# virtualenv
|
||||
django==4.2.14
|
||||
django==4.2.15
|
||||
# via
|
||||
# -c requirements/edx/../common_constraints.txt
|
||||
# -c requirements/edx/../constraints.txt
|
||||
@@ -345,6 +354,7 @@ django==4.2.14
|
||||
# django-multi-email-field
|
||||
# django-mysql
|
||||
# django-oauth-toolkit
|
||||
# django-push-notifications
|
||||
# django-sekizai
|
||||
# django-ses
|
||||
# django-statici18n
|
||||
@@ -451,7 +461,7 @@ django-fernet-fields-v2==0.9
|
||||
# -r requirements/edx/doc.txt
|
||||
# -r requirements/edx/testing.txt
|
||||
# edx-enterprise
|
||||
django-filter==24.2
|
||||
django-filter==24.3
|
||||
# via
|
||||
# -r requirements/edx/doc.txt
|
||||
# -r requirements/edx/testing.txt
|
||||
@@ -520,6 +530,11 @@ django-pipeline==3.1.0
|
||||
# via
|
||||
# -r requirements/edx/doc.txt
|
||||
# -r requirements/edx/testing.txt
|
||||
django-push-notifications==3.1.0
|
||||
# via
|
||||
# -r requirements/edx/doc.txt
|
||||
# -r requirements/edx/testing.txt
|
||||
# edx-ace
|
||||
django-ratelimit==4.1.0
|
||||
# via
|
||||
# -r requirements/edx/doc.txt
|
||||
@@ -561,7 +576,7 @@ django-stubs==1.16.0
|
||||
# -c requirements/edx/../constraints.txt
|
||||
# -r requirements/edx/development.in
|
||||
# djangorestframework-stubs
|
||||
django-stubs-ext==5.0.2
|
||||
django-stubs-ext==5.0.4
|
||||
# via django-stubs
|
||||
django-user-tasks==3.2.0
|
||||
# via
|
||||
@@ -616,7 +631,6 @@ dnspython==2.6.1
|
||||
# via
|
||||
# -r requirements/edx/doc.txt
|
||||
# -r requirements/edx/testing.txt
|
||||
# email-validator
|
||||
# pymongo
|
||||
docutils==0.21.2
|
||||
# via
|
||||
@@ -643,7 +657,7 @@ drf-yasg==1.21.7
|
||||
# -r requirements/edx/testing.txt
|
||||
# django-user-tasks
|
||||
# edx-api-doc-tools
|
||||
edx-ace==1.9.1
|
||||
edx-ace==1.11.1
|
||||
# via
|
||||
# -r requirements/edx/doc.txt
|
||||
# -r requirements/edx/testing.txt
|
||||
@@ -682,7 +696,7 @@ edx-codejail==3.4.1
|
||||
# via
|
||||
# -r requirements/edx/doc.txt
|
||||
# -r requirements/edx/testing.txt
|
||||
edx-completion==4.6.6
|
||||
edx-completion==4.6.7
|
||||
# via
|
||||
# -r requirements/edx/doc.txt
|
||||
# -r requirements/edx/testing.txt
|
||||
@@ -696,7 +710,7 @@ edx-django-sites-extensions==4.2.0
|
||||
# via
|
||||
# -r requirements/edx/doc.txt
|
||||
# -r requirements/edx/testing.txt
|
||||
edx-django-utils==5.14.2
|
||||
edx-django-utils==5.15.0
|
||||
# via
|
||||
# -r requirements/edx/doc.txt
|
||||
# -r requirements/edx/testing.txt
|
||||
@@ -727,12 +741,12 @@ edx-drf-extensions==10.3.0
|
||||
# edx-when
|
||||
# edxval
|
||||
# openedx-learning
|
||||
edx-enterprise==4.21.9
|
||||
edx-enterprise==4.23.9
|
||||
# via
|
||||
# -c requirements/edx/../constraints.txt
|
||||
# -r requirements/edx/doc.txt
|
||||
# -r requirements/edx/testing.txt
|
||||
edx-event-bus-kafka==5.7.0
|
||||
edx-event-bus-kafka==5.8.1
|
||||
# via
|
||||
# -r requirements/edx/doc.txt
|
||||
# -r requirements/edx/testing.txt
|
||||
@@ -792,7 +806,7 @@ edx-rest-api-client==5.7.1
|
||||
# -r requirements/edx/testing.txt
|
||||
# edx-enterprise
|
||||
# edx-proctoring
|
||||
edx-search==3.9.1
|
||||
edx-search==4.0.0
|
||||
# via
|
||||
# -r requirements/edx/doc.txt
|
||||
# -r requirements/edx/testing.txt
|
||||
@@ -800,7 +814,7 @@ edx-sga==0.25.0
|
||||
# via
|
||||
# -r requirements/edx/doc.txt
|
||||
# -r requirements/edx/testing.txt
|
||||
edx-submissions==3.7.5
|
||||
edx-submissions==3.7.7
|
||||
# via
|
||||
# -r requirements/edx/doc.txt
|
||||
# -r requirements/edx/testing.txt
|
||||
@@ -842,10 +856,6 @@ elasticsearch==7.13.4
|
||||
# -r requirements/edx/doc.txt
|
||||
# -r requirements/edx/testing.txt
|
||||
# edx-search
|
||||
email-validator==2.2.0
|
||||
# via
|
||||
# -r requirements/edx/testing.txt
|
||||
# fastapi
|
||||
enmerkar==0.7.1
|
||||
# via
|
||||
# -r requirements/edx/doc.txt
|
||||
@@ -867,20 +877,16 @@ execnet==2.1.1
|
||||
# via
|
||||
# -r requirements/edx/testing.txt
|
||||
# pytest-xdist
|
||||
factory-boy==3.3.0
|
||||
factory-boy==3.3.1
|
||||
# via -r requirements/edx/testing.txt
|
||||
faker==26.0.0
|
||||
faker==27.0.0
|
||||
# via
|
||||
# -r requirements/edx/testing.txt
|
||||
# factory-boy
|
||||
fastapi==0.111.1
|
||||
fastapi==0.112.1
|
||||
# via
|
||||
# -r requirements/edx/testing.txt
|
||||
# pact-python
|
||||
fastapi-cli==0.0.4
|
||||
# via
|
||||
# -r requirements/edx/testing.txt
|
||||
# fastapi
|
||||
fastavro==1.9.5
|
||||
# via
|
||||
# -r requirements/edx/doc.txt
|
||||
@@ -893,6 +899,11 @@ filelock==3.15.4
|
||||
# snowflake-connector-python
|
||||
# tox
|
||||
# virtualenv
|
||||
firebase-admin==6.5.0
|
||||
# via
|
||||
# -r requirements/edx/doc.txt
|
||||
# -r requirements/edx/testing.txt
|
||||
# edx-ace
|
||||
freezegun==1.5.1
|
||||
# via -r requirements/edx/testing.txt
|
||||
frozenlist==1.4.1
|
||||
@@ -932,18 +943,90 @@ glob2==0.7
|
||||
# via
|
||||
# -r requirements/edx/doc.txt
|
||||
# -r requirements/edx/testing.txt
|
||||
google-api-core[grpc]==2.19.1
|
||||
# via
|
||||
# -r requirements/edx/doc.txt
|
||||
# -r requirements/edx/testing.txt
|
||||
# firebase-admin
|
||||
# google-api-python-client
|
||||
# google-cloud-core
|
||||
# google-cloud-firestore
|
||||
# google-cloud-storage
|
||||
google-api-python-client==2.141.0
|
||||
# via
|
||||
# -r requirements/edx/doc.txt
|
||||
# -r requirements/edx/testing.txt
|
||||
# firebase-admin
|
||||
google-auth==2.34.0
|
||||
# via
|
||||
# -r requirements/edx/doc.txt
|
||||
# -r requirements/edx/testing.txt
|
||||
# google-api-core
|
||||
# google-api-python-client
|
||||
# google-auth-httplib2
|
||||
# google-cloud-core
|
||||
# google-cloud-firestore
|
||||
# google-cloud-storage
|
||||
google-auth-httplib2==0.2.0
|
||||
# via
|
||||
# -r requirements/edx/doc.txt
|
||||
# -r requirements/edx/testing.txt
|
||||
# google-api-python-client
|
||||
google-cloud-core==2.4.1
|
||||
# via
|
||||
# -r requirements/edx/doc.txt
|
||||
# -r requirements/edx/testing.txt
|
||||
# google-cloud-firestore
|
||||
# google-cloud-storage
|
||||
google-cloud-firestore==2.17.2
|
||||
# via
|
||||
# -r requirements/edx/doc.txt
|
||||
# -r requirements/edx/testing.txt
|
||||
# firebase-admin
|
||||
google-cloud-storage==2.18.2
|
||||
# via
|
||||
# -r requirements/edx/doc.txt
|
||||
# -r requirements/edx/testing.txt
|
||||
# firebase-admin
|
||||
google-crc32c==1.5.0
|
||||
# via
|
||||
# -r requirements/edx/doc.txt
|
||||
# -r requirements/edx/testing.txt
|
||||
# google-cloud-storage
|
||||
# google-resumable-media
|
||||
google-resumable-media==2.7.2
|
||||
# via
|
||||
# -r requirements/edx/doc.txt
|
||||
# -r requirements/edx/testing.txt
|
||||
# google-cloud-storage
|
||||
googleapis-common-protos==1.63.2
|
||||
# via
|
||||
# -r requirements/edx/doc.txt
|
||||
# -r requirements/edx/testing.txt
|
||||
# google-api-core
|
||||
# grpcio-status
|
||||
grimp==3.4.1
|
||||
# via
|
||||
# -r requirements/edx/testing.txt
|
||||
# import-linter
|
||||
gunicorn==22.0.0
|
||||
grpcio==1.65.5
|
||||
# via
|
||||
# -r requirements/edx/doc.txt
|
||||
# -r requirements/edx/testing.txt
|
||||
# google-api-core
|
||||
# grpcio-status
|
||||
grpcio-status==1.65.5
|
||||
# via
|
||||
# -r requirements/edx/doc.txt
|
||||
# -r requirements/edx/testing.txt
|
||||
# google-api-core
|
||||
gunicorn==23.0.0
|
||||
# via
|
||||
# -r requirements/edx/doc.txt
|
||||
# -r requirements/edx/testing.txt
|
||||
h11==0.14.0
|
||||
# via
|
||||
# -r requirements/edx/testing.txt
|
||||
# httpcore
|
||||
# uvicorn
|
||||
help-tokens==2.4.0
|
||||
# via
|
||||
@@ -954,21 +1037,14 @@ html5lib==1.1
|
||||
# -r requirements/edx/doc.txt
|
||||
# -r requirements/edx/testing.txt
|
||||
# ora2
|
||||
httpcore==0.16.3
|
||||
httplib2==0.22.0
|
||||
# via
|
||||
# -r requirements/edx/doc.txt
|
||||
# -r requirements/edx/testing.txt
|
||||
# httpx
|
||||
# google-api-python-client
|
||||
# google-auth-httplib2
|
||||
httpretty==1.1.4
|
||||
# via -r requirements/edx/testing.txt
|
||||
httptools==0.6.1
|
||||
# via
|
||||
# -r requirements/edx/testing.txt
|
||||
# uvicorn
|
||||
httpx==0.23.3
|
||||
# via
|
||||
# -r requirements/edx/testing.txt
|
||||
# fastapi
|
||||
# pact-python
|
||||
icalendar==5.0.13
|
||||
# via
|
||||
# -r requirements/edx/doc.txt
|
||||
@@ -978,10 +1054,8 @@ idna==3.7
|
||||
# -r requirements/edx/doc.txt
|
||||
# -r requirements/edx/testing.txt
|
||||
# anyio
|
||||
# email-validator
|
||||
# optimizely-sdk
|
||||
# requests
|
||||
# rfc3986
|
||||
# snowflake-connector-python
|
||||
# yarl
|
||||
imagesize==1.4.1
|
||||
@@ -990,9 +1064,8 @@ imagesize==1.4.1
|
||||
# sphinx
|
||||
import-linter==2.0
|
||||
# via -r requirements/edx/testing.txt
|
||||
importlib-metadata==6.11.0
|
||||
importlib-metadata==8.3.0
|
||||
# via
|
||||
# -c requirements/edx/../common_constraints.txt
|
||||
# -r requirements/edx/doc.txt
|
||||
# -r requirements/edx/testing.txt
|
||||
inflection==0.5.1
|
||||
@@ -1029,7 +1102,6 @@ jinja2==3.1.4
|
||||
# -r requirements/edx/testing.txt
|
||||
# code-annotations
|
||||
# diff-cover
|
||||
# fastapi
|
||||
# sphinx
|
||||
jmespath==1.0.1
|
||||
# via
|
||||
@@ -1042,7 +1114,7 @@ joblib==1.4.2
|
||||
# -r requirements/edx/doc.txt
|
||||
# -r requirements/edx/testing.txt
|
||||
# nltk
|
||||
jsondiff==2.1.2
|
||||
jsondiff==2.2.0
|
||||
# via
|
||||
# -r requirements/edx/doc.txt
|
||||
# -r requirements/edx/testing.txt
|
||||
@@ -1075,7 +1147,7 @@ jwcrypto==1.5.6
|
||||
# -r requirements/edx/testing.txt
|
||||
# django-oauth-toolkit
|
||||
# pylti1p3
|
||||
kombu==5.3.7
|
||||
kombu==5.4.0
|
||||
# via
|
||||
# -r requirements/edx/doc.txt
|
||||
# -r requirements/edx/testing.txt
|
||||
@@ -1146,10 +1218,6 @@ markdown==3.3.7
|
||||
# openedx-django-wiki
|
||||
# staff-graded-xblock
|
||||
# xblock-poll
|
||||
markdown-it-py==3.0.0
|
||||
# via
|
||||
# -r requirements/edx/testing.txt
|
||||
# rich
|
||||
markupsafe==2.1.5
|
||||
# via
|
||||
# -r requirements/edx/doc.txt
|
||||
@@ -1168,10 +1236,6 @@ mccabe==0.7.0
|
||||
# via
|
||||
# -r requirements/edx/testing.txt
|
||||
# pylint
|
||||
mdurl==0.1.2
|
||||
# via
|
||||
# -r requirements/edx/testing.txt
|
||||
# markdown-it-py
|
||||
meilisearch==0.31.4
|
||||
# via
|
||||
# -r requirements/edx/doc.txt
|
||||
@@ -1194,7 +1258,7 @@ monotonic==1.6
|
||||
# -r requirements/edx/testing.txt
|
||||
# analytics-python
|
||||
# py2neo
|
||||
more-itertools==10.3.0
|
||||
more-itertools==10.4.0
|
||||
# via
|
||||
# -r requirements/edx/doc.txt
|
||||
# -r requirements/edx/testing.txt
|
||||
@@ -1204,13 +1268,18 @@ mpmath==1.3.0
|
||||
# -r requirements/edx/doc.txt
|
||||
# -r requirements/edx/testing.txt
|
||||
# sympy
|
||||
msgpack==1.0.8
|
||||
# via
|
||||
# -r requirements/edx/doc.txt
|
||||
# -r requirements/edx/testing.txt
|
||||
# cachecontrol
|
||||
multidict==6.0.5
|
||||
# via
|
||||
# -r requirements/edx/doc.txt
|
||||
# -r requirements/edx/testing.txt
|
||||
# aiohttp
|
||||
# yarl
|
||||
mypy==1.10.1
|
||||
mypy==1.11.1
|
||||
# via
|
||||
# -r requirements/edx/development.in
|
||||
# django-stubs
|
||||
@@ -1221,7 +1290,7 @@ mysqlclient==2.2.4
|
||||
# via
|
||||
# -r requirements/edx/doc.txt
|
||||
# -r requirements/edx/testing.txt
|
||||
newrelic==9.12.0
|
||||
newrelic==9.13.0
|
||||
# via
|
||||
# -r requirements/edx/doc.txt
|
||||
# -r requirements/edx/testing.txt
|
||||
@@ -1230,7 +1299,7 @@ nh3==0.2.18
|
||||
# via
|
||||
# -r requirements/edx/doc.txt
|
||||
# -r requirements/edx/testing.txt
|
||||
nltk==3.8.1
|
||||
nltk==3.9.1
|
||||
# via
|
||||
# -r requirements/edx/doc.txt
|
||||
# -r requirements/edx/testing.txt
|
||||
@@ -1303,7 +1372,7 @@ openedx-filters==1.9.0
|
||||
# -r requirements/edx/testing.txt
|
||||
# lti-consumer-xblock
|
||||
# ora2
|
||||
openedx-learning==0.10.0
|
||||
openedx-learning==0.10.1
|
||||
# via
|
||||
# -c requirements/edx/../constraints.txt
|
||||
# -r requirements/edx/doc.txt
|
||||
@@ -1317,7 +1386,7 @@ optimizely-sdk==4.1.1
|
||||
# -c requirements/edx/../constraints.txt
|
||||
# -r requirements/edx/doc.txt
|
||||
# -r requirements/edx/testing.txt
|
||||
ora2==6.11.1
|
||||
ora2==6.11.2
|
||||
# via
|
||||
# -r requirements/edx/doc.txt
|
||||
# -r requirements/edx/testing.txt
|
||||
@@ -1336,14 +1405,14 @@ packaging==24.1
|
||||
# snowflake-connector-python
|
||||
# sphinx
|
||||
# tox
|
||||
pact-python==2.0.1
|
||||
pact-python==2.2.1
|
||||
# via -r requirements/edx/testing.txt
|
||||
pansi==2020.7.3
|
||||
# via
|
||||
# -r requirements/edx/doc.txt
|
||||
# -r requirements/edx/testing.txt
|
||||
# py2neo
|
||||
paramiko==3.4.0
|
||||
paramiko==3.4.1
|
||||
# via
|
||||
# -r requirements/edx/doc.txt
|
||||
# -r requirements/edx/testing.txt
|
||||
@@ -1417,6 +1486,21 @@ prompt-toolkit==3.0.47
|
||||
# -r requirements/edx/doc.txt
|
||||
# -r requirements/edx/testing.txt
|
||||
# click-repl
|
||||
proto-plus==1.24.0
|
||||
# via
|
||||
# -r requirements/edx/doc.txt
|
||||
# -r requirements/edx/testing.txt
|
||||
# google-api-core
|
||||
# google-cloud-firestore
|
||||
protobuf==5.27.3
|
||||
# via
|
||||
# -r requirements/edx/doc.txt
|
||||
# -r requirements/edx/testing.txt
|
||||
# google-api-core
|
||||
# google-cloud-firestore
|
||||
# googleapis-common-protos
|
||||
# grpcio-status
|
||||
# proto-plus
|
||||
psutil==6.0.0
|
||||
# via
|
||||
# -r requirements/edx/doc.txt
|
||||
@@ -1436,6 +1520,13 @@ pyasn1==0.6.0
|
||||
# -r requirements/edx/doc.txt
|
||||
# -r requirements/edx/testing.txt
|
||||
# pgpy
|
||||
# pyasn1-modules
|
||||
# rsa
|
||||
pyasn1-modules==0.4.0
|
||||
# via
|
||||
# -r requirements/edx/doc.txt
|
||||
# -r requirements/edx/testing.txt
|
||||
# google-auth
|
||||
pycodestyle==2.8.0
|
||||
# via
|
||||
# -c requirements/edx/../constraints.txt
|
||||
@@ -1479,7 +1570,6 @@ pygments==2.18.0
|
||||
# diff-cover
|
||||
# py2neo
|
||||
# pydata-sphinx-theme
|
||||
# rich
|
||||
# sphinx
|
||||
# sphinx-mdinclude
|
||||
pyjwkest==1.4.2
|
||||
@@ -1488,7 +1578,7 @@ pyjwkest==1.4.2
|
||||
# -r requirements/edx/testing.txt
|
||||
# edx-token-utils
|
||||
# lti-consumer-xblock
|
||||
pyjwt[crypto]==2.8.0
|
||||
pyjwt[crypto]==2.9.0
|
||||
# via
|
||||
# -r requirements/edx/doc.txt
|
||||
# -r requirements/edx/testing.txt
|
||||
@@ -1497,6 +1587,7 @@ pyjwt[crypto]==2.8.0
|
||||
# edx-drf-extensions
|
||||
# edx-proctoring
|
||||
# edx-rest-api-client
|
||||
# firebase-admin
|
||||
# pylti1p3
|
||||
# snowflake-connector-python
|
||||
# social-auth-core
|
||||
@@ -1556,7 +1647,7 @@ pynliner==0.8.0
|
||||
# via
|
||||
# -r requirements/edx/doc.txt
|
||||
# -r requirements/edx/testing.txt
|
||||
pyopenssl==24.1.0
|
||||
pyopenssl==24.2.1
|
||||
# via
|
||||
# -r requirements/edx/doc.txt
|
||||
# -r requirements/edx/testing.txt
|
||||
@@ -1567,6 +1658,7 @@ pyparsing==3.1.2
|
||||
# -r requirements/edx/doc.txt
|
||||
# -r requirements/edx/testing.txt
|
||||
# chem
|
||||
# httplib2
|
||||
# openedx-calc
|
||||
pyproject-api==1.7.1
|
||||
# via
|
||||
@@ -1589,7 +1681,7 @@ pysrt==1.1.2
|
||||
# -r requirements/edx/doc.txt
|
||||
# -r requirements/edx/testing.txt
|
||||
# edxval
|
||||
pytest==8.2.2
|
||||
pytest==8.3.2
|
||||
# via
|
||||
# -r requirements/edx/testing.txt
|
||||
# pylint-pytest
|
||||
@@ -1632,10 +1724,6 @@ python-dateutil==2.9.0.post0
|
||||
# olxcleaner
|
||||
# ora2
|
||||
# xblock
|
||||
python-dotenv==1.0.1
|
||||
# via
|
||||
# -r requirements/edx/testing.txt
|
||||
# uvicorn
|
||||
python-ipware==3.0.0
|
||||
# via
|
||||
# -r requirements/edx/doc.txt
|
||||
@@ -1645,10 +1733,6 @@ python-memcached==1.62
|
||||
# via
|
||||
# -r requirements/edx/doc.txt
|
||||
# -r requirements/edx/testing.txt
|
||||
python-multipart==0.0.9
|
||||
# via
|
||||
# -r requirements/edx/testing.txt
|
||||
# fastapi
|
||||
python-slugify==8.0.4
|
||||
# via
|
||||
# -r requirements/edx/doc.txt
|
||||
@@ -1694,7 +1778,7 @@ pyuca==1.2
|
||||
# -r requirements/edx/testing.txt
|
||||
pywatchman==2.0.0
|
||||
# via -r requirements/edx/development.in
|
||||
pyyaml==6.0.1
|
||||
pyyaml==6.0.2
|
||||
# via
|
||||
# -r requirements/edx/doc.txt
|
||||
# -r requirements/edx/testing.txt
|
||||
@@ -1705,7 +1789,6 @@ pyyaml==6.0.1
|
||||
# edx-i18n-tools
|
||||
# jsondiff
|
||||
# sphinxcontrib-openapi
|
||||
# uvicorn
|
||||
# xblock
|
||||
random2==1.0.2
|
||||
# via
|
||||
@@ -1715,7 +1798,7 @@ recommender-xblock==2.2.0
|
||||
# via
|
||||
# -r requirements/edx/doc.txt
|
||||
# -r requirements/edx/testing.txt
|
||||
redis==5.0.7
|
||||
redis==5.0.8
|
||||
# via
|
||||
# -r requirements/edx/doc.txt
|
||||
# -r requirements/edx/testing.txt
|
||||
@@ -1726,7 +1809,7 @@ referencing==0.35.1
|
||||
# -r requirements/edx/testing.txt
|
||||
# jsonschema
|
||||
# jsonschema-specifications
|
||||
regex==2024.5.15
|
||||
regex==2024.7.24
|
||||
# via
|
||||
# -r requirements/edx/doc.txt
|
||||
# -r requirements/edx/testing.txt
|
||||
@@ -1737,6 +1820,7 @@ requests==2.32.3
|
||||
# -r requirements/edx/testing.txt
|
||||
# algoliasearch
|
||||
# analytics-python
|
||||
# cachecontrol
|
||||
# django-oauth-toolkit
|
||||
# djangorestframework-stubs
|
||||
# edx-bulk-grades
|
||||
@@ -1744,6 +1828,8 @@ requests==2.32.3
|
||||
# edx-enterprise
|
||||
# edx-rest-api-client
|
||||
# geoip2
|
||||
# google-api-core
|
||||
# google-cloud-storage
|
||||
# mailsnake
|
||||
# meilisearch
|
||||
# openai
|
||||
@@ -1764,20 +1850,17 @@ requests-oauthlib==2.0.0
|
||||
# -r requirements/edx/doc.txt
|
||||
# -r requirements/edx/testing.txt
|
||||
# social-auth-core
|
||||
rfc3986[idna2008]==1.5.0
|
||||
# via
|
||||
# -r requirements/edx/testing.txt
|
||||
# httpx
|
||||
rich==13.7.1
|
||||
# via
|
||||
# -r requirements/edx/testing.txt
|
||||
# typer
|
||||
rpds-py==0.19.0
|
||||
rpds-py==0.20.0
|
||||
# via
|
||||
# -r requirements/edx/doc.txt
|
||||
# -r requirements/edx/testing.txt
|
||||
# jsonschema
|
||||
# referencing
|
||||
rsa==4.9
|
||||
# via
|
||||
# -r requirements/edx/doc.txt
|
||||
# -r requirements/edx/testing.txt
|
||||
# google-auth
|
||||
rules==3.4
|
||||
# via
|
||||
# -r requirements/edx/doc.txt
|
||||
@@ -1806,15 +1889,11 @@ semantic-version==2.10.0
|
||||
# -r requirements/edx/doc.txt
|
||||
# -r requirements/edx/testing.txt
|
||||
# edx-drf-extensions
|
||||
shapely==2.0.5
|
||||
shapely==2.0.6
|
||||
# via
|
||||
# -r requirements/edx/doc.txt
|
||||
# -r requirements/edx/testing.txt
|
||||
shellingham==1.5.4
|
||||
# via
|
||||
# -r requirements/edx/testing.txt
|
||||
# typer
|
||||
simplejson==3.19.2
|
||||
simplejson==3.19.3
|
||||
# via
|
||||
# -r requirements/edx/doc.txt
|
||||
# -r requirements/edx/testing.txt
|
||||
@@ -1871,19 +1950,18 @@ sniffio==1.3.1
|
||||
# via
|
||||
# -r requirements/edx/testing.txt
|
||||
# anyio
|
||||
# httpcore
|
||||
# httpx
|
||||
snowballstemmer==2.2.0
|
||||
# via
|
||||
# -r requirements/edx/doc.txt
|
||||
# sphinx
|
||||
snowflake-connector-python==3.11.0
|
||||
snowflake-connector-python==3.12.0
|
||||
# via
|
||||
# -r requirements/edx/doc.txt
|
||||
# -r requirements/edx/testing.txt
|
||||
# edx-enterprise
|
||||
social-auth-app-django==5.4.1
|
||||
# via
|
||||
# -c requirements/edx/../constraints.txt
|
||||
# -r requirements/edx/doc.txt
|
||||
# -r requirements/edx/testing.txt
|
||||
# edx-auth-backends
|
||||
@@ -1903,12 +1981,12 @@ sortedcontainers==2.4.0
|
||||
# -r requirements/edx/doc.txt
|
||||
# -r requirements/edx/testing.txt
|
||||
# snowflake-connector-python
|
||||
soupsieve==2.5
|
||||
soupsieve==2.6
|
||||
# via
|
||||
# -r requirements/edx/doc.txt
|
||||
# -r requirements/edx/testing.txt
|
||||
# beautifulsoup4
|
||||
sphinx==7.4.4
|
||||
sphinx==8.0.2
|
||||
# via
|
||||
# -r requirements/edx/doc.txt
|
||||
# pydata-sphinx-theme
|
||||
@@ -1921,23 +1999,23 @@ sphinx==7.4.4
|
||||
# sphinxext-rediraffe
|
||||
sphinx-book-theme==1.1.3
|
||||
# via -r requirements/edx/doc.txt
|
||||
sphinx-design==0.6.0
|
||||
sphinx-design==0.6.1
|
||||
# via -r requirements/edx/doc.txt
|
||||
sphinx-mdinclude==0.6.1
|
||||
sphinx-mdinclude==0.6.2
|
||||
# via
|
||||
# -r requirements/edx/doc.txt
|
||||
# sphinxcontrib-openapi
|
||||
sphinx-reredirects==0.1.5
|
||||
# via -r requirements/edx/doc.txt
|
||||
sphinxcontrib-applehelp==1.0.8
|
||||
sphinxcontrib-applehelp==2.0.0
|
||||
# via
|
||||
# -r requirements/edx/doc.txt
|
||||
# sphinx
|
||||
sphinxcontrib-devhelp==1.0.6
|
||||
sphinxcontrib-devhelp==2.0.0
|
||||
# via
|
||||
# -r requirements/edx/doc.txt
|
||||
# sphinx
|
||||
sphinxcontrib-htmlhelp==2.0.5
|
||||
sphinxcontrib-htmlhelp==2.1.0
|
||||
# via
|
||||
# -r requirements/edx/doc.txt
|
||||
# sphinx
|
||||
@@ -1951,11 +2029,11 @@ sphinxcontrib-jsmath==1.0.1
|
||||
# sphinx
|
||||
sphinxcontrib-openapi[markdown]==0.8.4
|
||||
# via -r requirements/edx/doc.txt
|
||||
sphinxcontrib-qthelp==1.0.7
|
||||
sphinxcontrib-qthelp==2.0.0
|
||||
# via
|
||||
# -r requirements/edx/doc.txt
|
||||
# sphinx
|
||||
sphinxcontrib-serializinghtml==1.1.10
|
||||
sphinxcontrib-serializinghtml==2.0.0
|
||||
# via
|
||||
# -r requirements/edx/doc.txt
|
||||
# sphinx
|
||||
@@ -1971,7 +2049,7 @@ staff-graded-xblock==2.3.0
|
||||
# via
|
||||
# -r requirements/edx/doc.txt
|
||||
# -r requirements/edx/testing.txt
|
||||
starlette==0.37.2
|
||||
starlette==0.38.2
|
||||
# via
|
||||
# -r requirements/edx/testing.txt
|
||||
# fastapi
|
||||
@@ -1989,7 +2067,7 @@ super-csv==3.2.0
|
||||
# -r requirements/edx/doc.txt
|
||||
# -r requirements/edx/testing.txt
|
||||
# edx-bulk-grades
|
||||
sympy==1.13.0
|
||||
sympy==1.13.2
|
||||
# via
|
||||
# -r requirements/edx/doc.txt
|
||||
# -r requirements/edx/testing.txt
|
||||
@@ -2011,27 +2089,23 @@ tinycss2==1.2.1
|
||||
# bleach
|
||||
tomli==2.0.1
|
||||
# via django-stubs
|
||||
tomlkit==0.13.0
|
||||
tomlkit==0.13.2
|
||||
# via
|
||||
# -r requirements/edx/doc.txt
|
||||
# -r requirements/edx/testing.txt
|
||||
# pylint
|
||||
# snowflake-connector-python
|
||||
tox==4.16.0
|
||||
tox==4.18.0
|
||||
# via -r requirements/edx/testing.txt
|
||||
tqdm==4.66.4
|
||||
tqdm==4.66.5
|
||||
# via
|
||||
# -r requirements/edx/doc.txt
|
||||
# -r requirements/edx/testing.txt
|
||||
# nltk
|
||||
# openai
|
||||
typer==0.12.3
|
||||
# via
|
||||
# -r requirements/edx/testing.txt
|
||||
# fastapi-cli
|
||||
types-pytz==2024.1.0.20240417
|
||||
# via django-stubs
|
||||
types-pyyaml==6.0.12.20240311
|
||||
types-pyyaml==6.0.12.20240808
|
||||
# via
|
||||
# django-stubs
|
||||
# djangorestframework-stubs
|
||||
@@ -2058,7 +2132,6 @@ typing-extensions==4.12.2
|
||||
# pydata-sphinx-theme
|
||||
# pylti1p3
|
||||
# snowflake-connector-python
|
||||
# typer
|
||||
tzdata==2024.1
|
||||
# via
|
||||
# -r requirements/edx/doc.txt
|
||||
@@ -2077,6 +2150,7 @@ uritemplate==4.1.1
|
||||
# -r requirements/edx/testing.txt
|
||||
# drf-spectacular
|
||||
# drf-yasg
|
||||
# google-api-python-client
|
||||
urllib3==1.26.19
|
||||
# via
|
||||
# -c requirements/edx/../constraints.txt
|
||||
@@ -2084,22 +2158,16 @@ urllib3==1.26.19
|
||||
# -r requirements/edx/testing.txt
|
||||
# botocore
|
||||
# elasticsearch
|
||||
# pact-python
|
||||
# py2neo
|
||||
# requests
|
||||
user-util==1.1.0
|
||||
# via
|
||||
# -r requirements/edx/doc.txt
|
||||
# -r requirements/edx/testing.txt
|
||||
uvicorn[standard]==0.30.1
|
||||
uvicorn==0.30.6
|
||||
# via
|
||||
# -r requirements/edx/testing.txt
|
||||
# fastapi
|
||||
# pact-python
|
||||
uvloop==0.19.0
|
||||
# via
|
||||
# -r requirements/edx/testing.txt
|
||||
# uvicorn
|
||||
vine==5.1.0
|
||||
# via
|
||||
# -r requirements/edx/doc.txt
|
||||
@@ -2123,15 +2191,11 @@ walrus==0.9.4
|
||||
# -r requirements/edx/doc.txt
|
||||
# -r requirements/edx/testing.txt
|
||||
# edx-event-bus-redis
|
||||
watchdog==4.0.1
|
||||
watchdog==4.0.2
|
||||
# via
|
||||
# -r requirements/edx/development.in
|
||||
# -r requirements/edx/doc.txt
|
||||
# -r requirements/edx/testing.txt
|
||||
watchfiles==0.22.0
|
||||
# via
|
||||
# -r requirements/edx/testing.txt
|
||||
# uvicorn
|
||||
wcwidth==0.2.13
|
||||
# via
|
||||
# -r requirements/edx/doc.txt
|
||||
@@ -2153,16 +2217,12 @@ webencodings==0.5.1
|
||||
# bleach
|
||||
# html5lib
|
||||
# tinycss2
|
||||
webob==1.8.7
|
||||
webob==1.8.8
|
||||
# via
|
||||
# -r requirements/edx/doc.txt
|
||||
# -r requirements/edx/testing.txt
|
||||
# xblock
|
||||
websockets==12.0
|
||||
# via
|
||||
# -r requirements/edx/testing.txt
|
||||
# uvicorn
|
||||
wheel==0.43.0
|
||||
wheel==0.44.0
|
||||
# via
|
||||
# -r requirements/edx/../pip-tools.txt
|
||||
# pip-tools
|
||||
@@ -2173,6 +2233,7 @@ wrapt==1.16.0
|
||||
# astroid
|
||||
xblock[django]==4.0.1
|
||||
# via
|
||||
# -c requirements/edx/../constraints.txt
|
||||
# -r requirements/edx/doc.txt
|
||||
# -r requirements/edx/testing.txt
|
||||
# acid-xblock
|
||||
@@ -2220,7 +2281,8 @@ yarl==1.9.4
|
||||
# -r requirements/edx/doc.txt
|
||||
# -r requirements/edx/testing.txt
|
||||
# aiohttp
|
||||
zipp==3.19.2
|
||||
# pact-python
|
||||
zipp==3.20.0
|
||||
# via
|
||||
# -r requirements/edx/doc.txt
|
||||
# -r requirements/edx/testing.txt
|
||||
|
||||
@@ -10,7 +10,11 @@ accessible-pygments==0.0.5
|
||||
# via pydata-sphinx-theme
|
||||
acid-xblock==0.3.1
|
||||
# via -r requirements/edx/base.txt
|
||||
aiohttp==3.9.5
|
||||
aiohappyeyeballs==2.4.0
|
||||
# via
|
||||
# -r requirements/edx/base.txt
|
||||
# aiohttp
|
||||
aiohttp==3.10.5
|
||||
# via
|
||||
# -r requirements/edx/base.txt
|
||||
# geoip2
|
||||
@@ -19,10 +23,12 @@ aiosignal==1.3.1
|
||||
# via
|
||||
# -r requirements/edx/base.txt
|
||||
# aiohttp
|
||||
alabaster==0.7.16
|
||||
alabaster==1.0.0
|
||||
# via sphinx
|
||||
algoliasearch==3.0.0
|
||||
# via -r requirements/edx/base.txt
|
||||
# via
|
||||
# -c requirements/edx/../constraints.txt
|
||||
# -r requirements/edx/base.txt
|
||||
amqp==5.2.0
|
||||
# via
|
||||
# -r requirements/edx/base.txt
|
||||
@@ -51,7 +57,7 @@ asn1crypto==1.5.1
|
||||
# via
|
||||
# -r requirements/edx/base.txt
|
||||
# snowflake-connector-python
|
||||
attrs==23.2.0
|
||||
attrs==24.2.0
|
||||
# via
|
||||
# -r requirements/edx/base.txt
|
||||
# aiohttp
|
||||
@@ -61,7 +67,7 @@ attrs==23.2.0
|
||||
# openedx-events
|
||||
# openedx-learning
|
||||
# referencing
|
||||
babel==2.15.0
|
||||
babel==2.16.0
|
||||
# via
|
||||
# -r requirements/edx/base.txt
|
||||
# enmerkar
|
||||
@@ -72,7 +78,7 @@ backoff==1.10.0
|
||||
# via
|
||||
# -r requirements/edx/base.txt
|
||||
# analytics-python
|
||||
bcrypt==4.1.3
|
||||
bcrypt==4.2.0
|
||||
# via
|
||||
# -r requirements/edx/base.txt
|
||||
# paramiko
|
||||
@@ -96,19 +102,27 @@ bleach[css]==6.1.0
|
||||
# xblock-poll
|
||||
boto==2.49.0
|
||||
# via -r requirements/edx/base.txt
|
||||
boto3==1.34.144
|
||||
boto3==1.35.1
|
||||
# via
|
||||
# -r requirements/edx/base.txt
|
||||
# django-ses
|
||||
# fs-s3fs
|
||||
# ora2
|
||||
botocore==1.34.144
|
||||
botocore==1.35.1
|
||||
# via
|
||||
# -r requirements/edx/base.txt
|
||||
# boto3
|
||||
# s3transfer
|
||||
bridgekeeper==0.9
|
||||
# via -r requirements/edx/base.txt
|
||||
cachecontrol==0.14.0
|
||||
# via
|
||||
# -r requirements/edx/base.txt
|
||||
# firebase-admin
|
||||
cachetools==5.5.0
|
||||
# via
|
||||
# -r requirements/edx/base.txt
|
||||
# google-auth
|
||||
camel-converter[pydantic]==3.1.2
|
||||
# via
|
||||
# -r requirements/edx/base.txt
|
||||
@@ -130,7 +144,7 @@ certifi==2024.7.4
|
||||
# py2neo
|
||||
# requests
|
||||
# snowflake-connector-python
|
||||
cffi==1.16.0
|
||||
cffi==1.17.0
|
||||
# via
|
||||
# -r requirements/edx/base.txt
|
||||
# cryptography
|
||||
@@ -208,7 +222,7 @@ defusedxml==0.7.1
|
||||
# ora2
|
||||
# python3-openid
|
||||
# social-auth-core
|
||||
django==4.2.14
|
||||
django==4.2.15
|
||||
# via
|
||||
# -c requirements/edx/../common_constraints.txt
|
||||
# -c requirements/edx/../constraints.txt
|
||||
@@ -227,6 +241,7 @@ django==4.2.14
|
||||
# django-multi-email-field
|
||||
# django-mysql
|
||||
# django-oauth-toolkit
|
||||
# django-push-notifications
|
||||
# django-sekizai
|
||||
# django-ses
|
||||
# django-statici18n
|
||||
@@ -318,7 +333,7 @@ django-fernet-fields-v2==0.9
|
||||
# via
|
||||
# -r requirements/edx/base.txt
|
||||
# edx-enterprise
|
||||
django-filter==24.2
|
||||
django-filter==24.3
|
||||
# via
|
||||
# -r requirements/edx/base.txt
|
||||
# edx-enterprise
|
||||
@@ -373,6 +388,10 @@ django-object-actions==4.2.0
|
||||
# edx-enterprise
|
||||
django-pipeline==3.1.0
|
||||
# via -r requirements/edx/base.txt
|
||||
django-push-notifications==3.1.0
|
||||
# via
|
||||
# -r requirements/edx/base.txt
|
||||
# edx-ace
|
||||
django-ratelimit==4.1.0
|
||||
# via -r requirements/edx/base.txt
|
||||
django-sekizai==4.1.0
|
||||
@@ -462,7 +481,7 @@ drf-yasg==1.21.7
|
||||
# -r requirements/edx/base.txt
|
||||
# django-user-tasks
|
||||
# edx-api-doc-tools
|
||||
edx-ace==1.9.1
|
||||
edx-ace==1.11.1
|
||||
# via -r requirements/edx/base.txt
|
||||
edx-api-doc-tools==1.8.0
|
||||
# via
|
||||
@@ -490,7 +509,7 @@ edx-celeryutils==1.3.0
|
||||
# super-csv
|
||||
edx-codejail==3.4.1
|
||||
# via -r requirements/edx/base.txt
|
||||
edx-completion==4.6.6
|
||||
edx-completion==4.6.7
|
||||
# via -r requirements/edx/base.txt
|
||||
edx-django-release-util==1.4.0
|
||||
# via
|
||||
@@ -499,7 +518,7 @@ edx-django-release-util==1.4.0
|
||||
# edxval
|
||||
edx-django-sites-extensions==4.2.0
|
||||
# via -r requirements/edx/base.txt
|
||||
edx-django-utils==5.14.2
|
||||
edx-django-utils==5.15.0
|
||||
# via
|
||||
# -r requirements/edx/base.txt
|
||||
# django-config-models
|
||||
@@ -528,11 +547,11 @@ edx-drf-extensions==10.3.0
|
||||
# edx-when
|
||||
# edxval
|
||||
# openedx-learning
|
||||
edx-enterprise==4.21.9
|
||||
edx-enterprise==4.23.9
|
||||
# via
|
||||
# -c requirements/edx/../constraints.txt
|
||||
# -r requirements/edx/base.txt
|
||||
edx-event-bus-kafka==5.7.0
|
||||
edx-event-bus-kafka==5.8.1
|
||||
# via -r requirements/edx/base.txt
|
||||
edx-event-bus-redis==0.5.0
|
||||
# via -r requirements/edx/base.txt
|
||||
@@ -575,11 +594,11 @@ edx-rest-api-client==5.7.1
|
||||
# -r requirements/edx/base.txt
|
||||
# edx-enterprise
|
||||
# edx-proctoring
|
||||
edx-search==3.9.1
|
||||
edx-search==4.0.0
|
||||
# via -r requirements/edx/base.txt
|
||||
edx-sga==0.25.0
|
||||
# via -r requirements/edx/base.txt
|
||||
edx-submissions==3.7.5
|
||||
edx-submissions==3.7.7
|
||||
# via
|
||||
# -r requirements/edx/base.txt
|
||||
# ora2
|
||||
@@ -633,6 +652,10 @@ filelock==3.15.4
|
||||
# via
|
||||
# -r requirements/edx/base.txt
|
||||
# snowflake-connector-python
|
||||
firebase-admin==6.5.0
|
||||
# via
|
||||
# -r requirements/edx/base.txt
|
||||
# edx-ace
|
||||
frozenlist==1.4.1
|
||||
# via
|
||||
# -r requirements/edx/base.txt
|
||||
@@ -660,7 +683,68 @@ gitpython==3.1.43
|
||||
# via -r requirements/edx/doc.in
|
||||
glob2==0.7
|
||||
# via -r requirements/edx/base.txt
|
||||
gunicorn==22.0.0
|
||||
google-api-core[grpc]==2.19.1
|
||||
# via
|
||||
# -r requirements/edx/base.txt
|
||||
# firebase-admin
|
||||
# google-api-python-client
|
||||
# google-cloud-core
|
||||
# google-cloud-firestore
|
||||
# google-cloud-storage
|
||||
google-api-python-client==2.141.0
|
||||
# via
|
||||
# -r requirements/edx/base.txt
|
||||
# firebase-admin
|
||||
google-auth==2.34.0
|
||||
# via
|
||||
# -r requirements/edx/base.txt
|
||||
# google-api-core
|
||||
# google-api-python-client
|
||||
# google-auth-httplib2
|
||||
# google-cloud-core
|
||||
# google-cloud-firestore
|
||||
# google-cloud-storage
|
||||
google-auth-httplib2==0.2.0
|
||||
# via
|
||||
# -r requirements/edx/base.txt
|
||||
# google-api-python-client
|
||||
google-cloud-core==2.4.1
|
||||
# via
|
||||
# -r requirements/edx/base.txt
|
||||
# google-cloud-firestore
|
||||
# google-cloud-storage
|
||||
google-cloud-firestore==2.17.2
|
||||
# via
|
||||
# -r requirements/edx/base.txt
|
||||
# firebase-admin
|
||||
google-cloud-storage==2.18.2
|
||||
# via
|
||||
# -r requirements/edx/base.txt
|
||||
# firebase-admin
|
||||
google-crc32c==1.5.0
|
||||
# via
|
||||
# -r requirements/edx/base.txt
|
||||
# google-cloud-storage
|
||||
# google-resumable-media
|
||||
google-resumable-media==2.7.2
|
||||
# via
|
||||
# -r requirements/edx/base.txt
|
||||
# google-cloud-storage
|
||||
googleapis-common-protos==1.63.2
|
||||
# via
|
||||
# -r requirements/edx/base.txt
|
||||
# google-api-core
|
||||
# grpcio-status
|
||||
grpcio==1.65.5
|
||||
# via
|
||||
# -r requirements/edx/base.txt
|
||||
# google-api-core
|
||||
# grpcio-status
|
||||
grpcio-status==1.65.5
|
||||
# via
|
||||
# -r requirements/edx/base.txt
|
||||
# google-api-core
|
||||
gunicorn==23.0.0
|
||||
# via -r requirements/edx/base.txt
|
||||
help-tokens==2.4.0
|
||||
# via -r requirements/edx/base.txt
|
||||
@@ -668,6 +752,11 @@ html5lib==1.1
|
||||
# via
|
||||
# -r requirements/edx/base.txt
|
||||
# ora2
|
||||
httplib2==0.22.0
|
||||
# via
|
||||
# -r requirements/edx/base.txt
|
||||
# google-api-python-client
|
||||
# google-auth-httplib2
|
||||
icalendar==5.0.13
|
||||
# via -r requirements/edx/base.txt
|
||||
idna==3.7
|
||||
@@ -679,10 +768,8 @@ idna==3.7
|
||||
# yarl
|
||||
imagesize==1.4.1
|
||||
# via sphinx
|
||||
importlib-metadata==6.11.0
|
||||
# via
|
||||
# -c requirements/edx/../common_constraints.txt
|
||||
# -r requirements/edx/base.txt
|
||||
importlib-metadata==8.3.0
|
||||
# via -r requirements/edx/base.txt
|
||||
inflection==0.5.1
|
||||
# via
|
||||
# -r requirements/edx/base.txt
|
||||
@@ -712,7 +799,7 @@ joblib==1.4.2
|
||||
# via
|
||||
# -r requirements/edx/base.txt
|
||||
# nltk
|
||||
jsondiff==2.1.2
|
||||
jsondiff==2.2.0
|
||||
# via
|
||||
# -r requirements/edx/base.txt
|
||||
# edx-enterprise
|
||||
@@ -740,7 +827,7 @@ jwcrypto==1.5.6
|
||||
# -r requirements/edx/base.txt
|
||||
# django-oauth-toolkit
|
||||
# pylti1p3
|
||||
kombu==5.3.7
|
||||
kombu==5.4.0
|
||||
# via
|
||||
# -r requirements/edx/base.txt
|
||||
# celery
|
||||
@@ -817,7 +904,7 @@ monotonic==1.6
|
||||
# -r requirements/edx/base.txt
|
||||
# analytics-python
|
||||
# py2neo
|
||||
more-itertools==10.3.0
|
||||
more-itertools==10.4.0
|
||||
# via
|
||||
# -r requirements/edx/base.txt
|
||||
# cssutils
|
||||
@@ -825,6 +912,10 @@ mpmath==1.3.0
|
||||
# via
|
||||
# -r requirements/edx/base.txt
|
||||
# sympy
|
||||
msgpack==1.0.8
|
||||
# via
|
||||
# -r requirements/edx/base.txt
|
||||
# cachecontrol
|
||||
multidict==6.0.5
|
||||
# via
|
||||
# -r requirements/edx/base.txt
|
||||
@@ -832,13 +923,13 @@ multidict==6.0.5
|
||||
# yarl
|
||||
mysqlclient==2.2.4
|
||||
# via -r requirements/edx/base.txt
|
||||
newrelic==9.12.0
|
||||
newrelic==9.13.0
|
||||
# via
|
||||
# -r requirements/edx/base.txt
|
||||
# edx-django-utils
|
||||
nh3==0.2.18
|
||||
# via -r requirements/edx/base.txt
|
||||
nltk==3.8.1
|
||||
nltk==3.9.1
|
||||
# via
|
||||
# -r requirements/edx/base.txt
|
||||
# chem
|
||||
@@ -891,7 +982,7 @@ openedx-filters==1.9.0
|
||||
# -r requirements/edx/base.txt
|
||||
# lti-consumer-xblock
|
||||
# ora2
|
||||
openedx-learning==0.10.0
|
||||
openedx-learning==0.10.1
|
||||
# via
|
||||
# -c requirements/edx/../constraints.txt
|
||||
# -r requirements/edx/base.txt
|
||||
@@ -901,7 +992,7 @@ optimizely-sdk==4.1.1
|
||||
# via
|
||||
# -c requirements/edx/../constraints.txt
|
||||
# -r requirements/edx/base.txt
|
||||
ora2==6.11.1
|
||||
ora2==6.11.2
|
||||
# via -r requirements/edx/base.txt
|
||||
packaging==24.1
|
||||
# via
|
||||
@@ -916,7 +1007,7 @@ pansi==2020.7.3
|
||||
# via
|
||||
# -r requirements/edx/base.txt
|
||||
# py2neo
|
||||
paramiko==3.4.0
|
||||
paramiko==3.4.1
|
||||
# via
|
||||
# -r requirements/edx/base.txt
|
||||
# edx-enterprise
|
||||
@@ -964,6 +1055,19 @@ prompt-toolkit==3.0.47
|
||||
# via
|
||||
# -r requirements/edx/base.txt
|
||||
# click-repl
|
||||
proto-plus==1.24.0
|
||||
# via
|
||||
# -r requirements/edx/base.txt
|
||||
# google-api-core
|
||||
# google-cloud-firestore
|
||||
protobuf==5.27.3
|
||||
# via
|
||||
# -r requirements/edx/base.txt
|
||||
# google-api-core
|
||||
# google-cloud-firestore
|
||||
# googleapis-common-protos
|
||||
# grpcio-status
|
||||
# proto-plus
|
||||
psutil==6.0.0
|
||||
# via
|
||||
# -r requirements/edx/base.txt
|
||||
@@ -976,6 +1080,12 @@ pyasn1==0.6.0
|
||||
# via
|
||||
# -r requirements/edx/base.txt
|
||||
# pgpy
|
||||
# pyasn1-modules
|
||||
# rsa
|
||||
pyasn1-modules==0.4.0
|
||||
# via
|
||||
# -r requirements/edx/base.txt
|
||||
# google-auth
|
||||
pycountry==24.6.1
|
||||
# via -r requirements/edx/base.txt
|
||||
pycparser==2.22
|
||||
@@ -1011,7 +1121,7 @@ pyjwkest==1.4.2
|
||||
# -r requirements/edx/base.txt
|
||||
# edx-token-utils
|
||||
# lti-consumer-xblock
|
||||
pyjwt[crypto]==2.8.0
|
||||
pyjwt[crypto]==2.9.0
|
||||
# via
|
||||
# -r requirements/edx/base.txt
|
||||
# drf-jwt
|
||||
@@ -1019,6 +1129,7 @@ pyjwt[crypto]==2.8.0
|
||||
# edx-drf-extensions
|
||||
# edx-proctoring
|
||||
# edx-rest-api-client
|
||||
# firebase-admin
|
||||
# pylti1p3
|
||||
# snowflake-connector-python
|
||||
# social-auth-core
|
||||
@@ -1045,7 +1156,7 @@ pynacl==1.5.0
|
||||
# paramiko
|
||||
pynliner==0.8.0
|
||||
# via -r requirements/edx/base.txt
|
||||
pyopenssl==24.1.0
|
||||
pyopenssl==24.2.1
|
||||
# via
|
||||
# -r requirements/edx/base.txt
|
||||
# optimizely-sdk
|
||||
@@ -1054,6 +1165,7 @@ pyparsing==3.1.2
|
||||
# via
|
||||
# -r requirements/edx/base.txt
|
||||
# chem
|
||||
# httplib2
|
||||
# openedx-calc
|
||||
pyrsistent==0.20.0
|
||||
# via
|
||||
@@ -1117,7 +1229,7 @@ pytz==2024.1
|
||||
# xblock
|
||||
pyuca==1.2
|
||||
# via -r requirements/edx/base.txt
|
||||
pyyaml==6.0.1
|
||||
pyyaml==6.0.2
|
||||
# via
|
||||
# -r requirements/edx/base.txt
|
||||
# code-annotations
|
||||
@@ -1132,7 +1244,7 @@ random2==1.0.2
|
||||
# via -r requirements/edx/base.txt
|
||||
recommender-xblock==2.2.0
|
||||
# via -r requirements/edx/base.txt
|
||||
redis==5.0.7
|
||||
redis==5.0.8
|
||||
# via
|
||||
# -r requirements/edx/base.txt
|
||||
# walrus
|
||||
@@ -1141,7 +1253,7 @@ referencing==0.35.1
|
||||
# -r requirements/edx/base.txt
|
||||
# jsonschema
|
||||
# jsonschema-specifications
|
||||
regex==2024.5.15
|
||||
regex==2024.7.24
|
||||
# via
|
||||
# -r requirements/edx/base.txt
|
||||
# nltk
|
||||
@@ -1150,12 +1262,15 @@ requests==2.32.3
|
||||
# -r requirements/edx/base.txt
|
||||
# algoliasearch
|
||||
# analytics-python
|
||||
# cachecontrol
|
||||
# django-oauth-toolkit
|
||||
# edx-bulk-grades
|
||||
# edx-drf-extensions
|
||||
# edx-enterprise
|
||||
# edx-rest-api-client
|
||||
# geoip2
|
||||
# google-api-core
|
||||
# google-cloud-storage
|
||||
# mailsnake
|
||||
# meilisearch
|
||||
# openai
|
||||
@@ -1174,11 +1289,15 @@ requests-oauthlib==2.0.0
|
||||
# via
|
||||
# -r requirements/edx/base.txt
|
||||
# social-auth-core
|
||||
rpds-py==0.19.0
|
||||
rpds-py==0.20.0
|
||||
# via
|
||||
# -r requirements/edx/base.txt
|
||||
# jsonschema
|
||||
# referencing
|
||||
rsa==4.9
|
||||
# via
|
||||
# -r requirements/edx/base.txt
|
||||
# google-auth
|
||||
rules==3.4
|
||||
# via
|
||||
# -r requirements/edx/base.txt
|
||||
@@ -1202,9 +1321,9 @@ semantic-version==2.10.0
|
||||
# via
|
||||
# -r requirements/edx/base.txt
|
||||
# edx-drf-extensions
|
||||
shapely==2.0.5
|
||||
shapely==2.0.6
|
||||
# via -r requirements/edx/base.txt
|
||||
simplejson==3.19.2
|
||||
simplejson==3.19.3
|
||||
# via
|
||||
# -r requirements/edx/base.txt
|
||||
# sailthru-client
|
||||
@@ -1249,12 +1368,13 @@ smmap==5.0.1
|
||||
# via gitdb
|
||||
snowballstemmer==2.2.0
|
||||
# via sphinx
|
||||
snowflake-connector-python==3.11.0
|
||||
snowflake-connector-python==3.12.0
|
||||
# via
|
||||
# -r requirements/edx/base.txt
|
||||
# edx-enterprise
|
||||
social-auth-app-django==5.4.1
|
||||
# via
|
||||
# -c requirements/edx/../constraints.txt
|
||||
# -r requirements/edx/base.txt
|
||||
# edx-auth-backends
|
||||
social-auth-core==4.5.4
|
||||
@@ -1270,11 +1390,11 @@ sortedcontainers==2.4.0
|
||||
# via
|
||||
# -r requirements/edx/base.txt
|
||||
# snowflake-connector-python
|
||||
soupsieve==2.5
|
||||
soupsieve==2.6
|
||||
# via
|
||||
# -r requirements/edx/base.txt
|
||||
# beautifulsoup4
|
||||
sphinx==7.4.4
|
||||
sphinx==8.0.2
|
||||
# via
|
||||
# -r requirements/edx/doc.in
|
||||
# pydata-sphinx-theme
|
||||
@@ -1287,17 +1407,17 @@ sphinx==7.4.4
|
||||
# sphinxext-rediraffe
|
||||
sphinx-book-theme==1.1.3
|
||||
# via -r requirements/edx/doc.in
|
||||
sphinx-design==0.6.0
|
||||
sphinx-design==0.6.1
|
||||
# via -r requirements/edx/doc.in
|
||||
sphinx-mdinclude==0.6.1
|
||||
sphinx-mdinclude==0.6.2
|
||||
# via sphinxcontrib-openapi
|
||||
sphinx-reredirects==0.1.5
|
||||
# via -r requirements/edx/doc.in
|
||||
sphinxcontrib-applehelp==1.0.8
|
||||
sphinxcontrib-applehelp==2.0.0
|
||||
# via sphinx
|
||||
sphinxcontrib-devhelp==1.0.6
|
||||
sphinxcontrib-devhelp==2.0.0
|
||||
# via sphinx
|
||||
sphinxcontrib-htmlhelp==2.0.5
|
||||
sphinxcontrib-htmlhelp==2.1.0
|
||||
# via sphinx
|
||||
sphinxcontrib-httpdomain==1.8.1
|
||||
# via sphinxcontrib-openapi
|
||||
@@ -1305,9 +1425,9 @@ sphinxcontrib-jsmath==1.0.1
|
||||
# via sphinx
|
||||
sphinxcontrib-openapi[markdown]==0.8.4
|
||||
# via -r requirements/edx/doc.in
|
||||
sphinxcontrib-qthelp==1.0.7
|
||||
sphinxcontrib-qthelp==2.0.0
|
||||
# via sphinx
|
||||
sphinxcontrib-serializinghtml==1.1.10
|
||||
sphinxcontrib-serializinghtml==2.0.0
|
||||
# via sphinx
|
||||
sphinxext-rediraffe==0.2.7
|
||||
# via -r requirements/edx/doc.in
|
||||
@@ -1329,7 +1449,7 @@ super-csv==3.2.0
|
||||
# via
|
||||
# -r requirements/edx/base.txt
|
||||
# edx-bulk-grades
|
||||
sympy==1.13.0
|
||||
sympy==1.13.2
|
||||
# via
|
||||
# -r requirements/edx/base.txt
|
||||
# openedx-calc
|
||||
@@ -1345,11 +1465,11 @@ tinycss2==1.2.1
|
||||
# via
|
||||
# -r requirements/edx/base.txt
|
||||
# bleach
|
||||
tomlkit==0.13.0
|
||||
tomlkit==0.13.2
|
||||
# via
|
||||
# -r requirements/edx/base.txt
|
||||
# snowflake-connector-python
|
||||
tqdm==4.66.4
|
||||
tqdm==4.66.5
|
||||
# via
|
||||
# -r requirements/edx/base.txt
|
||||
# nltk
|
||||
@@ -1378,6 +1498,7 @@ uritemplate==4.1.1
|
||||
# -r requirements/edx/base.txt
|
||||
# drf-spectacular
|
||||
# drf-yasg
|
||||
# google-api-python-client
|
||||
urllib3==1.26.19
|
||||
# via
|
||||
# -c requirements/edx/../constraints.txt
|
||||
@@ -1402,7 +1523,7 @@ walrus==0.9.4
|
||||
# via
|
||||
# -r requirements/edx/base.txt
|
||||
# edx-event-bus-redis
|
||||
watchdog==4.0.1
|
||||
watchdog==4.0.2
|
||||
# via -r requirements/edx/base.txt
|
||||
wcwidth==0.2.13
|
||||
# via
|
||||
@@ -1422,7 +1543,7 @@ webencodings==0.5.1
|
||||
# bleach
|
||||
# html5lib
|
||||
# tinycss2
|
||||
webob==1.8.7
|
||||
webob==1.8.8
|
||||
# via
|
||||
# -r requirements/edx/base.txt
|
||||
# xblock
|
||||
@@ -1430,6 +1551,7 @@ wrapt==1.16.0
|
||||
# via -r requirements/edx/base.txt
|
||||
xblock[django]==4.0.1
|
||||
# via
|
||||
# -c requirements/edx/../constraints.txt
|
||||
# -r requirements/edx/base.txt
|
||||
# acid-xblock
|
||||
# crowdsourcehinter-xblock
|
||||
@@ -1465,7 +1587,7 @@ yarl==1.9.4
|
||||
# via
|
||||
# -r requirements/edx/base.txt
|
||||
# aiohttp
|
||||
zipp==3.19.2
|
||||
zipp==3.20.0
|
||||
# via
|
||||
# -r requirements/edx/base.txt
|
||||
# importlib-metadata
|
||||
|
||||
@@ -61,7 +61,7 @@ urllib3==1.26.19
|
||||
# via
|
||||
# -c requirements/edx/../constraints.txt
|
||||
# requests
|
||||
watchdog==4.0.1
|
||||
watchdog==4.0.2
|
||||
# via -r requirements/edx/paver.in
|
||||
wrapt==1.16.0
|
||||
# via -r requirements/edx/paver.in
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
#
|
||||
# make upgrade
|
||||
#
|
||||
attrs==23.2.0
|
||||
attrs==24.2.0
|
||||
# via
|
||||
# glom
|
||||
# jsonschema
|
||||
@@ -15,7 +15,7 @@ boltons==21.0.0
|
||||
# face
|
||||
# glom
|
||||
# semgrep
|
||||
bracex==2.4
|
||||
bracex==2.5
|
||||
# via wcmatch
|
||||
certifi==2024.7.4
|
||||
# via requests
|
||||
@@ -62,7 +62,7 @@ requests==2.32.3
|
||||
# via semgrep
|
||||
rich==13.7.1
|
||||
# via semgrep
|
||||
rpds-py==0.19.0
|
||||
rpds-py==0.20.0
|
||||
# via
|
||||
# jsonschema
|
||||
# referencing
|
||||
|
||||
@@ -8,7 +8,11 @@
|
||||
# via -r requirements/edx/base.txt
|
||||
acid-xblock==0.3.1
|
||||
# via -r requirements/edx/base.txt
|
||||
aiohttp==3.9.5
|
||||
aiohappyeyeballs==2.4.0
|
||||
# via
|
||||
# -r requirements/edx/base.txt
|
||||
# aiohttp
|
||||
aiohttp==3.10.5
|
||||
# via
|
||||
# -r requirements/edx/base.txt
|
||||
# geoip2
|
||||
@@ -18,7 +22,9 @@ aiosignal==1.3.1
|
||||
# -r requirements/edx/base.txt
|
||||
# aiohttp
|
||||
algoliasearch==3.0.0
|
||||
# via -r requirements/edx/base.txt
|
||||
# via
|
||||
# -c requirements/edx/../constraints.txt
|
||||
# -r requirements/edx/base.txt
|
||||
amqp==5.2.0
|
||||
# via
|
||||
# -r requirements/edx/base.txt
|
||||
@@ -34,10 +40,7 @@ annotated-types==0.7.0
|
||||
# -r requirements/edx/base.txt
|
||||
# pydantic
|
||||
anyio==4.4.0
|
||||
# via
|
||||
# httpcore
|
||||
# starlette
|
||||
# watchfiles
|
||||
# via starlette
|
||||
appdirs==1.4.4
|
||||
# via
|
||||
# -r requirements/edx/base.txt
|
||||
@@ -56,7 +59,7 @@ astroid==2.13.5
|
||||
# via
|
||||
# pylint
|
||||
# pylint-celery
|
||||
attrs==23.2.0
|
||||
attrs==24.2.0
|
||||
# via
|
||||
# -r requirements/edx/base.txt
|
||||
# aiohttp
|
||||
@@ -66,7 +69,7 @@ attrs==23.2.0
|
||||
# openedx-events
|
||||
# openedx-learning
|
||||
# referencing
|
||||
babel==2.15.0
|
||||
babel==2.16.0
|
||||
# via
|
||||
# -r requirements/edx/base.txt
|
||||
# enmerkar
|
||||
@@ -75,7 +78,7 @@ backoff==1.10.0
|
||||
# via
|
||||
# -r requirements/edx/base.txt
|
||||
# analytics-python
|
||||
bcrypt==4.1.3
|
||||
bcrypt==4.2.0
|
||||
# via
|
||||
# -r requirements/edx/base.txt
|
||||
# paramiko
|
||||
@@ -99,21 +102,28 @@ bleach[css]==6.1.0
|
||||
# xblock-poll
|
||||
boto==2.49.0
|
||||
# via -r requirements/edx/base.txt
|
||||
boto3==1.34.144
|
||||
boto3==1.35.1
|
||||
# via
|
||||
# -r requirements/edx/base.txt
|
||||
# django-ses
|
||||
# fs-s3fs
|
||||
# ora2
|
||||
botocore==1.34.144
|
||||
botocore==1.35.1
|
||||
# via
|
||||
# -r requirements/edx/base.txt
|
||||
# boto3
|
||||
# s3transfer
|
||||
bridgekeeper==0.9
|
||||
# via -r requirements/edx/base.txt
|
||||
cachetools==5.4.0
|
||||
# via tox
|
||||
cachecontrol==0.14.0
|
||||
# via
|
||||
# -r requirements/edx/base.txt
|
||||
# firebase-admin
|
||||
cachetools==5.5.0
|
||||
# via
|
||||
# -r requirements/edx/base.txt
|
||||
# google-auth
|
||||
# tox
|
||||
camel-converter[pydantic]==3.1.2
|
||||
# via
|
||||
# -r requirements/edx/base.txt
|
||||
@@ -132,15 +142,14 @@ certifi==2024.7.4
|
||||
# via
|
||||
# -r requirements/edx/base.txt
|
||||
# elasticsearch
|
||||
# httpcore
|
||||
# httpx
|
||||
# py2neo
|
||||
# requests
|
||||
# snowflake-connector-python
|
||||
cffi==1.16.0
|
||||
cffi==1.17.0
|
||||
# via
|
||||
# -r requirements/edx/base.txt
|
||||
# cryptography
|
||||
# pact-python
|
||||
# pynacl
|
||||
# snowflake-connector-python
|
||||
chardet==5.2.0
|
||||
@@ -173,7 +182,6 @@ click==8.1.6
|
||||
# import-linter
|
||||
# nltk
|
||||
# pact-python
|
||||
# typer
|
||||
# user-util
|
||||
# uvicorn
|
||||
click-didyoumean==0.3.1
|
||||
@@ -201,7 +209,7 @@ codejail-includes==1.0.0
|
||||
# via -r requirements/edx/base.txt
|
||||
colorama==0.4.6
|
||||
# via tox
|
||||
coverage[toml]==7.6.0
|
||||
coverage[toml]==7.6.1
|
||||
# via
|
||||
# -r requirements/edx/coverage.txt
|
||||
# pytest-cov
|
||||
@@ -237,13 +245,13 @@ defusedxml==0.7.1
|
||||
# ora2
|
||||
# python3-openid
|
||||
# social-auth-core
|
||||
diff-cover==9.1.0
|
||||
diff-cover==9.1.1
|
||||
# via -r requirements/edx/coverage.txt
|
||||
dill==0.3.8
|
||||
# via pylint
|
||||
distlib==0.3.8
|
||||
# via virtualenv
|
||||
django==4.2.14
|
||||
django==4.2.15
|
||||
# via
|
||||
# -c requirements/edx/../common_constraints.txt
|
||||
# -c requirements/edx/../constraints.txt
|
||||
@@ -262,6 +270,7 @@ django==4.2.14
|
||||
# django-multi-email-field
|
||||
# django-mysql
|
||||
# django-oauth-toolkit
|
||||
# django-push-notifications
|
||||
# django-sekizai
|
||||
# django-ses
|
||||
# django-statici18n
|
||||
@@ -353,7 +362,7 @@ django-fernet-fields-v2==0.9
|
||||
# via
|
||||
# -r requirements/edx/base.txt
|
||||
# edx-enterprise
|
||||
django-filter==24.2
|
||||
django-filter==24.3
|
||||
# via
|
||||
# -r requirements/edx/base.txt
|
||||
# edx-enterprise
|
||||
@@ -408,6 +417,10 @@ django-object-actions==4.2.0
|
||||
# edx-enterprise
|
||||
django-pipeline==3.1.0
|
||||
# via -r requirements/edx/base.txt
|
||||
django-push-notifications==3.1.0
|
||||
# via
|
||||
# -r requirements/edx/base.txt
|
||||
# edx-ace
|
||||
django-ratelimit==4.1.0
|
||||
# via -r requirements/edx/base.txt
|
||||
django-sekizai==4.1.0
|
||||
@@ -478,7 +491,6 @@ djangorestframework-xml==2.0.0
|
||||
dnspython==2.6.1
|
||||
# via
|
||||
# -r requirements/edx/base.txt
|
||||
# email-validator
|
||||
# pymongo
|
||||
done-xblock==2.3.0
|
||||
# via -r requirements/edx/base.txt
|
||||
@@ -493,7 +505,7 @@ drf-yasg==1.21.7
|
||||
# -r requirements/edx/base.txt
|
||||
# django-user-tasks
|
||||
# edx-api-doc-tools
|
||||
edx-ace==1.9.1
|
||||
edx-ace==1.11.1
|
||||
# via -r requirements/edx/base.txt
|
||||
edx-api-doc-tools==1.8.0
|
||||
# via
|
||||
@@ -521,7 +533,7 @@ edx-celeryutils==1.3.0
|
||||
# super-csv
|
||||
edx-codejail==3.4.1
|
||||
# via -r requirements/edx/base.txt
|
||||
edx-completion==4.6.6
|
||||
edx-completion==4.6.7
|
||||
# via -r requirements/edx/base.txt
|
||||
edx-django-release-util==1.4.0
|
||||
# via
|
||||
@@ -530,7 +542,7 @@ edx-django-release-util==1.4.0
|
||||
# edxval
|
||||
edx-django-sites-extensions==4.2.0
|
||||
# via -r requirements/edx/base.txt
|
||||
edx-django-utils==5.14.2
|
||||
edx-django-utils==5.15.0
|
||||
# via
|
||||
# -r requirements/edx/base.txt
|
||||
# django-config-models
|
||||
@@ -559,11 +571,11 @@ edx-drf-extensions==10.3.0
|
||||
# edx-when
|
||||
# edxval
|
||||
# openedx-learning
|
||||
edx-enterprise==4.21.9
|
||||
edx-enterprise==4.23.9
|
||||
# via
|
||||
# -c requirements/edx/../constraints.txt
|
||||
# -r requirements/edx/base.txt
|
||||
edx-event-bus-kafka==5.7.0
|
||||
edx-event-bus-kafka==5.8.1
|
||||
# via -r requirements/edx/base.txt
|
||||
edx-event-bus-redis==0.5.0
|
||||
# via -r requirements/edx/base.txt
|
||||
@@ -608,11 +620,11 @@ edx-rest-api-client==5.7.1
|
||||
# -r requirements/edx/base.txt
|
||||
# edx-enterprise
|
||||
# edx-proctoring
|
||||
edx-search==3.9.1
|
||||
edx-search==4.0.0
|
||||
# via -r requirements/edx/base.txt
|
||||
edx-sga==0.25.0
|
||||
# via -r requirements/edx/base.txt
|
||||
edx-submissions==3.7.5
|
||||
edx-submissions==3.7.7
|
||||
# via
|
||||
# -r requirements/edx/base.txt
|
||||
# ora2
|
||||
@@ -645,8 +657,6 @@ elasticsearch==7.13.4
|
||||
# -c requirements/edx/../common_constraints.txt
|
||||
# -r requirements/edx/base.txt
|
||||
# edx-search
|
||||
email-validator==2.2.0
|
||||
# via fastapi
|
||||
enmerkar==0.7.1
|
||||
# via
|
||||
# -r requirements/edx/base.txt
|
||||
@@ -662,14 +672,12 @@ event-tracking==3.0.0
|
||||
# edx-search
|
||||
execnet==2.1.1
|
||||
# via pytest-xdist
|
||||
factory-boy==3.3.0
|
||||
factory-boy==3.3.1
|
||||
# via -r requirements/edx/testing.in
|
||||
faker==26.0.0
|
||||
faker==27.0.0
|
||||
# via factory-boy
|
||||
fastapi==0.111.1
|
||||
fastapi==0.112.1
|
||||
# via pact-python
|
||||
fastapi-cli==0.0.4
|
||||
# via fastapi
|
||||
fastavro==1.9.5
|
||||
# via
|
||||
# -r requirements/edx/base.txt
|
||||
@@ -680,6 +688,10 @@ filelock==3.15.4
|
||||
# snowflake-connector-python
|
||||
# tox
|
||||
# virtualenv
|
||||
firebase-admin==6.5.0
|
||||
# via
|
||||
# -r requirements/edx/base.txt
|
||||
# edx-ace
|
||||
freezegun==1.5.1
|
||||
# via -r requirements/edx/testing.in
|
||||
frozenlist==1.4.1
|
||||
@@ -705,48 +717,100 @@ geoip2==4.8.0
|
||||
# via -r requirements/edx/base.txt
|
||||
glob2==0.7
|
||||
# via -r requirements/edx/base.txt
|
||||
google-api-core[grpc]==2.19.1
|
||||
# via
|
||||
# -r requirements/edx/base.txt
|
||||
# firebase-admin
|
||||
# google-api-python-client
|
||||
# google-cloud-core
|
||||
# google-cloud-firestore
|
||||
# google-cloud-storage
|
||||
google-api-python-client==2.141.0
|
||||
# via
|
||||
# -r requirements/edx/base.txt
|
||||
# firebase-admin
|
||||
google-auth==2.34.0
|
||||
# via
|
||||
# -r requirements/edx/base.txt
|
||||
# google-api-core
|
||||
# google-api-python-client
|
||||
# google-auth-httplib2
|
||||
# google-cloud-core
|
||||
# google-cloud-firestore
|
||||
# google-cloud-storage
|
||||
google-auth-httplib2==0.2.0
|
||||
# via
|
||||
# -r requirements/edx/base.txt
|
||||
# google-api-python-client
|
||||
google-cloud-core==2.4.1
|
||||
# via
|
||||
# -r requirements/edx/base.txt
|
||||
# google-cloud-firestore
|
||||
# google-cloud-storage
|
||||
google-cloud-firestore==2.17.2
|
||||
# via
|
||||
# -r requirements/edx/base.txt
|
||||
# firebase-admin
|
||||
google-cloud-storage==2.18.2
|
||||
# via
|
||||
# -r requirements/edx/base.txt
|
||||
# firebase-admin
|
||||
google-crc32c==1.5.0
|
||||
# via
|
||||
# -r requirements/edx/base.txt
|
||||
# google-cloud-storage
|
||||
# google-resumable-media
|
||||
google-resumable-media==2.7.2
|
||||
# via
|
||||
# -r requirements/edx/base.txt
|
||||
# google-cloud-storage
|
||||
googleapis-common-protos==1.63.2
|
||||
# via
|
||||
# -r requirements/edx/base.txt
|
||||
# google-api-core
|
||||
# grpcio-status
|
||||
grimp==3.4.1
|
||||
# via import-linter
|
||||
gunicorn==22.0.0
|
||||
grpcio==1.65.5
|
||||
# via
|
||||
# -r requirements/edx/base.txt
|
||||
# google-api-core
|
||||
# grpcio-status
|
||||
grpcio-status==1.65.5
|
||||
# via
|
||||
# -r requirements/edx/base.txt
|
||||
# google-api-core
|
||||
gunicorn==23.0.0
|
||||
# via -r requirements/edx/base.txt
|
||||
h11==0.14.0
|
||||
# via
|
||||
# httpcore
|
||||
# uvicorn
|
||||
# via uvicorn
|
||||
help-tokens==2.4.0
|
||||
# via -r requirements/edx/base.txt
|
||||
html5lib==1.1
|
||||
# via
|
||||
# -r requirements/edx/base.txt
|
||||
# ora2
|
||||
httpcore==0.16.3
|
||||
# via httpx
|
||||
httplib2==0.22.0
|
||||
# via
|
||||
# -r requirements/edx/base.txt
|
||||
# google-api-python-client
|
||||
# google-auth-httplib2
|
||||
httpretty==1.1.4
|
||||
# via -r requirements/edx/testing.in
|
||||
httptools==0.6.1
|
||||
# via uvicorn
|
||||
httpx==0.23.3
|
||||
# via
|
||||
# fastapi
|
||||
# pact-python
|
||||
icalendar==5.0.13
|
||||
# via -r requirements/edx/base.txt
|
||||
idna==3.7
|
||||
# via
|
||||
# -r requirements/edx/base.txt
|
||||
# anyio
|
||||
# email-validator
|
||||
# optimizely-sdk
|
||||
# requests
|
||||
# rfc3986
|
||||
# snowflake-connector-python
|
||||
# yarl
|
||||
import-linter==2.0
|
||||
# via -r requirements/edx/testing.in
|
||||
importlib-metadata==6.11.0
|
||||
# via
|
||||
# -c requirements/edx/../common_constraints.txt
|
||||
# -r requirements/edx/base.txt
|
||||
importlib-metadata==8.3.0
|
||||
# via -r requirements/edx/base.txt
|
||||
inflection==0.5.1
|
||||
# via
|
||||
# -r requirements/edx/base.txt
|
||||
@@ -774,7 +838,6 @@ jinja2==3.1.4
|
||||
# -r requirements/edx/coverage.txt
|
||||
# code-annotations
|
||||
# diff-cover
|
||||
# fastapi
|
||||
jmespath==1.0.1
|
||||
# via
|
||||
# -r requirements/edx/base.txt
|
||||
@@ -784,7 +847,7 @@ joblib==1.4.2
|
||||
# via
|
||||
# -r requirements/edx/base.txt
|
||||
# nltk
|
||||
jsondiff==2.1.2
|
||||
jsondiff==2.2.0
|
||||
# via
|
||||
# -r requirements/edx/base.txt
|
||||
# edx-enterprise
|
||||
@@ -811,7 +874,7 @@ jwcrypto==1.5.6
|
||||
# -r requirements/edx/base.txt
|
||||
# django-oauth-toolkit
|
||||
# pylti1p3
|
||||
kombu==5.3.7
|
||||
kombu==5.4.0
|
||||
# via
|
||||
# -r requirements/edx/base.txt
|
||||
# celery
|
||||
@@ -866,8 +929,6 @@ markdown==3.3.7
|
||||
# openedx-django-wiki
|
||||
# staff-graded-xblock
|
||||
# xblock-poll
|
||||
markdown-it-py==3.0.0
|
||||
# via rich
|
||||
markupsafe==2.1.5
|
||||
# via
|
||||
# -r requirements/edx/base.txt
|
||||
@@ -883,8 +944,6 @@ maxminddb==2.6.2
|
||||
# geoip2
|
||||
mccabe==0.7.0
|
||||
# via pylint
|
||||
mdurl==0.1.2
|
||||
# via markdown-it-py
|
||||
meilisearch==0.31.4
|
||||
# via -r requirements/edx/base.txt
|
||||
mock==5.1.0
|
||||
@@ -896,7 +955,7 @@ monotonic==1.6
|
||||
# -r requirements/edx/base.txt
|
||||
# analytics-python
|
||||
# py2neo
|
||||
more-itertools==10.3.0
|
||||
more-itertools==10.4.0
|
||||
# via
|
||||
# -r requirements/edx/base.txt
|
||||
# cssutils
|
||||
@@ -904,6 +963,10 @@ mpmath==1.3.0
|
||||
# via
|
||||
# -r requirements/edx/base.txt
|
||||
# sympy
|
||||
msgpack==1.0.8
|
||||
# via
|
||||
# -r requirements/edx/base.txt
|
||||
# cachecontrol
|
||||
multidict==6.0.5
|
||||
# via
|
||||
# -r requirements/edx/base.txt
|
||||
@@ -911,13 +974,13 @@ multidict==6.0.5
|
||||
# yarl
|
||||
mysqlclient==2.2.4
|
||||
# via -r requirements/edx/base.txt
|
||||
newrelic==9.12.0
|
||||
newrelic==9.13.0
|
||||
# via
|
||||
# -r requirements/edx/base.txt
|
||||
# edx-django-utils
|
||||
nh3==0.2.18
|
||||
# via -r requirements/edx/base.txt
|
||||
nltk==3.8.1
|
||||
nltk==3.9.1
|
||||
# via
|
||||
# -r requirements/edx/base.txt
|
||||
# chem
|
||||
@@ -970,7 +1033,7 @@ openedx-filters==1.9.0
|
||||
# -r requirements/edx/base.txt
|
||||
# lti-consumer-xblock
|
||||
# ora2
|
||||
openedx-learning==0.10.0
|
||||
openedx-learning==0.10.1
|
||||
# via
|
||||
# -c requirements/edx/../constraints.txt
|
||||
# -r requirements/edx/base.txt
|
||||
@@ -980,7 +1043,7 @@ optimizely-sdk==4.1.1
|
||||
# via
|
||||
# -c requirements/edx/../constraints.txt
|
||||
# -r requirements/edx/base.txt
|
||||
ora2==6.11.1
|
||||
ora2==6.11.2
|
||||
# via -r requirements/edx/base.txt
|
||||
packaging==24.1
|
||||
# via
|
||||
@@ -992,13 +1055,13 @@ packaging==24.1
|
||||
# pytest
|
||||
# snowflake-connector-python
|
||||
# tox
|
||||
pact-python==2.0.1
|
||||
pact-python==2.2.1
|
||||
# via -r requirements/edx/testing.in
|
||||
pansi==2020.7.3
|
||||
# via
|
||||
# -r requirements/edx/base.txt
|
||||
# py2neo
|
||||
paramiko==3.4.0
|
||||
paramiko==3.4.1
|
||||
# via
|
||||
# -r requirements/edx/base.txt
|
||||
# edx-enterprise
|
||||
@@ -1054,6 +1117,19 @@ prompt-toolkit==3.0.47
|
||||
# via
|
||||
# -r requirements/edx/base.txt
|
||||
# click-repl
|
||||
proto-plus==1.24.0
|
||||
# via
|
||||
# -r requirements/edx/base.txt
|
||||
# google-api-core
|
||||
# google-cloud-firestore
|
||||
protobuf==5.27.3
|
||||
# via
|
||||
# -r requirements/edx/base.txt
|
||||
# google-api-core
|
||||
# google-cloud-firestore
|
||||
# googleapis-common-protos
|
||||
# grpcio-status
|
||||
# proto-plus
|
||||
psutil==6.0.0
|
||||
# via
|
||||
# -r requirements/edx/base.txt
|
||||
@@ -1070,6 +1146,12 @@ pyasn1==0.6.0
|
||||
# via
|
||||
# -r requirements/edx/base.txt
|
||||
# pgpy
|
||||
# pyasn1-modules
|
||||
# rsa
|
||||
pyasn1-modules==0.4.0
|
||||
# via
|
||||
# -r requirements/edx/base.txt
|
||||
# google-auth
|
||||
pycodestyle==2.8.0
|
||||
# via
|
||||
# -c requirements/edx/../constraints.txt
|
||||
@@ -1101,13 +1183,12 @@ pygments==2.18.0
|
||||
# -r requirements/edx/coverage.txt
|
||||
# diff-cover
|
||||
# py2neo
|
||||
# rich
|
||||
pyjwkest==1.4.2
|
||||
# via
|
||||
# -r requirements/edx/base.txt
|
||||
# edx-token-utils
|
||||
# lti-consumer-xblock
|
||||
pyjwt[crypto]==2.8.0
|
||||
pyjwt[crypto]==2.9.0
|
||||
# via
|
||||
# -r requirements/edx/base.txt
|
||||
# drf-jwt
|
||||
@@ -1115,6 +1196,7 @@ pyjwt[crypto]==2.8.0
|
||||
# edx-drf-extensions
|
||||
# edx-proctoring
|
||||
# edx-rest-api-client
|
||||
# firebase-admin
|
||||
# pylti1p3
|
||||
# snowflake-connector-python
|
||||
# social-auth-core
|
||||
@@ -1159,7 +1241,7 @@ pynacl==1.5.0
|
||||
# paramiko
|
||||
pynliner==0.8.0
|
||||
# via -r requirements/edx/base.txt
|
||||
pyopenssl==24.1.0
|
||||
pyopenssl==24.2.1
|
||||
# via
|
||||
# -r requirements/edx/base.txt
|
||||
# optimizely-sdk
|
||||
@@ -1168,6 +1250,7 @@ pyparsing==3.1.2
|
||||
# via
|
||||
# -r requirements/edx/base.txt
|
||||
# chem
|
||||
# httplib2
|
||||
# openedx-calc
|
||||
pyproject-api==1.7.1
|
||||
# via tox
|
||||
@@ -1181,7 +1264,7 @@ pysrt==1.1.2
|
||||
# via
|
||||
# -r requirements/edx/base.txt
|
||||
# edxval
|
||||
pytest==8.2.2
|
||||
pytest==8.3.2
|
||||
# via
|
||||
# -r requirements/edx/testing.in
|
||||
# pylint-pytest
|
||||
@@ -1223,16 +1306,12 @@ python-dateutil==2.9.0.post0
|
||||
# olxcleaner
|
||||
# ora2
|
||||
# xblock
|
||||
python-dotenv==1.0.1
|
||||
# via uvicorn
|
||||
python-ipware==3.0.0
|
||||
# via
|
||||
# -r requirements/edx/base.txt
|
||||
# django-ipware
|
||||
python-memcached==1.62
|
||||
# via -r requirements/edx/base.txt
|
||||
python-multipart==0.0.9
|
||||
# via fastapi
|
||||
python-slugify==8.0.4
|
||||
# via
|
||||
# -r requirements/edx/base.txt
|
||||
@@ -1268,7 +1347,7 @@ pytz==2024.1
|
||||
# xblock
|
||||
pyuca==1.2
|
||||
# via -r requirements/edx/base.txt
|
||||
pyyaml==6.0.1
|
||||
pyyaml==6.0.2
|
||||
# via
|
||||
# -r requirements/edx/base.txt
|
||||
# code-annotations
|
||||
@@ -1277,13 +1356,12 @@ pyyaml==6.0.1
|
||||
# edx-django-release-util
|
||||
# edx-i18n-tools
|
||||
# jsondiff
|
||||
# uvicorn
|
||||
# xblock
|
||||
random2==1.0.2
|
||||
# via -r requirements/edx/base.txt
|
||||
recommender-xblock==2.2.0
|
||||
# via -r requirements/edx/base.txt
|
||||
redis==5.0.7
|
||||
redis==5.0.8
|
||||
# via
|
||||
# -r requirements/edx/base.txt
|
||||
# walrus
|
||||
@@ -1292,7 +1370,7 @@ referencing==0.35.1
|
||||
# -r requirements/edx/base.txt
|
||||
# jsonschema
|
||||
# jsonschema-specifications
|
||||
regex==2024.5.15
|
||||
regex==2024.7.24
|
||||
# via
|
||||
# -r requirements/edx/base.txt
|
||||
# nltk
|
||||
@@ -1301,12 +1379,15 @@ requests==2.32.3
|
||||
# -r requirements/edx/base.txt
|
||||
# algoliasearch
|
||||
# analytics-python
|
||||
# cachecontrol
|
||||
# django-oauth-toolkit
|
||||
# edx-bulk-grades
|
||||
# edx-drf-extensions
|
||||
# edx-enterprise
|
||||
# edx-rest-api-client
|
||||
# geoip2
|
||||
# google-api-core
|
||||
# google-cloud-storage
|
||||
# mailsnake
|
||||
# meilisearch
|
||||
# openai
|
||||
@@ -1325,15 +1406,15 @@ requests-oauthlib==2.0.0
|
||||
# via
|
||||
# -r requirements/edx/base.txt
|
||||
# social-auth-core
|
||||
rfc3986[idna2008]==1.5.0
|
||||
# via httpx
|
||||
rich==13.7.1
|
||||
# via typer
|
||||
rpds-py==0.19.0
|
||||
rpds-py==0.20.0
|
||||
# via
|
||||
# -r requirements/edx/base.txt
|
||||
# jsonschema
|
||||
# referencing
|
||||
rsa==4.9
|
||||
# via
|
||||
# -r requirements/edx/base.txt
|
||||
# google-auth
|
||||
rules==3.4
|
||||
# via
|
||||
# -r requirements/edx/base.txt
|
||||
@@ -1357,11 +1438,9 @@ semantic-version==2.10.0
|
||||
# via
|
||||
# -r requirements/edx/base.txt
|
||||
# edx-drf-extensions
|
||||
shapely==2.0.5
|
||||
shapely==2.0.6
|
||||
# via -r requirements/edx/base.txt
|
||||
shellingham==1.5.4
|
||||
# via typer
|
||||
simplejson==3.19.2
|
||||
simplejson==3.19.3
|
||||
# via
|
||||
# -r requirements/edx/base.txt
|
||||
# sailthru-client
|
||||
@@ -1406,16 +1485,14 @@ slumber==0.7.1
|
||||
# edx-enterprise
|
||||
# edx-rest-api-client
|
||||
sniffio==1.3.1
|
||||
# via
|
||||
# anyio
|
||||
# httpcore
|
||||
# httpx
|
||||
snowflake-connector-python==3.11.0
|
||||
# via anyio
|
||||
snowflake-connector-python==3.12.0
|
||||
# via
|
||||
# -r requirements/edx/base.txt
|
||||
# edx-enterprise
|
||||
social-auth-app-django==5.4.1
|
||||
# via
|
||||
# -c requirements/edx/../constraints.txt
|
||||
# -r requirements/edx/base.txt
|
||||
# edx-auth-backends
|
||||
social-auth-core==4.5.4
|
||||
@@ -1431,7 +1508,7 @@ sortedcontainers==2.4.0
|
||||
# via
|
||||
# -r requirements/edx/base.txt
|
||||
# snowflake-connector-python
|
||||
soupsieve==2.5
|
||||
soupsieve==2.6
|
||||
# via
|
||||
# -r requirements/edx/base.txt
|
||||
# beautifulsoup4
|
||||
@@ -1441,7 +1518,7 @@ sqlparse==0.5.1
|
||||
# django
|
||||
staff-graded-xblock==2.3.0
|
||||
# via -r requirements/edx/base.txt
|
||||
starlette==0.37.2
|
||||
starlette==0.38.2
|
||||
# via fastapi
|
||||
stevedore==5.2.0
|
||||
# via
|
||||
@@ -1455,7 +1532,7 @@ super-csv==3.2.0
|
||||
# via
|
||||
# -r requirements/edx/base.txt
|
||||
# edx-bulk-grades
|
||||
sympy==1.13.0
|
||||
sympy==1.13.2
|
||||
# via
|
||||
# -r requirements/edx/base.txt
|
||||
# openedx-calc
|
||||
@@ -1472,20 +1549,18 @@ tinycss2==1.2.1
|
||||
# via
|
||||
# -r requirements/edx/base.txt
|
||||
# bleach
|
||||
tomlkit==0.13.0
|
||||
tomlkit==0.13.2
|
||||
# via
|
||||
# -r requirements/edx/base.txt
|
||||
# pylint
|
||||
# snowflake-connector-python
|
||||
tox==4.16.0
|
||||
tox==4.18.0
|
||||
# via -r requirements/edx/testing.in
|
||||
tqdm==4.66.4
|
||||
tqdm==4.66.5
|
||||
# via
|
||||
# -r requirements/edx/base.txt
|
||||
# nltk
|
||||
# openai
|
||||
typer==0.12.3
|
||||
# via fastapi-cli
|
||||
typing-extensions==4.12.2
|
||||
# via
|
||||
# -r requirements/edx/base.txt
|
||||
@@ -1499,7 +1574,6 @@ typing-extensions==4.12.2
|
||||
# pydantic-core
|
||||
# pylti1p3
|
||||
# snowflake-connector-python
|
||||
# typer
|
||||
tzdata==2024.1
|
||||
# via
|
||||
# -r requirements/edx/base.txt
|
||||
@@ -1515,23 +1589,19 @@ uritemplate==4.1.1
|
||||
# -r requirements/edx/base.txt
|
||||
# drf-spectacular
|
||||
# drf-yasg
|
||||
# google-api-python-client
|
||||
urllib3==1.26.19
|
||||
# via
|
||||
# -c requirements/edx/../constraints.txt
|
||||
# -r requirements/edx/base.txt
|
||||
# botocore
|
||||
# elasticsearch
|
||||
# pact-python
|
||||
# py2neo
|
||||
# requests
|
||||
user-util==1.1.0
|
||||
# via -r requirements/edx/base.txt
|
||||
uvicorn[standard]==0.30.1
|
||||
# via
|
||||
# fastapi
|
||||
# pact-python
|
||||
uvloop==0.19.0
|
||||
# via uvicorn
|
||||
uvicorn==0.30.6
|
||||
# via pact-python
|
||||
vine==5.1.0
|
||||
# via
|
||||
# -r requirements/edx/base.txt
|
||||
@@ -1548,10 +1618,8 @@ walrus==0.9.4
|
||||
# via
|
||||
# -r requirements/edx/base.txt
|
||||
# edx-event-bus-redis
|
||||
watchdog==4.0.1
|
||||
watchdog==4.0.2
|
||||
# via -r requirements/edx/base.txt
|
||||
watchfiles==0.22.0
|
||||
# via uvicorn
|
||||
wcwidth==0.2.13
|
||||
# via
|
||||
# -r requirements/edx/base.txt
|
||||
@@ -1570,18 +1638,17 @@ webencodings==0.5.1
|
||||
# bleach
|
||||
# html5lib
|
||||
# tinycss2
|
||||
webob==1.8.7
|
||||
webob==1.8.8
|
||||
# via
|
||||
# -r requirements/edx/base.txt
|
||||
# xblock
|
||||
websockets==12.0
|
||||
# via uvicorn
|
||||
wrapt==1.16.0
|
||||
# via
|
||||
# -r requirements/edx/base.txt
|
||||
# astroid
|
||||
xblock[django]==4.0.1
|
||||
# via
|
||||
# -c requirements/edx/../constraints.txt
|
||||
# -r requirements/edx/base.txt
|
||||
# acid-xblock
|
||||
# crowdsourcehinter-xblock
|
||||
@@ -1617,7 +1684,8 @@ yarl==1.9.4
|
||||
# via
|
||||
# -r requirements/edx/base.txt
|
||||
# aiohttp
|
||||
zipp==3.19.2
|
||||
# pact-python
|
||||
zipp==3.20.0
|
||||
# via
|
||||
# -r requirements/edx/base.txt
|
||||
# importlib-metadata
|
||||
|
||||
@@ -18,7 +18,7 @@ pyproject-hooks==1.1.0
|
||||
# via
|
||||
# build
|
||||
# pip-tools
|
||||
wheel==0.43.0
|
||||
wheel==0.44.0
|
||||
# via pip-tools
|
||||
|
||||
# The following packages are considered to be unsafe in a requirements file:
|
||||
|
||||
@@ -4,11 +4,11 @@
|
||||
#
|
||||
# make upgrade
|
||||
#
|
||||
wheel==0.43.0
|
||||
wheel==0.44.0
|
||||
# via -r requirements/pip.in
|
||||
|
||||
# The following packages are considered to be unsafe in a requirements file:
|
||||
pip==24.1.2
|
||||
pip==24.2
|
||||
# via -r requirements/pip.in
|
||||
setuptools==70.3.0
|
||||
setuptools==73.0.0
|
||||
# via -r requirements/pip.in
|
||||
|
||||
@@ -32,7 +32,7 @@ pymongo==4.4.0
|
||||
# via
|
||||
# -r scripts/structures_pruning/requirements/base.txt
|
||||
# edx-opaque-keys
|
||||
pytest==8.2.2
|
||||
pytest==8.3.2
|
||||
# via -r scripts/structures_pruning/requirements/testing.in
|
||||
stevedore==5.2.0
|
||||
# via
|
||||
|
||||
@@ -6,21 +6,21 @@
|
||||
#
|
||||
asgiref==3.8.1
|
||||
# via django
|
||||
attrs==23.2.0
|
||||
attrs==24.2.0
|
||||
# via zeep
|
||||
backoff==2.2.1
|
||||
# via -r scripts/user_retirement/requirements/base.in
|
||||
boto3==1.34.144
|
||||
boto3==1.35.1
|
||||
# via -r scripts/user_retirement/requirements/base.in
|
||||
botocore==1.34.144
|
||||
botocore==1.35.1
|
||||
# via
|
||||
# boto3
|
||||
# s3transfer
|
||||
cachetools==5.4.0
|
||||
cachetools==5.5.0
|
||||
# via google-auth
|
||||
certifi==2024.7.4
|
||||
# via requests
|
||||
cffi==1.16.0
|
||||
cffi==1.17.0
|
||||
# via
|
||||
# cryptography
|
||||
# pynacl
|
||||
@@ -33,9 +33,9 @@ click==8.1.6
|
||||
# -c scripts/user_retirement/requirements/../../../requirements/constraints.txt
|
||||
# -r scripts/user_retirement/requirements/base.in
|
||||
# edx-django-utils
|
||||
cryptography==42.0.8
|
||||
cryptography==43.0.0
|
||||
# via pyjwt
|
||||
django==4.2.14
|
||||
django==4.2.15
|
||||
# via
|
||||
# -c scripts/user_retirement/requirements/../../../requirements/common_constraints.txt
|
||||
# -c scripts/user_retirement/requirements/../../../requirements/constraints.txt
|
||||
@@ -46,15 +46,15 @@ django-crum==0.7.9
|
||||
# via edx-django-utils
|
||||
django-waffle==4.1.0
|
||||
# via edx-django-utils
|
||||
edx-django-utils==5.14.2
|
||||
edx-django-utils==5.15.0
|
||||
# via edx-rest-api-client
|
||||
edx-rest-api-client==5.7.1
|
||||
# via -r scripts/user_retirement/requirements/base.in
|
||||
google-api-core==2.19.1
|
||||
# via google-api-python-client
|
||||
google-api-python-client==2.137.0
|
||||
google-api-python-client==2.141.0
|
||||
# via -r scripts/user_retirement/requirements/base.in
|
||||
google-auth==2.32.0
|
||||
google-auth==2.34.0
|
||||
# via
|
||||
# google-api-core
|
||||
# google-api-python-client
|
||||
@@ -81,9 +81,9 @@ lxml==4.9.4
|
||||
# via
|
||||
# -c scripts/user_retirement/requirements/../../../requirements/constraints.txt
|
||||
# zeep
|
||||
more-itertools==10.3.0
|
||||
more-itertools==10.4.0
|
||||
# via simple-salesforce
|
||||
newrelic==9.12.0
|
||||
newrelic==9.13.0
|
||||
# via edx-django-utils
|
||||
pbr==6.0.0
|
||||
# via stevedore
|
||||
@@ -91,7 +91,7 @@ platformdirs==4.2.2
|
||||
# via zeep
|
||||
proto-plus==1.24.0
|
||||
# via google-api-core
|
||||
protobuf==5.27.2
|
||||
protobuf==5.27.3
|
||||
# via
|
||||
# google-api-core
|
||||
# googleapis-common-protos
|
||||
@@ -106,7 +106,7 @@ pyasn1-modules==0.4.0
|
||||
# via google-auth
|
||||
pycparser==2.22
|
||||
# via cffi
|
||||
pyjwt[crypto]==2.8.0
|
||||
pyjwt[crypto]==2.9.0
|
||||
# via
|
||||
# edx-rest-api-client
|
||||
# simple-salesforce
|
||||
@@ -120,7 +120,7 @@ pytz==2024.1
|
||||
# via
|
||||
# jenkinsapi
|
||||
# zeep
|
||||
pyyaml==6.0.1
|
||||
pyyaml==6.0.2
|
||||
# via -r scripts/user_retirement/requirements/base.in
|
||||
requests==2.32.3
|
||||
# via
|
||||
@@ -143,7 +143,7 @@ s3transfer==0.10.2
|
||||
# via boto3
|
||||
simple-salesforce==1.12.6
|
||||
# via -r scripts/user_retirement/requirements/base.in
|
||||
simplejson==3.19.2
|
||||
simplejson==3.19.3
|
||||
# via -r scripts/user_retirement/requirements/base.in
|
||||
six==1.16.0
|
||||
# via
|
||||
|
||||
@@ -8,23 +8,23 @@ asgiref==3.8.1
|
||||
# via
|
||||
# -r scripts/user_retirement/requirements/base.txt
|
||||
# django
|
||||
attrs==23.2.0
|
||||
attrs==24.2.0
|
||||
# via
|
||||
# -r scripts/user_retirement/requirements/base.txt
|
||||
# zeep
|
||||
backoff==2.2.1
|
||||
# via -r scripts/user_retirement/requirements/base.txt
|
||||
boto3==1.34.144
|
||||
boto3==1.35.1
|
||||
# via
|
||||
# -r scripts/user_retirement/requirements/base.txt
|
||||
# moto
|
||||
botocore==1.34.144
|
||||
botocore==1.35.1
|
||||
# via
|
||||
# -r scripts/user_retirement/requirements/base.txt
|
||||
# boto3
|
||||
# moto
|
||||
# s3transfer
|
||||
cachetools==5.4.0
|
||||
cachetools==5.5.0
|
||||
# via
|
||||
# -r scripts/user_retirement/requirements/base.txt
|
||||
# google-auth
|
||||
@@ -32,7 +32,7 @@ certifi==2024.7.4
|
||||
# via
|
||||
# -r scripts/user_retirement/requirements/base.txt
|
||||
# requests
|
||||
cffi==1.16.0
|
||||
cffi==1.17.0
|
||||
# via
|
||||
# -r scripts/user_retirement/requirements/base.txt
|
||||
# cryptography
|
||||
@@ -45,14 +45,14 @@ click==8.1.6
|
||||
# via
|
||||
# -r scripts/user_retirement/requirements/base.txt
|
||||
# edx-django-utils
|
||||
cryptography==42.0.8
|
||||
cryptography==43.0.0
|
||||
# via
|
||||
# -r scripts/user_retirement/requirements/base.txt
|
||||
# moto
|
||||
# pyjwt
|
||||
ddt==1.7.2
|
||||
# via -r scripts/user_retirement/requirements/testing.in
|
||||
django==4.2.14
|
||||
django==4.2.15
|
||||
# via
|
||||
# -r scripts/user_retirement/requirements/base.txt
|
||||
# django-crum
|
||||
@@ -66,7 +66,7 @@ django-waffle==4.1.0
|
||||
# via
|
||||
# -r scripts/user_retirement/requirements/base.txt
|
||||
# edx-django-utils
|
||||
edx-django-utils==5.14.2
|
||||
edx-django-utils==5.15.0
|
||||
# via
|
||||
# -r scripts/user_retirement/requirements/base.txt
|
||||
# edx-rest-api-client
|
||||
@@ -76,9 +76,9 @@ google-api-core==2.19.1
|
||||
# via
|
||||
# -r scripts/user_retirement/requirements/base.txt
|
||||
# google-api-python-client
|
||||
google-api-python-client==2.137.0
|
||||
google-api-python-client==2.141.0
|
||||
# via -r scripts/user_retirement/requirements/base.txt
|
||||
google-auth==2.32.0
|
||||
google-auth==2.34.0
|
||||
# via
|
||||
# -r scripts/user_retirement/requirements/base.txt
|
||||
# google-api-core
|
||||
@@ -126,13 +126,13 @@ markupsafe==2.1.5
|
||||
# werkzeug
|
||||
mock==5.1.0
|
||||
# via -r scripts/user_retirement/requirements/testing.in
|
||||
more-itertools==10.3.0
|
||||
more-itertools==10.4.0
|
||||
# via
|
||||
# -r scripts/user_retirement/requirements/base.txt
|
||||
# simple-salesforce
|
||||
moto==4.2.14
|
||||
# via -r scripts/user_retirement/requirements/testing.in
|
||||
newrelic==9.12.0
|
||||
newrelic==9.13.0
|
||||
# via
|
||||
# -r scripts/user_retirement/requirements/base.txt
|
||||
# edx-django-utils
|
||||
@@ -152,7 +152,7 @@ proto-plus==1.24.0
|
||||
# via
|
||||
# -r scripts/user_retirement/requirements/base.txt
|
||||
# google-api-core
|
||||
protobuf==5.27.2
|
||||
protobuf==5.27.3
|
||||
# via
|
||||
# -r scripts/user_retirement/requirements/base.txt
|
||||
# google-api-core
|
||||
@@ -175,7 +175,7 @@ pycparser==2.22
|
||||
# via
|
||||
# -r scripts/user_retirement/requirements/base.txt
|
||||
# cffi
|
||||
pyjwt[crypto]==2.8.0
|
||||
pyjwt[crypto]==2.9.0
|
||||
# via
|
||||
# -r scripts/user_retirement/requirements/base.txt
|
||||
# edx-rest-api-client
|
||||
@@ -188,7 +188,7 @@ pyparsing==3.1.2
|
||||
# via
|
||||
# -r scripts/user_retirement/requirements/base.txt
|
||||
# httplib2
|
||||
pytest==8.2.2
|
||||
pytest==8.3.2
|
||||
# via -r scripts/user_retirement/requirements/testing.in
|
||||
python-dateutil==2.9.0.post0
|
||||
# via
|
||||
@@ -200,7 +200,7 @@ pytz==2024.1
|
||||
# -r scripts/user_retirement/requirements/base.txt
|
||||
# jenkinsapi
|
||||
# zeep
|
||||
pyyaml==6.0.1
|
||||
pyyaml==6.0.2
|
||||
# via
|
||||
# -r scripts/user_retirement/requirements/base.txt
|
||||
# responses
|
||||
@@ -242,7 +242,7 @@ s3transfer==0.10.2
|
||||
# boto3
|
||||
simple-salesforce==1.12.6
|
||||
# via -r scripts/user_retirement/requirements/base.txt
|
||||
simplejson==3.19.2
|
||||
simplejson==3.19.3
|
||||
# via -r scripts/user_retirement/requirements/base.txt
|
||||
six==1.16.0
|
||||
# via
|
||||
|
||||
@@ -21,7 +21,7 @@ from scripts.user_retirement.tests.retirement_helpers import (
|
||||
FAKE_USERNAMES,
|
||||
TEST_RETIREMENT_QUEUE_STATES,
|
||||
TEST_RETIREMENT_STATE,
|
||||
get_fake_user_retirement
|
||||
get_fake_user_retirement,
|
||||
)
|
||||
from scripts.user_retirement.utils import edx_api
|
||||
|
||||
@@ -499,46 +499,6 @@ class TestDiscoveryApi(OAuth2Mixin, unittest.TestCase):
|
||||
)
|
||||
|
||||
|
||||
class TestDemographicsApi(OAuth2Mixin, unittest.TestCase):
|
||||
"""
|
||||
Test the edX Demographics API client.
|
||||
"""
|
||||
|
||||
@responses.activate(registry=OrderedRegistry)
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
self.mock_access_token_response()
|
||||
self.lms_base_url = 'http://localhost:18000/'
|
||||
self.demographics_base_url = 'http://localhost:18360/'
|
||||
self.demographics_api = edx_api.DemographicsApi(
|
||||
self.lms_base_url,
|
||||
self.demographics_base_url,
|
||||
'the_client_id',
|
||||
'the_client_secret'
|
||||
)
|
||||
|
||||
def tearDown(self):
|
||||
super().tearDown()
|
||||
responses.reset()
|
||||
|
||||
@patch.object(edx_api.DemographicsApi, 'retire_learner')
|
||||
def test_retire_learner(self, mock_method):
|
||||
json_data = {
|
||||
'lms_user_id': get_fake_user_retirement()['user']['id']
|
||||
}
|
||||
responses.add(
|
||||
POST,
|
||||
urljoin(self.demographics_base_url, 'demographics/api/v1/retire_demographics/'),
|
||||
match=[matchers.json_params_matcher(json_data)]
|
||||
)
|
||||
self.demographics_api.retire_learner(
|
||||
learner=get_fake_user_retirement()
|
||||
)
|
||||
mock_method.assert_called_once_with(
|
||||
learner=get_fake_user_retirement()
|
||||
)
|
||||
|
||||
|
||||
class TestLicenseManagerApi(OAuth2Mixin, unittest.TestCase):
|
||||
"""
|
||||
Test the edX License Manager API client.
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
"""
|
||||
edX API classes which call edX service REST API endpoints using the edx-rest-api-client module.
|
||||
"""
|
||||
|
||||
import logging
|
||||
from urllib.parse import urljoin
|
||||
|
||||
@@ -28,6 +29,7 @@ class BaseApiClient:
|
||||
"""
|
||||
API client base class used to submit API requests to a particular web service.
|
||||
"""
|
||||
|
||||
append_slash = True
|
||||
_access_token = None
|
||||
|
||||
@@ -45,15 +47,15 @@ class BaseApiClient:
|
||||
Args:
|
||||
path (str): API endpoint path.
|
||||
"""
|
||||
path = path.strip('/')
|
||||
path = path.strip("/")
|
||||
if self.append_slash:
|
||||
path += '/'
|
||||
path += "/"
|
||||
|
||||
return urljoin(f'{self.api_base_url}/', path)
|
||||
return urljoin(f"{self.api_base_url}/", path)
|
||||
|
||||
def _request(self, method, url, log_404_as_error=True, **kwargs):
|
||||
if 'headers' not in kwargs:
|
||||
kwargs['headers'] = {'Content-type': 'application/json'}
|
||||
if "headers" not in kwargs:
|
||||
kwargs["headers"] = {"Content-type": "application/json"}
|
||||
|
||||
try:
|
||||
response = requests.request(method, url, auth=SuppliedJwtAuth(self._access_token), **kwargs)
|
||||
@@ -68,7 +70,7 @@ class BaseApiClient:
|
||||
# Immediately raise the error so that a 404 isn't logged as an API error in this case.
|
||||
raise HttpDoesNotExistException(str(exc))
|
||||
|
||||
LOG.error(f'API Error: {str(exc)} with status code: {status_code}')
|
||||
LOG.error(f"API Error: {str(exc)} with status code: {status_code}")
|
||||
|
||||
if status_code == 504:
|
||||
# Differentiate gateway errors so different backoff can be used.
|
||||
@@ -92,31 +94,31 @@ class BaseApiClient:
|
||||
Returns:
|
||||
str: JWT access token
|
||||
"""
|
||||
oauth_access_token_url = urljoin(f'{oauth_base_url}/', OAUTH_ACCESS_TOKEN_URL)
|
||||
oauth_access_token_url = urljoin(f"{oauth_base_url}/", OAUTH_ACCESS_TOKEN_URL)
|
||||
data = {
|
||||
'grant_type': 'client_credentials',
|
||||
'client_id': client_id,
|
||||
'client_secret': client_secret,
|
||||
'token_type': 'jwt',
|
||||
"grant_type": "client_credentials",
|
||||
"client_id": client_id,
|
||||
"client_secret": client_secret,
|
||||
"token_type": "jwt",
|
||||
}
|
||||
try:
|
||||
response = requests.post(
|
||||
oauth_access_token_url,
|
||||
data=data,
|
||||
headers={
|
||||
'User-Agent': 'scripts.user_retirement',
|
||||
"User-Agent": "scripts.user_retirement",
|
||||
},
|
||||
timeout=(REQUEST_CONNECT_TIMEOUT, REQUEST_READ_TIMEOUT)
|
||||
timeout=(REQUEST_CONNECT_TIMEOUT, REQUEST_READ_TIMEOUT),
|
||||
)
|
||||
response.raise_for_status()
|
||||
return response.json()['access_token']
|
||||
return response.json()["access_token"]
|
||||
except KeyError as exc:
|
||||
LOG.error(f'Failed to get token. {str(exc)} does not exist.')
|
||||
LOG.error(f"Failed to get token. {str(exc)} does not exist.")
|
||||
raise
|
||||
|
||||
except HTTPError as exc:
|
||||
LOG.error(
|
||||
f'API Error: {str(exc)} with status code: {exc.response.status_code} fetching access token: {client_id}'
|
||||
f"API Error: {str(exc)} with status code: {exc.response.status_code} fetching access token: {client_id}"
|
||||
)
|
||||
raise
|
||||
|
||||
@@ -125,7 +127,7 @@ def _backoff_handler(details):
|
||||
"""
|
||||
Simple logging handler for when timeout backoff occurs.
|
||||
"""
|
||||
LOG.info('Trying again in {wait:0.1f} seconds after {tries} tries calling {target}'.format(**details))
|
||||
LOG.info("Trying again in {wait:0.1f} seconds after {tries} tries calling {target}".format(**details))
|
||||
|
||||
|
||||
def _wait_one_minute():
|
||||
@@ -143,10 +145,7 @@ def _giveup_on_unexpected_exception(exc):
|
||||
# Treat a ConnectionError as retryable.
|
||||
isinstance(exc, ConnectionError)
|
||||
# All 5xx status codes are retryable except for 504 Gateway Timeout.
|
||||
or (
|
||||
500 <= exc.response.status_code < 600
|
||||
and exc.response.status_code != 504 # Gateway Timeout
|
||||
)
|
||||
or (500 <= exc.response.status_code < 600 and exc.response.status_code != 504) # Gateway Timeout
|
||||
# Status code 104 is unreserved, but we must have added this because we observed retryable 104 responses.
|
||||
or exc.response.status_code == 104
|
||||
)
|
||||
@@ -167,7 +166,7 @@ def _retry_lms_api():
|
||||
# Wrap the actual _backoff_handler so that we can patch the real one in unit tests. Otherwise, the func
|
||||
# will get decorated on import, embedding this handler as a python object reference, precluding our ability
|
||||
# to patch it in tests.
|
||||
on_backoff=lambda details: _backoff_handler(details) # pylint: disable=unnecessary-lambda
|
||||
on_backoff=lambda details: _backoff_handler(details), # pylint: disable=unnecessary-lambda
|
||||
)
|
||||
func_with_timeout_backoff = backoff.on_exception(
|
||||
_wait_one_minute,
|
||||
@@ -176,7 +175,7 @@ def _retry_lms_api():
|
||||
# Wrap the actual _backoff_handler so that we can patch the real one in unit tests. Otherwise, the func
|
||||
# will get decorated on import, embedding this handler as a python object reference, precluding our ability
|
||||
# to patch it in tests.
|
||||
on_backoff=lambda details: _backoff_handler(details) # pylint: disable=unnecessary-lambda
|
||||
on_backoff=lambda details: _backoff_handler(details), # pylint: disable=unnecessary-lambda
|
||||
)
|
||||
return func_with_backoff(func_with_timeout_backoff(func))
|
||||
|
||||
@@ -193,14 +192,11 @@ class LmsApi(BaseApiClient):
|
||||
"""
|
||||
Retrieves a list of learners awaiting retirement actions.
|
||||
"""
|
||||
params = {
|
||||
'cool_off_days': cool_off_days,
|
||||
'states': states_to_request
|
||||
}
|
||||
params = {"cool_off_days": cool_off_days, "states": states_to_request}
|
||||
if limit:
|
||||
params['limit'] = limit
|
||||
api_url = self.get_api_url('api/user/v1/accounts/retirement_queue')
|
||||
return self._request('GET', api_url, params=params)
|
||||
params["limit"] = limit
|
||||
api_url = self.get_api_url("api/user/v1/accounts/retirement_queue")
|
||||
return self._request("GET", api_url, params=params)
|
||||
|
||||
@_retry_lms_api()
|
||||
def get_learners_by_date_and_status(self, state_to_request, start_date, end_date):
|
||||
@@ -214,20 +210,20 @@ class LmsApi(BaseApiClient):
|
||||
:param end_date: Date or Datetime
|
||||
"""
|
||||
params = {
|
||||
'start_date': start_date.strftime('%Y-%m-%d'),
|
||||
'end_date': end_date.strftime('%Y-%m-%d'),
|
||||
'state': state_to_request
|
||||
"start_date": start_date.strftime("%Y-%m-%d"),
|
||||
"end_date": end_date.strftime("%Y-%m-%d"),
|
||||
"state": state_to_request,
|
||||
}
|
||||
api_url = self.get_api_url('api/user/v1/accounts/retirements_by_status_and_date')
|
||||
return self._request('GET', api_url, params=params)
|
||||
api_url = self.get_api_url("api/user/v1/accounts/retirements_by_status_and_date")
|
||||
return self._request("GET", api_url, params=params)
|
||||
|
||||
@_retry_lms_api()
|
||||
def get_learner_retirement_state(self, username):
|
||||
"""
|
||||
Retrieves the given learner's retirement state.
|
||||
"""
|
||||
api_url = self.get_api_url(f'api/user/v1/accounts/{username}/retirement_status')
|
||||
return self._request('GET', api_url)
|
||||
api_url = self.get_api_url(f"api/user/v1/accounts/{username}/retirement_status")
|
||||
return self._request("GET", api_url)
|
||||
|
||||
@_retry_lms_api()
|
||||
def update_learner_retirement_state(self, username, new_state_name, message, force=False):
|
||||
@@ -235,26 +231,22 @@ class LmsApi(BaseApiClient):
|
||||
Updates the given learner's retirement state to the retirement state name new_string
|
||||
with the additional string information in message (for logging purposes).
|
||||
"""
|
||||
data = {
|
||||
'username': username,
|
||||
'new_state': new_state_name,
|
||||
'response': message
|
||||
}
|
||||
data = {"username": username, "new_state": new_state_name, "response": message}
|
||||
|
||||
if force:
|
||||
data['force'] = True
|
||||
data["force"] = True
|
||||
|
||||
api_url = self.get_api_url('api/user/v1/accounts/update_retirement_status')
|
||||
return self._request('PATCH', api_url, json=data)
|
||||
api_url = self.get_api_url("api/user/v1/accounts/update_retirement_status")
|
||||
return self._request("PATCH", api_url, json=data)
|
||||
|
||||
@_retry_lms_api()
|
||||
def retirement_deactivate_logout(self, learner):
|
||||
"""
|
||||
Performs the user deactivation and forced logout step of learner retirement
|
||||
"""
|
||||
data = {'username': learner['original_username']}
|
||||
api_url = self.get_api_url('api/user/v1/accounts/deactivate_logout')
|
||||
return self._request('POST', api_url, json=data)
|
||||
data = {"username": learner["original_username"]}
|
||||
api_url = self.get_api_url("api/user/v1/accounts/deactivate_logout")
|
||||
return self._request("POST", api_url, json=data)
|
||||
|
||||
@_retry_lms_api()
|
||||
def retirement_retire_forum(self, learner):
|
||||
@@ -262,10 +254,10 @@ class LmsApi(BaseApiClient):
|
||||
Performs the forum retirement step of learner retirement
|
||||
"""
|
||||
# api/discussion/
|
||||
data = {'username': learner['original_username']}
|
||||
data = {"username": learner["original_username"]}
|
||||
try:
|
||||
api_url = self.get_api_url('api/discussion/v1/accounts/retire_forum')
|
||||
return self._request('POST', api_url, json=data)
|
||||
api_url = self.get_api_url("api/discussion/v1/accounts/retire_forum")
|
||||
return self._request("POST", api_url, json=data)
|
||||
except HttpDoesNotExistException:
|
||||
LOG.info("No information about learner retirement")
|
||||
return True
|
||||
@@ -275,18 +267,18 @@ class LmsApi(BaseApiClient):
|
||||
"""
|
||||
Performs the email list retirement step of learner retirement
|
||||
"""
|
||||
data = {'username': learner['original_username']}
|
||||
api_url = self.get_api_url('api/user/v1/accounts/retire_mailings')
|
||||
return self._request('POST', api_url, json=data)
|
||||
data = {"username": learner["original_username"]}
|
||||
api_url = self.get_api_url("api/user/v1/accounts/retire_mailings")
|
||||
return self._request("POST", api_url, json=data)
|
||||
|
||||
@_retry_lms_api()
|
||||
def retirement_unenroll(self, learner):
|
||||
"""
|
||||
Unenrolls the user from all courses
|
||||
"""
|
||||
data = {'username': learner['original_username']}
|
||||
api_url = self.get_api_url('api/enrollment/v1/unenroll')
|
||||
return self._request('POST', api_url, json=data)
|
||||
data = {"username": learner["original_username"]}
|
||||
api_url = self.get_api_url("api/enrollment/v1/unenroll")
|
||||
return self._request("POST", api_url, json=data)
|
||||
|
||||
# This endpoint additionally returns 500 when the EdxNotes backend service is unavailable.
|
||||
@_retry_lms_api()
|
||||
@@ -294,9 +286,9 @@ class LmsApi(BaseApiClient):
|
||||
"""
|
||||
Deletes all the user's notes (aka. annotations)
|
||||
"""
|
||||
data = {'username': learner['original_username']}
|
||||
api_url = self.get_api_url('api/edxnotes/v1/retire_user')
|
||||
return self._request('POST', api_url, json=data)
|
||||
data = {"username": learner["original_username"]}
|
||||
api_url = self.get_api_url("api/edxnotes/v1/retire_user")
|
||||
return self._request("POST", api_url, json=data)
|
||||
|
||||
@_retry_lms_api()
|
||||
def retirement_lms_retire_misc(self, learner):
|
||||
@@ -304,27 +296,27 @@ class LmsApi(BaseApiClient):
|
||||
Deletes, blanks, or one-way hashes personal information in LMS as
|
||||
defined in EDUCATOR-2802 and sub-tasks.
|
||||
"""
|
||||
data = {'username': learner['original_username']}
|
||||
api_url = self.get_api_url('api/user/v1/accounts/retire_misc')
|
||||
return self._request('POST', api_url, json=data)
|
||||
data = {"username": learner["original_username"]}
|
||||
api_url = self.get_api_url("api/user/v1/accounts/retire_misc")
|
||||
return self._request("POST", api_url, json=data)
|
||||
|
||||
@_retry_lms_api()
|
||||
def retirement_lms_retire(self, learner):
|
||||
"""
|
||||
Deletes, blanks, or one-way hashes all remaining personal information in LMS
|
||||
"""
|
||||
data = {'username': learner['original_username']}
|
||||
api_url = self.get_api_url('api/user/v1/accounts/retire')
|
||||
return self._request('POST', api_url, json=data)
|
||||
data = {"username": learner["original_username"]}
|
||||
api_url = self.get_api_url("api/user/v1/accounts/retire")
|
||||
return self._request("POST", api_url, json=data)
|
||||
|
||||
@_retry_lms_api()
|
||||
def retirement_partner_queue(self, learner):
|
||||
"""
|
||||
Calls LMS to add the given user to the retirement reporting queue
|
||||
"""
|
||||
data = {'username': learner['original_username']}
|
||||
api_url = self.get_api_url('api/user/v1/accounts/retirement_partner_report')
|
||||
return self._request('PUT', api_url, json=data)
|
||||
data = {"username": learner["original_username"]}
|
||||
api_url = self.get_api_url("api/user/v1/accounts/retirement_partner_report")
|
||||
return self._request("PUT", api_url, json=data)
|
||||
|
||||
@_retry_lms_api()
|
||||
def retirement_partner_report(self):
|
||||
@@ -332,16 +324,16 @@ class LmsApi(BaseApiClient):
|
||||
Retrieves the list of users to create partner reports for and set their status to
|
||||
processing
|
||||
"""
|
||||
api_url = self.get_api_url('api/user/v1/accounts/retirement_partner_report')
|
||||
return self._request('POST', api_url)
|
||||
api_url = self.get_api_url("api/user/v1/accounts/retirement_partner_report")
|
||||
return self._request("POST", api_url)
|
||||
|
||||
@_retry_lms_api()
|
||||
def retirement_partner_cleanup(self, usernames):
|
||||
"""
|
||||
Removes the given users from the partner reporting queue
|
||||
"""
|
||||
api_url = self.get_api_url('api/user/v1/accounts/retirement_partner_report_cleanup')
|
||||
return self._request('POST', api_url, json=usernames)
|
||||
api_url = self.get_api_url("api/user/v1/accounts/retirement_partner_report_cleanup")
|
||||
return self._request("POST", api_url, json=usernames)
|
||||
|
||||
@_retry_lms_api()
|
||||
def retirement_retire_proctoring_data(self, learner):
|
||||
@@ -349,7 +341,7 @@ class LmsApi(BaseApiClient):
|
||||
Deletes or hashes learner data from edx-proctoring
|
||||
"""
|
||||
api_url = self.get_api_url(f"api/edx_proctoring/v1/retire_user/{learner['user']['id']}")
|
||||
return self._request('POST', api_url)
|
||||
return self._request("POST", api_url)
|
||||
|
||||
@_retry_lms_api()
|
||||
def retirement_retire_proctoring_backend_data(self, learner):
|
||||
@@ -357,16 +349,16 @@ class LmsApi(BaseApiClient):
|
||||
Removes the given learner from 3rd party proctoring backends
|
||||
"""
|
||||
api_url = self.get_api_url(f"api/edx_proctoring/v1/retire_backend_user/{learner['user']['id']}")
|
||||
return self._request('POST', api_url)
|
||||
return self._request("POST", api_url)
|
||||
|
||||
@_retry_lms_api()
|
||||
def bulk_cleanup_retirements(self, usernames):
|
||||
"""
|
||||
Deletes the retirements for all given usernames
|
||||
"""
|
||||
data = {'usernames': usernames}
|
||||
api_url = self.get_api_url('api/user/v1/accounts/retirement_cleanup')
|
||||
return self._request('POST', api_url, json=data)
|
||||
data = {"usernames": usernames}
|
||||
api_url = self.get_api_url("api/user/v1/accounts/retirement_cleanup")
|
||||
return self._request("POST", api_url, json=data)
|
||||
|
||||
def replace_lms_usernames(self, username_mappings):
|
||||
"""
|
||||
@@ -377,8 +369,8 @@ class LmsApi(BaseApiClient):
|
||||
[{current_un_1: desired_un_1}, {current_un_2: desired_un_2}]
|
||||
"""
|
||||
data = {"username_mappings": username_mappings}
|
||||
api_url = self.get_api_url('api/user/v1/accounts/replace_usernames')
|
||||
return self._request('POST', api_url, json=data)
|
||||
api_url = self.get_api_url("api/user/v1/accounts/replace_usernames")
|
||||
return self._request("POST", api_url, json=data)
|
||||
|
||||
def replace_forums_usernames(self, username_mappings):
|
||||
"""
|
||||
@@ -389,8 +381,8 @@ class LmsApi(BaseApiClient):
|
||||
[{current_un_1: new_un_1}, {current_un_2: new_un_2}]
|
||||
"""
|
||||
data = {"username_mappings": username_mappings}
|
||||
api_url = self.get_api_url('api/discussion/v1/accounts/replace_usernames')
|
||||
return self._request('POST', api_url, json=data)
|
||||
api_url = self.get_api_url("api/discussion/v1/accounts/replace_usernames")
|
||||
return self._request("POST", api_url, json=data)
|
||||
|
||||
|
||||
class EcommerceApi(BaseApiClient):
|
||||
@@ -403,9 +395,9 @@ class EcommerceApi(BaseApiClient):
|
||||
"""
|
||||
Performs the learner retirement step for Ecommerce
|
||||
"""
|
||||
data = {'username': learner['original_username']}
|
||||
api_url = self.get_api_url('api/v2/user/retire')
|
||||
return self._request('POST', api_url, json=data)
|
||||
data = {"username": learner["original_username"]}
|
||||
api_url = self.get_api_url("api/v2/user/retire")
|
||||
return self._request("POST", api_url, json=data)
|
||||
|
||||
@_retry_lms_api()
|
||||
def get_tracking_key(self, learner):
|
||||
@@ -414,7 +406,7 @@ class EcommerceApi(BaseApiClient):
|
||||
ecommerce doesn't have access to the LMS user id.
|
||||
"""
|
||||
api_url = self.get_api_url(f"api/v2/retirement/tracking_id/{learner['original_username']}")
|
||||
return self._request('GET', api_url)['ecommerce_tracking_id']
|
||||
return self._request("GET", api_url)["ecommerce_tracking_id"]
|
||||
|
||||
def replace_usernames(self, username_mappings):
|
||||
"""
|
||||
@@ -425,8 +417,8 @@ class EcommerceApi(BaseApiClient):
|
||||
[{current_un_1: new_un_1}, {current_un_2: new_un_2}]
|
||||
"""
|
||||
data = {"username_mappings": username_mappings}
|
||||
api_url = self.get_api_url('api/v2/user_management/replace_usernames')
|
||||
return self._request('POST', api_url, json=data)
|
||||
api_url = self.get_api_url("api/v2/user_management/replace_usernames")
|
||||
return self._request("POST", api_url, json=data)
|
||||
|
||||
|
||||
class CredentialsApi(BaseApiClient):
|
||||
@@ -439,9 +431,9 @@ class CredentialsApi(BaseApiClient):
|
||||
"""
|
||||
Performs the learner retirement step for Credentials
|
||||
"""
|
||||
data = {'username': learner['original_username']}
|
||||
api_url = self.get_api_url('user/retire')
|
||||
return self._request('POST', api_url, json=data)
|
||||
data = {"username": learner["original_username"]}
|
||||
api_url = self.get_api_url("user/retire")
|
||||
return self._request("POST", api_url, json=data)
|
||||
|
||||
def replace_usernames(self, username_mappings):
|
||||
"""
|
||||
@@ -452,8 +444,8 @@ class CredentialsApi(BaseApiClient):
|
||||
[{current_un_1: new_un_1}, {current_un_2: new_un_2}]
|
||||
"""
|
||||
data = {"username_mappings": username_mappings}
|
||||
api_url = self.get_api_url('api/v2/replace_usernames')
|
||||
return self._request('POST', api_url, json=data)
|
||||
api_url = self.get_api_url("api/v2/replace_usernames")
|
||||
return self._request("POST", api_url, json=data)
|
||||
|
||||
|
||||
class DiscoveryApi(BaseApiClient):
|
||||
@@ -470,30 +462,8 @@ class DiscoveryApi(BaseApiClient):
|
||||
[{current_un_1: new_un_1}, {current_un_2: new_un_2}]
|
||||
"""
|
||||
data = {"username_mappings": username_mappings}
|
||||
api_url = self.get_api_url('api/v1/replace_usernames')
|
||||
return self._request('POST', api_url, json=data)
|
||||
|
||||
|
||||
class DemographicsApi(BaseApiClient):
|
||||
"""
|
||||
Demographics API client.
|
||||
"""
|
||||
|
||||
@_retry_lms_api()
|
||||
def retire_learner(self, learner):
|
||||
"""
|
||||
Performs the learner retirement step for Demographics. Passes the learner's LMS User Id instead of username.
|
||||
"""
|
||||
data = {'lms_user_id': learner['user']['id']}
|
||||
# If the user we are retiring has no data in the Demographics DB the request will return a 404. We
|
||||
# catch the HTTPError and return True in order to prevent this error getting raised and
|
||||
# incorrectly causing the learner to enter an ERROR state during retirement.
|
||||
try:
|
||||
api_url = self.get_api_url('demographics/api/v1/retire_demographics')
|
||||
return self._request('POST', api_url, log_404_as_error=False, json=data)
|
||||
except HttpDoesNotExistException:
|
||||
LOG.info("No demographics data found for user")
|
||||
return True
|
||||
api_url = self.get_api_url("api/v1/replace_usernames")
|
||||
return self._request("POST", api_url, json=data)
|
||||
|
||||
|
||||
class LicenseManagerApi(BaseApiClient):
|
||||
@@ -508,15 +478,15 @@ class LicenseManagerApi(BaseApiClient):
|
||||
username.
|
||||
"""
|
||||
data = {
|
||||
'lms_user_id': learner['user']['id'],
|
||||
'original_username': learner['original_username'],
|
||||
"lms_user_id": learner["user"]["id"],
|
||||
"original_username": learner["original_username"],
|
||||
}
|
||||
# If the user we are retiring has no data in the License Manager DB the request will return a 404. We
|
||||
# catch the HTTPError and return True in order to prevent this error getting raised and
|
||||
# incorrectly causing the learner to enter an ERROR state during retirement.
|
||||
try:
|
||||
api_url = self.get_api_url('api/v1/retire_user')
|
||||
return self._request('POST', api_url, log_404_as_error=False, json=data)
|
||||
api_url = self.get_api_url("api/v1/retire_user")
|
||||
return self._request("POST", api_url, log_404_as_error=False, json=data)
|
||||
except HttpDoesNotExistException:
|
||||
LOG.info("No license manager data found for user")
|
||||
return True
|
||||
|
||||
@@ -1,17 +1,5 @@
|
||||
module.exports = {
|
||||
entry: {
|
||||
AboutBlockDisplay: [
|
||||
'./xmodule/js/src/xmodule.js',
|
||||
'./xmodule/js/src/html/display.js',
|
||||
'./xmodule/js/src/javascript_loader.js',
|
||||
'./xmodule/js/src/collapsible.js',
|
||||
'./xmodule/js/src/html/imageModal.js',
|
||||
'./xmodule/js/common_static/js/vendor/draggabilly.js'
|
||||
],
|
||||
AboutBlockEditor: [
|
||||
'./xmodule/js/src/xmodule.js',
|
||||
'./xmodule/js/src/html/edit.js'
|
||||
],
|
||||
AnnotatableBlockDisplay: [
|
||||
'./xmodule/js/src/xmodule.js',
|
||||
'./xmodule/js/src/html/display.js',
|
||||
@@ -33,18 +21,6 @@ module.exports = {
|
||||
'./xmodule/js/src/xmodule.js',
|
||||
'./xmodule/js/src/sequence/edit.js'
|
||||
],
|
||||
CourseInfoBlockDisplay: [
|
||||
'./xmodule/js/src/xmodule.js',
|
||||
'./xmodule/js/src/html/display.js',
|
||||
'./xmodule/js/src/javascript_loader.js',
|
||||
'./xmodule/js/src/collapsible.js',
|
||||
'./xmodule/js/src/html/imageModal.js',
|
||||
'./xmodule/js/common_static/js/vendor/draggabilly.js'
|
||||
],
|
||||
CourseInfoBlockEditor: [
|
||||
'./xmodule/js/src/xmodule.js',
|
||||
'./xmodule/js/src/html/edit.js'
|
||||
],
|
||||
CustomTagBlockDisplay: './xmodule/js/src/xmodule.js',
|
||||
CustomTagBlockEditor: [
|
||||
'./xmodule/js/src/xmodule.js',
|
||||
@@ -104,18 +80,6 @@ module.exports = {
|
||||
'./xmodule/js/src/xmodule.js',
|
||||
'./xmodule/js/src/sequence/edit.js'
|
||||
],
|
||||
StaticTabBlockDisplay: [
|
||||
'./xmodule/js/src/xmodule.js',
|
||||
'./xmodule/js/src/html/display.js',
|
||||
'./xmodule/js/src/javascript_loader.js',
|
||||
'./xmodule/js/src/collapsible.js',
|
||||
'./xmodule/js/src/html/imageModal.js',
|
||||
'./xmodule/js/common_static/js/vendor/draggabilly.js'
|
||||
],
|
||||
StaticTabBlockEditor: [
|
||||
'./xmodule/js/src/xmodule.js',
|
||||
'./xmodule/js/src/html/edit.js'
|
||||
],
|
||||
VideoBlockDisplay: [
|
||||
'./xmodule/js/src/xmodule.js',
|
||||
'./xmodule/js/src/video/10_main.js'
|
||||
|
||||
@@ -30,8 +30,11 @@ def connect_to_mongodb(
|
||||
handles AutoReconnect errors by retrying read operations, since these exceptions
|
||||
typically indicate a temporary step-down condition for MongoDB.
|
||||
"""
|
||||
# If the MongoDB server uses a separate authentication database that should be specified here
|
||||
auth_source = kwargs.get('authsource', '') or None
|
||||
# If the MongoDB server uses a separate authentication database that should be specified here.
|
||||
# Convert the lowercased authsource parameter to the camel-cased authSource expected by MongoClient.
|
||||
auth_source = db
|
||||
if auth_source_key := {'authSource', 'authsource'}.intersection(set(kwargs.keys())):
|
||||
auth_source = kwargs.pop(auth_source_key.pop()) or db
|
||||
|
||||
# sanitize a kwarg which may be present and is no longer expected
|
||||
# AED 2020-03-02 TODO: Remove this when 'auth_source' will no longer exist in kwargs
|
||||
@@ -63,7 +66,7 @@ def connect_to_mongodb(
|
||||
}
|
||||
|
||||
if user is not None and password is not None and not db.startswith('test_'):
|
||||
connection_params.update({'username': user, 'password': password, 'authSource': db})
|
||||
connection_params.update({'username': user, 'password': password, 'authSource': auth_source})
|
||||
|
||||
mongo_conn = pymongo.MongoClient(**connection_params)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user