Merge branch 'master' into dkaplan1/APER-1322_certs-with-invalidation-records-arent-in-the-unavailable-status

This commit is contained in:
Deborah Kaplan
2024-01-29 11:52:34 -05:00
committed by GitHub
25 changed files with 1190 additions and 324 deletions

View File

@@ -191,7 +191,7 @@ define([
* @return {JSON} the data of the previous export
*/
storedExport: function(contentHomeUrl) {
var storedData = JSON.parse($.cookie(COOKIE_NAME));
var storedData = JSON.parse($.cookie(COOKIE_NAME) || null);
if (storedData) {
successUnixDate = storedData.date;
}

View File

@@ -23,6 +23,7 @@ from common.djangoapps.student.models import (
)
from common.djangoapps.student.models_api import confirm_name_change
from common.djangoapps.student.signals import USER_EMAIL_CHANGED
from openedx.core.djangoapps.safe_sessions.middleware import EmailChangeMiddleware
from openedx.features.name_affirmation_api.utils import is_name_affirmation_installed
logger = logging.getLogger(__name__)
@@ -105,8 +106,12 @@ if is_name_affirmation_installed():
@receiver(USER_EMAIL_CHANGED)
def _listen_for_user_email_changed(sender, user, **kwargs):
""" If user has changed their email, update that in email Braze. """
def _listen_for_user_email_changed(sender, user, request, **kwargs):
""" If user has changed their email, update that in session and Braze profile. """
# Store the user's email for session consistency (used by EmailChangeMiddleware)
EmailChangeMiddleware.register_email_change(request, user.email)
email = user.email
user_id = user.id
attributes = [{'email': email, 'external_id': user_id}]

View File

@@ -9,7 +9,7 @@ from common.djangoapps.student.models import CourseEnrollmentCelebration, Pendin
from common.djangoapps.student.signals.signals import USER_EMAIL_CHANGED
from common.djangoapps.student.tests.factories import CourseEnrollmentFactory, UserFactory, UserProfileFactory
from lms.djangoapps.courseware.toggles import COURSEWARE_MICROFRONTEND_PROGRESS_MILESTONES
from openedx.core.djangolib.testing.utils import skip_unless_lms
from openedx.core.djangolib.testing.utils import skip_unless_lms, get_mock_request
from openedx.features.name_affirmation_api.utils import is_name_affirmation_installed
from xmodule.modulestore.tests.django_utils import SharedModuleStoreTestCase # lint-amnesty, pylint: disable=wrong-import-order
@@ -75,10 +75,18 @@ class ReceiversTest(SharedModuleStoreTestCase):
@patch('common.djangoapps.student.signals.receivers.get_braze_client')
def test_listen_for_user_email_changed(self, mock_get_braze_client):
"""
Ensure that USER_EMAIL_CHANGED signal triggers correct calls to get_braze_client.
Ensure that USER_EMAIL_CHANGED signal triggers correct calls to
get_braze_client and update email in session.
"""
user = UserFactory(email='email@test.com', username='jdoe')
request = get_mock_request(user=user)
request.session = self.client.session
USER_EMAIL_CHANGED.send(sender=None, user=user)
# simulating email change
user.email = 'new_email@test.com'
user.save()
USER_EMAIL_CHANGED.send(sender=None, user=user, request=request)
assert mock_get_braze_client.called
assert request.session.get('email', None) == user.email

View File

@@ -910,7 +910,7 @@ def confirm_email_change(request, key):
response = render_to_response("email_change_successful.html", address_context)
USER_EMAIL_CHANGED.send(sender=None, user=user)
USER_EMAIL_CHANGED.send(sender=None, user=user, request=request)
return response

View File

@@ -309,7 +309,7 @@ class CertificatesListRestApiTest(AuthAndScopesTestMixin, SharedModuleStoreTestC
def test_query_counts(self):
# Test student with no certificates
student_no_cert = UserFactory.create(password=self.user_password)
with self.assertNumQueries(17, table_ignorelist=WAFFLE_TABLES):
with self.assertNumQueries(21, table_ignorelist=WAFFLE_TABLES):
resp = self.get_response(
AuthType.jwt,
requesting_user=self.global_staff,
@@ -319,7 +319,7 @@ class CertificatesListRestApiTest(AuthAndScopesTestMixin, SharedModuleStoreTestC
assert len(resp.data) == 0
# Test student with 1 certificate
with self.assertNumQueries(12, table_ignorelist=WAFFLE_TABLES):
with self.assertNumQueries(13, table_ignorelist=WAFFLE_TABLES):
resp = self.get_response(
AuthType.jwt,
requesting_user=self.global_staff,
@@ -359,7 +359,7 @@ class CertificatesListRestApiTest(AuthAndScopesTestMixin, SharedModuleStoreTestC
download_url='www.google.com',
grade="0.88",
)
with self.assertNumQueries(12, table_ignorelist=WAFFLE_TABLES):
with self.assertNumQueries(13, table_ignorelist=WAFFLE_TABLES):
resp = self.get_response(
AuthType.jwt,
requesting_user=self.global_staff,

View File

@@ -434,7 +434,7 @@ class CourseListSearchViewTest(CourseApiTestViewMixin, ModuleStoreTestCase, Sear
self.setup_user(self.audit_user)
# These query counts were found empirically
query_counts = [50, 46, 46, 46, 46, 46, 46, 46, 46, 46, 16]
query_counts = [53, 46, 46, 46, 46, 46, 46, 46, 46, 46, 16]
ordered_course_ids = sorted([str(cid) for cid in (course_ids + [c.id for c in self.courses])])
self.clear_caches()

View File

@@ -86,6 +86,7 @@ class CourseHomeMetadataTests(BaseCourseHomeTests):
assert self.client.get(self.url).data['username'] == self.user.username
def test_get_unknown_course(self):
self.client.logout()
url = reverse('course-home:course-metadata', args=['course-v1:unknown+course+2T2020'])
# Django TestCase wraps every test in a transaction, so we must specifically wrap this when we expect an error
with transaction.atomic():

View File

@@ -1,8 +1,6 @@
"""
Discussion notifications sender util.
"""
import logging
from django.conf import settings
from lms.djangoapps.discussion.django_comment_client.permissions import get_team
from openedx_events.learning.data import UserNotificationData, CourseNotificationData
@@ -22,9 +20,6 @@ from openedx.core.djangoapps.django_comment_common.models import (
)
log = logging.getLogger(__name__)
class DiscussionNotificationSender:
"""
Class to send notifications to users who are subscribed to the thread.
@@ -262,8 +257,6 @@ class DiscussionNotificationSender:
'username': self.creator.username,
'post_title': self.thread.title
}
log.info(f"Temp: Audience filter for course-wide notification is {audience_filters}")
self._send_course_wide_notification(notification_type, audience_filters, context)

View File

@@ -2238,6 +2238,9 @@ MIDDLEWARE = [
#'django.contrib.auth.middleware.AuthenticationMiddleware',
'openedx.core.djangoapps.cache_toolbox.middleware.CacheBackedAuthenticationMiddleware',
# Middleware to flush user's session in other browsers when their email is changed.
'openedx.core.djangoapps.safe_sessions.middleware.EmailChangeMiddleware',
'common.djangoapps.student.middleware.UserStandingMiddleware',
'openedx.core.djangoapps.contentserver.middleware.StaticContentServer',
@@ -5041,6 +5044,20 @@ HIBP_LOGIN_BLOCK_PASSWORD_FREQUENCY_THRESHOLD = 5
# .. toggle_tickets: https://openedx.atlassian.net/browse/VAN-838
ENABLE_DYNAMIC_REGISTRATION_FIELDS = False
############## Settings for EmailChangeMiddleware ###############
# .. toggle_name: ENFORCE_SESSION_EMAIL_MATCH
# .. toggle_implementation: DjangoSetting
# .. toggle_default: False
# .. toggle_description: When enabled, this setting invalidates sessions in other browsers
# upon email change, while preserving the session validity in the browser where the
# email change occurs. This toggle is just being used for rollout.
# .. toggle_use_cases: temporary
# .. toggle_creation_date: 2023-12-07
# .. toggle_target_removal_date: 2024-04-01
# .. toggle_tickets: https://2u-internal.atlassian.net/browse/VAN-1797
ENFORCE_SESSION_EMAIL_MATCH = False
LEARNER_HOME_MFE_REDIRECT_PERCENTAGE = 0
############### Settings for the ace_common plugin #################

View File

@@ -1,7 +1,6 @@
"""
Audience based filters for notifications
"""
import logging
from abc import abstractmethod
@@ -22,9 +21,6 @@ from openedx.core.djangoapps.django_comment_common.models import (
)
log = logging.getLogger(__name__)
class NotificationAudienceFilterBase:
"""
Base class for notification audience filters
@@ -84,12 +80,10 @@ class CourseRoleAudienceFilter(NotificationAudienceFilterBase):
if 'staff' in course_roles:
staff_users = CourseStaffRole(course_key).users_with_role().values_list('id', flat=True)
log.info(f'Temp: Course wide notification, staff users calculated are {staff_users}')
user_ids.extend(staff_users)
if 'instructor' in course_roles:
instructor_users = CourseInstructorRole(course_key).users_with_role().values_list('id', flat=True)
log.info(f'Temp: Course wide notification, instructor users calculated are {instructor_users}')
user_ids.extend(instructor_users)
return user_ids

View File

@@ -96,13 +96,10 @@ def calculate_course_wide_notification_audience(course_key, audience_filters):
if filter_class:
filter_instance = filter_class(course_key)
filtered_users = filter_instance.filter(filter_values)
log.info(f'Temp: Course-wide notification filtered users are '
f'{filtered_users} for filter type {filter_type}')
audience_user_ids.extend(filtered_users)
else:
raise ValueError(f"Invalid audience filter type: {filter_type}")
log.info(f'Temp: Course-wide notification after audience filter is applied, users: {list(set(audience_user_ids))}')
return list(set(audience_user_ids))
@@ -131,5 +128,4 @@ def generate_course_notifications(signal, sender, course_notification_data, meta
'content_url': course_notification_data.get('content_url'),
}
log.info(f"Temp: Course-wide notification, user_ids to sent notifications to {notification_data.get('user_ids')}")
send_notifications.delay(**notification_data)

View File

@@ -95,7 +95,7 @@ from edx_django_utils.logging import encrypt_for_log
from edx_django_utils.monitoring import set_custom_attribute
from edx_toggles.toggles import SettingToggle
from openedx.core.djangoapps.user_authn.cookies import delete_logged_in_cookies
from openedx.core.djangoapps.user_authn.cookies import delete_logged_in_cookies, set_logged_in_cookies
from openedx.core.lib.mobile_utils import is_request_from_mobile_app
# .. toggle_name: LOG_REQUEST_USER_CHANGES
@@ -768,6 +768,92 @@ class SafeSessionMiddleware(SessionMiddleware, MiddlewareMixin):
return encrypt_for_log(str(request.headers), getattr(settings, 'SAFE_SESSIONS_DEBUG_PUBLIC_KEY', None))
class EmailChangeMiddleware(MiddlewareMixin):
"""
Middleware responsible for performing the following
jobs on detecting an email change
1) It will update the session's email and update the JWT cookie
to match the new email.
2) It will invalidate any future session on other browsers where
the user's email does not match its session email.
This middleware ensures that the sessions in other browsers
are invalidated when a user changes their email in one browser.
The active session in which the email change is made will remain valid.
The user's email is stored in their session and JWT cookies during login
and gets updated when the user changes their email.
This middleware checks for any mismatch between the stored email
and the current user's email in each request, and if found,
it invalidates/flushes the session and mark cookies for deletion in request
which are then deleted in the process_response of SafeSessionMiddleware.
"""
def process_request(self, request):
"""
Invalidate the user session if there's a mismatch
between the email in the user's session and request.user.email.
"""
if request.user.is_authenticated:
user_session_email = request.session.get('email', None)
are_emails_mismatched = user_session_email is not None and request.user.email != user_session_email
EmailChangeMiddleware._set_session_email_match_custom_attributes(are_emails_mismatched)
if settings.ENFORCE_SESSION_EMAIL_MATCH and are_emails_mismatched:
# Flush the session and mark cookies for deletion.
log.info(
f'EmailChangeMiddleware invalidating session for user: {request.user.id} due to email mismatch.'
)
request.session.flush()
request.user = AnonymousUser()
_mark_cookie_for_deletion(request)
def process_response(self, request, response):
"""
1. Update the logged-in cookies if the email change was requested
2. Store user's email in session if not already
"""
if request.user.is_authenticated:
if request.session.get('email', None) is None:
# .. custom_attribute_name: session_with_no_email_found
# .. custom_attribute_description: Indicates that user's email was not
# yet stored in the user's session.
set_custom_attribute('session_with_no_email_found', True)
request.session['email'] = request.user.email
if request_cache.get_cached_response('email_change_requested').is_found:
# Update the JWT cookies with new user email
response = set_logged_in_cookies(request, response, request.user)
return response
@staticmethod
def register_email_change(request, email):
"""
Stores the fact that an email change happened.
1. Sets the email in session for later comparison.
2. Sets a request level variable to mark that the user email change was requested.
"""
request.session['email'] = email
request_cache.set('email_change_requested', True)
@staticmethod
def _set_session_email_match_custom_attributes(are_emails_mismatched):
"""
Sets custom attributes of session_email_match
"""
# .. custom_attribute_name: session_email_match
# .. custom_attribute_description: Indicates whether there is a match between the
# email in the user's session and the current user's email in the request.
set_custom_attribute('session_email_mismatch', are_emails_mismatched)
# .. custom_attribute_name: is_enforce_session_email_match_enabled
# .. custom_attribute_description: Indicates whether session email match was enforced.
# When enforced/enabled, it invalidates sessions in other browsers upon email change,
# while preserving the session validity in the browser where the email change occurs.
set_custom_attribute('is_enforce_session_email_match_enabled', settings.ENFORCE_SESSION_EMAIL_MATCH)
def obscure_token(value: Union[str, None]) -> Union[str, None]:
"""
Return a short string that can be used to detect other occurrences

View File

@@ -1,22 +1,29 @@
"""
Unit tests for SafeSessionMiddleware
"""
import uuid
from unittest.mock import call, patch, MagicMock
import ddt
from crum import set_current_request
from django.conf import settings
from django.contrib.auth import SESSION_KEY
from django.contrib.auth.models import AnonymousUser
from django.contrib.auth.models import AnonymousUser, User # lint-amnesty, pylint: disable=imported-auth-user
from django.http import HttpResponse, HttpResponseRedirect, SimpleCookie
from django.test import TestCase
from django.test.utils import override_settings
from django.urls import reverse
from edx_django_utils.cache import RequestCache
from edx_rest_framework_extensions.auth.jwt import cookies as jwt_cookies
from openedx.core.djangolib.testing.utils import get_mock_request, CacheIsolationTestCase
from common.djangoapps.student.models import PendingEmailChange
from openedx.core.djangolib.testing.utils import get_mock_request, CacheIsolationTestCase, skip_unless_lms
from openedx.core.djangoapps.user_authn.tests.utils import setup_login_oauth_client
from openedx.core.djangoapps.user_authn.cookies import ALL_LOGGED_IN_COOKIE_NAMES
from common.djangoapps.student.tests.factories import UserFactory
from ..middleware import (
EmailChangeMiddleware,
SafeCookieData,
SafeSessionMiddleware,
mark_user_change_as_expected,
@@ -615,3 +622,748 @@ class TestTrackRequestUserChanges(TestCase):
request.user = object()
assert len(request.debug_user_changes) == 2
assert "Changing request user but user has no id." in request.debug_user_changes[1]
@skip_unless_lms
class TestEmailChangeMiddleware(TestSafeSessionsLogMixin, TestCase):
"""
Test class for EmailChangeMiddleware
"""
def setUp(self):
super().setUp()
self.EMAIL = 'test@example.com'
self.PASSWORD = 'Password1234'
self.user = UserFactory.create(email=self.EMAIL, password=self.PASSWORD)
self.addCleanup(set_current_request, None)
self.request = get_mock_request(self.user)
self.request.session = {}
self.client.response = HttpResponse()
self.client.response.cookies = SimpleCookie()
self.addCleanup(RequestCache.clear_all_namespaces)
self.login_url = reverse("user_api_login_session", kwargs={'api_version': 'v2'})
self.register_url = reverse("user_api_registration_v2")
self.dashboard_url = reverse('dashboard')
@override_settings(ENFORCE_SESSION_EMAIL_MATCH=False)
@patch('openedx.core.djangoapps.safe_sessions.middleware._mark_cookie_for_deletion')
def test_process_request_user_not_authenticated_with_toggle_disabled(self, mock_mark_cookie_for_deletion):
"""
Calls EmailChangeMiddleware.process_request when no user is authenticated
and ENFORCE_SESSION_EMAIL_MATCH toggle is disabled.
Verifies that session and cookies are not affected.
"""
# Unauthenticated User
self.request.user = AnonymousUser()
# Call process_request without authenticating a user
EmailChangeMiddleware(get_response=lambda request: None).process_request(self.request)
# Assert that session and cookies are not affected
# Assert that _mark_cookie_for_deletion not called
mock_mark_cookie_for_deletion.assert_not_called()
@override_settings(ENFORCE_SESSION_EMAIL_MATCH=True)
@patch('openedx.core.djangoapps.safe_sessions.middleware._mark_cookie_for_deletion')
def test_process_request_user_not_authenticated_with_toggle_enabled(self, mock_mark_cookie_for_deletion):
"""
Calls EmailChangeMiddleware.process_request when no user is authenticated
and ENFORCE_SESSION_EMAIL_MATCH toggle is enabled.
Verifies that session and cookies are not affected.
"""
# Unauthenticated User
self.request.user = AnonymousUser()
# Call process_request without authenticating a user
EmailChangeMiddleware(get_response=lambda request: None).process_request(self.request)
# Assert that session and cookies are not affected
# Assert that _mark_cookie_for_deletion not called
mock_mark_cookie_for_deletion.assert_not_called()
@override_settings(ENFORCE_SESSION_EMAIL_MATCH=True)
@patch('openedx.core.djangoapps.safe_sessions.middleware._mark_cookie_for_deletion')
@patch("openedx.core.djangoapps.safe_sessions.middleware.set_custom_attribute")
def test_process_request_emails_match_with_toggle_enabled(
self, mock_set_custom_attribute, mock_mark_cookie_for_deletion
):
"""
Calls EmailChangeMiddleware.process_request when user is authenticated,
ENFORCE_SESSION_EMAIL_MATCH is enabled and user session and request email also match.
Verifies that session and cookies are not affected.
"""
# Log in the user
self.client.login(email=self.user.email, password=self.PASSWORD)
self.request.session = self.client.session
self.client.response.set_cookie(settings.SESSION_COOKIE_NAME, 'authenticated') # Add some logged-in cookie
# Registering email change (store user's email in session for later comparison by
# process_request function of middleware)
EmailChangeMiddleware.register_email_change(request=self.request, email=self.user.email)
# Ensure email is set in the session
self.assertEqual(self.request.session.get('email'), self.user.email)
# Ensure session cookie exist
self.assertEqual(len(self.client.response.cookies), 1)
# No email change occurred in any browser
# Call process_request
EmailChangeMiddleware(get_response=lambda request: None).process_request(self.request)
# Verify that session_email_mismatch and is_enforce_session_email_match_enabled
# custom attributes are set
mock_set_custom_attribute.assert_has_calls([call('session_email_mismatch', False)])
mock_set_custom_attribute.assert_has_calls([call('is_enforce_session_email_match_enabled', True)])
# Assert that the session and cookies are not affected
self.assertEqual(self.request.session.get('email'), self.user.email)
self.assertEqual(len(self.client.response.cookies), 1)
self.assertEqual(self.client.response.cookies[settings.SESSION_COOKIE_NAME].value, 'authenticated')
# Assert that _mark_cookie_for_deletion not called
mock_mark_cookie_for_deletion.assert_not_called()
@override_settings(ENFORCE_SESSION_EMAIL_MATCH=False)
@patch('openedx.core.djangoapps.safe_sessions.middleware._mark_cookie_for_deletion')
@patch("openedx.core.djangoapps.safe_sessions.middleware.set_custom_attribute")
def test_process_request_emails_match_with_toggle_disabled(
self, mock_set_custom_attribute, mock_mark_cookie_for_deletion
):
"""
Calls EmailChangeMiddleware.process_request when user is authenticated,
ENFORCE_SESSION_EMAIL_MATCH is disabled and user session and request email match.
Verifies that session and cookies are not affected.
"""
# Log in the user
self.client.login(email=self.user.email, password=self.PASSWORD)
self.request.session = self.client.session
self.client.response.set_cookie(settings.SESSION_COOKIE_NAME, 'authenticated') # Add some logged-in cookie
# Registering email change (store user's email in session for later comparison by
# process_request function of middleware)
EmailChangeMiddleware.register_email_change(request=self.request, email=self.user.email)
# Ensure email is set in the session
self.assertEqual(self.request.session.get('email'), self.user.email)
# Ensure session cookie exist
self.assertEqual(len(self.client.response.cookies), 1)
# No email change occurred in any browser
# Call process_request
EmailChangeMiddleware(get_response=lambda request: None).process_request(self.request)
# Verify that session_email_mismatch and is_enforce_session_email_match_enabled
# custom attributes are set
mock_set_custom_attribute.assert_has_calls([call('session_email_mismatch', False)])
mock_set_custom_attribute.assert_has_calls([call('is_enforce_session_email_match_enabled', False)])
# Assert that the session and cookies are not affected
self.assertEqual(self.request.session.get('email'), self.user.email)
self.assertEqual(len(self.client.response.cookies), 1)
self.assertEqual(self.client.response.cookies[settings.SESSION_COOKIE_NAME].value, 'authenticated')
# Assert that _mark_cookie_for_deletion not called
mock_mark_cookie_for_deletion.assert_not_called()
@override_settings(ENFORCE_SESSION_EMAIL_MATCH=True)
@patch('openedx.core.djangoapps.safe_sessions.middleware._mark_cookie_for_deletion')
@patch("openedx.core.djangoapps.safe_sessions.middleware.set_custom_attribute")
def test_process_request_emails_mismatch_with_toggle_enabled(
self, mock_set_custom_attribute, mock_mark_cookie_for_deletion
):
"""
Calls EmailChangeMiddleware.process_request when user is authenticated,
ENFORCE_SESSION_EMAIL_MATCH is enabled and user session and request
email mismatch. (Email was changed in some other browser)
Verifies that session is flushed and cookies are marked for deletion.
"""
# Log in the user
self.client.login(email=self.user.email, password=self.PASSWORD)
self.request.session = self.client.session
self.client.response.set_cookie(settings.SESSION_COOKIE_NAME, 'authenticated') # Add some logged-in cookie
# Registering email change (store user's email in session for later comparison by
# process_request function of middleware)
EmailChangeMiddleware.register_email_change(request=self.request, email=self.user.email)
# Ensure email is set in the session
self.assertEqual(self.request.session.get('email'), self.user.email)
# Ensure session cookie exist
self.assertEqual(len(self.client.response.cookies), 1)
# simulating email changed in some other browser
self.user.email = 'new_email@test.com'
self.user.save()
# Call process_request
EmailChangeMiddleware(get_response=lambda request: None).process_request(self.request)
# Verify that session_email_mismatch and is_enforce_session_email_match_enabled
# custom attributes are set
mock_set_custom_attribute.assert_has_calls([call('session_email_mismatch', True)])
mock_set_custom_attribute.assert_has_calls([call('is_enforce_session_email_match_enabled', True)])
# Assert that the session is flushed and cookies marked for deletion
mock_mark_cookie_for_deletion.assert_called()
assert self.request.session.get(SESSION_KEY) is None
assert self.request.user == AnonymousUser()
@override_settings(ENFORCE_SESSION_EMAIL_MATCH=False)
@patch('openedx.core.djangoapps.safe_sessions.middleware._mark_cookie_for_deletion')
@patch("openedx.core.djangoapps.safe_sessions.middleware.set_custom_attribute")
def test_process_request_emails_mismatch_with_toggle_disabled(
self, mock_set_custom_attribute, mock_mark_cookie_for_deletion
):
"""
Calls EmailChangeMiddleware.process_request when user is authenticated,
ENFORCE_SESSION_EMAIL_MATCH is disabled and user session and request
email mismatch. (Email was changed in some other browser)
Verifies that session and cookies are not affected.
"""
# Log in the user
self.client.login(email=self.user.email, password=self.PASSWORD)
self.request.session = self.client.session
self.client.response.set_cookie(settings.SESSION_COOKIE_NAME, 'authenticated') # Add some logged-in cookie
# Registering email change (store user's email in session for later comparison by
# process_request function of middleware)
EmailChangeMiddleware.register_email_change(request=self.request, email=self.user.email)
# Ensure email is set in the session
self.assertEqual(self.request.session.get('email'), self.user.email)
# Ensure session cookie exist
self.assertEqual(len(self.client.response.cookies), 1)
# simulating email changed in some other browser
self.user.email = 'new_email@test.com'
self.user.save()
# Call process_request
EmailChangeMiddleware(get_response=lambda request: None).process_request(self.request)
# Verify that session_email_mismatch and is_enforce_session_email_match_enabled
# custom attributes are set
mock_set_custom_attribute.assert_has_calls([call('session_email_mismatch', True)])
mock_set_custom_attribute.assert_has_calls([call('is_enforce_session_email_match_enabled', False)])
# Assert that the session and cookies are not affected
self.assertNotEqual(self.request.session.get('email'), self.user.email)
self.assertEqual(len(self.client.response.cookies), 1)
self.assertEqual(self.client.response.cookies[settings.SESSION_COOKIE_NAME].value, 'authenticated')
# Assert that _mark_cookie_for_deletion not called
mock_mark_cookie_for_deletion.assert_not_called()
@override_settings(ENFORCE_SESSION_EMAIL_MATCH=True)
@patch('openedx.core.djangoapps.safe_sessions.middleware._mark_cookie_for_deletion')
def test_process_request_no_email_change_history_with_toggle_enabled(
self, mock_mark_cookie_for_deletion
):
"""
Calls EmailChangeMiddleware.process_request when there is no previous
history of an email change and ENFORCE_SESSION_EMAIL_MATCH is enabled
Verifies that existing sessions are not affected.
Test that sessions predating this code are not affected.
"""
# Log in the user (Simulating user logged-in before this code and email was not set in session)
self.client.login(email=self.user.email, password=self.PASSWORD)
self.request.session = self.client.session
self.client.response.set_cookie(settings.SESSION_COOKIE_NAME, 'authenticated') # Add some logged-in cookie
# Ensure there is no email in the session denoting no previous history of email change
self.assertEqual(self.request.session.get('email'), None)
# Ensure session cookie exist
self.assertEqual(len(self.client.response.cookies), 1)
# simulating email changed in some other browser
self.user.email = 'new_email@test.com'
self.user.save()
# Call process_request
EmailChangeMiddleware(get_response=lambda request: None).process_request(self.request)
# Assert that the session and cookies are not affected
self.assertEqual(len(self.client.response.cookies), 1)
self.assertEqual(self.client.response.cookies[settings.SESSION_COOKIE_NAME].value, 'authenticated')
# Assert that _mark_cookie_for_deletion not called
mock_mark_cookie_for_deletion.assert_not_called()
@override_settings(ENFORCE_SESSION_EMAIL_MATCH=False)
@patch('openedx.core.djangoapps.safe_sessions.middleware._mark_cookie_for_deletion')
def test_process_request_no_email_change_history_with_toggle_disabled(
self, mock_mark_cookie_for_deletion
):
"""
Calls EmailChangeMiddleware.process_request when there is no previous
history of an email change and ENFORCE_SESSION_EMAIL_MATCH is disabled
Verifies that existing sessions are not affected.
Test that sessions predating this code are not affected.
"""
# Log in the user (Simulating user logged-in before this code and email was not set in session)
self.client.login(email=self.user.email, password=self.PASSWORD)
self.request.session = self.client.session
self.client.response.set_cookie(settings.SESSION_COOKIE_NAME, 'authenticated') # Add some logged-in cookie
# Ensure there is no email in the session denoting no previous history of email change
self.assertEqual(self.request.session.get('email'), None)
# Ensure session cookie exist
self.assertEqual(len(self.client.response.cookies), 1)
# simulating email changed in some other browser
self.user.email = 'new_email@test.com'
self.user.save()
# Call process_request
EmailChangeMiddleware(get_response=lambda request: None).process_request(self.request)
# Assert that the session and cookies are not affected
self.assertEqual(len(self.client.response.cookies), 1)
self.assertEqual(self.client.response.cookies[settings.SESSION_COOKIE_NAME].value, 'authenticated')
# Assert that _mark_cookie_for_deletion not called
mock_mark_cookie_for_deletion.assert_not_called()
@patch("openedx.core.djangoapps.safe_sessions.middleware.set_logged_in_cookies")
def test_process_response_user_not_authenticated(self, mock_set_logged_in_cookies):
"""
Calls EmailChangeMiddleware.process_response when user is not authenticated.
Verify that the logged-in cookies are not updated
"""
# return value of mock
mock_set_logged_in_cookies.return_value = self.client.response
# Unauthenticated User
self.request.user = AnonymousUser()
# Call process_response without authenticating a user
response = EmailChangeMiddleware(get_response=lambda request: None).process_response(
self.request, self.client.response
)
assert response.status_code == 200
# Assert that cookies are not updated
# Assert that mock_set_logged_in_cookies not called
mock_set_logged_in_cookies.assert_not_called()
@patch("openedx.core.djangoapps.safe_sessions.middleware.set_logged_in_cookies")
def test_process_response_user_authenticated_but_email_change_not_requested(self, mock_set_logged_in_cookies):
"""
Calls EmailChangeMiddleware.process_response when user is authenticated but email
change was not requested.
Verify that the logged-in cookies are not updated
"""
# return value of mock
mock_set_logged_in_cookies.return_value = self.client.response
# Log in the user
self.client.login(email=self.user.email, password=self.PASSWORD)
self.request.session = self.client.session
self.client.response.set_cookie(settings.SESSION_COOKIE_NAME, 'authenticated') # Add some logged-in cookie
# No call to register_email_change to indicate email was not changed
# Call process_response
response = EmailChangeMiddleware(get_response=lambda request: None).process_response(
self.request, self.client.response
)
assert response.status_code == 200
# Assert that cookies are not updated
# Assert that mock_set_logged_in_cookies not called
mock_set_logged_in_cookies.assert_not_called()
@patch("openedx.core.djangoapps.safe_sessions.middleware.set_logged_in_cookies")
def test_process_response_user_authenticated_and_email_change_requested(self, mock_set_logged_in_cookies):
"""
Calls EmailChangeMiddleware.process_response when user is authenticated and email
change was requested.
Verify that the logged-in cookies are updated
"""
# return value of mock
mock_set_logged_in_cookies.return_value = self.client.response
# Log in the user
self.client.login(email=self.user.email, password=self.PASSWORD)
self.request.session = self.client.session
self.client.response.set_cookie(settings.SESSION_COOKIE_NAME, 'authenticated') # Add some logged-in cookie
# Registering email change (setting a variable `email_change_requested` to indicate email was changed)
# so that process_response can update cookies
EmailChangeMiddleware.register_email_change(request=self.request, email=self.user.email)
# Call process_response
response = EmailChangeMiddleware(get_response=lambda request: None).process_response(
self.request, self.client.response
)
assert response.status_code == 200
# Assert that cookies are updated
# Assert that mock_set_logged_in_cookies is called
mock_set_logged_in_cookies.assert_called()
def test_process_response_no_email_in_session(self):
"""
Calls EmailChangeMiddleware.process_response when user is authenticated and
user's email was not stored in user's session.
Verify that the user's email is stored in session
"""
# Log in the user
self.client.login(email=self.user.email, password=self.PASSWORD)
self.request.session = self.client.session
self.client.response.set_cookie(settings.SESSION_COOKIE_NAME, 'authenticated') # Add some logged-in cookie
# Ensure there is no email in the session
self.assertEqual(self.request.session.get('email'), None)
# Call process_response
response = EmailChangeMiddleware(get_response=lambda request: None).process_response(
self.request, self.client.response
)
assert response.status_code == 200
# Verify that email is set in the session
self.assertEqual(self.request.session.get('email'), self.user.email)
@patch.dict("django.conf.settings.FEATURES", {"DISABLE_SET_JWT_COOKIES_FOR_TESTS": False})
def test_user_remain_authenticated_on_email_change_in_other_browser_with_toggle_disabled(self):
"""
Integration Test: test that a user remains authenticated upon email change
in other browser when ENFORCE_SESSION_EMAIL_MATCH toggle is disabled
Verify that the session and cookies are not affected in current browser and
user remains authenticated
"""
setup_login_oauth_client()
# Login the user with 'test@example.com` email and test password in current browser
response = self.client.post(self.login_url, {
"email_or_username": self.EMAIL,
"password": self.PASSWORD,
})
# Verify that the user is logged in successfully in current browser
assert response.status_code == 200
# Verify that the logged-in cookies are set in current browser
self._assert_logged_in_cookies_present(response)
# Verify that the authenticated user can access the dashboard in current browser
response = self.client.get(self.dashboard_url)
assert response.status_code == 200
# simulating email changed in some other browser (Email is changed in DB)
self.user.email = 'new_email@test.com'
self.user.save()
# Verify that the user remains authenticated in current browser and can access the dashboard
response = self.client.get(self.dashboard_url)
assert response.status_code == 200
@patch.dict("django.conf.settings.FEATURES", {"DISABLE_SET_JWT_COOKIES_FOR_TESTS": False})
@override_settings(ENFORCE_SESSION_EMAIL_MATCH=True)
def test_cookies_are_updated_with_new_email_on_email_change_with_toggle_enabled(self):
"""
Integration Test: test that cookies are updated with new email upon email change
in current browser regardless of toggle setting
Verify that the cookies are updated in current browser and
user remains authenticated
"""
setup_login_oauth_client()
# Login the user with 'test@example.com` email and test password in current browser
login_response = self.client.post(self.login_url, {
"email_or_username": self.EMAIL,
"password": self.PASSWORD,
})
# Verify that the user is logged in successfully in current browser
assert login_response.status_code == 200
# Verify that the logged-in cookies are set in current browser
self._assert_logged_in_cookies_present(login_response)
# Verify that the authenticated user can access the dashboard in current browser
response = self.client.get(self.dashboard_url)
assert response.status_code == 200
# simulating email change in current browser
activation_key = uuid.uuid4().hex
PendingEmailChange.objects.update_or_create(
user=self.user,
defaults={
'new_email': 'new_email@test.com',
'activation_key': activation_key,
}
)
email_change_response = self.client.get(
reverse('confirm_email_change', kwargs={'key': activation_key}),
)
# Verify that email change is successful
assert email_change_response.status_code == 200
self._assert_logged_in_cookies_present(email_change_response)
# Verify that jwt cookies are updated with new email and
# not equal to old logged-in cookies in current browser
self.assertNotEqual(
login_response.cookies[jwt_cookies.jwt_cookie_header_payload_name()].value,
email_change_response.cookies[jwt_cookies.jwt_cookie_header_payload_name()].value
)
self.assertNotEqual(
login_response.cookies[jwt_cookies.jwt_cookie_signature_name()].value,
email_change_response.cookies[jwt_cookies.jwt_cookie_signature_name()].value
)
@patch.dict("django.conf.settings.FEATURES", {"DISABLE_SET_JWT_COOKIES_FOR_TESTS": False})
@override_settings(ENFORCE_SESSION_EMAIL_MATCH=False)
def test_cookies_are_updated_with_new_email_on_email_change_with_toggle_disabled(self):
"""
Integration Test: test that cookies are updated with new email upon email change
in current browser regardless of toggle setting
Verify that the cookies are updated in current browser and
user remains authenticated
"""
setup_login_oauth_client()
# Login the user with 'test@example.com` email and test password in current browser
login_response = self.client.post(self.login_url, {
"email_or_username": self.EMAIL,
"password": self.PASSWORD,
})
# Verify that the user is logged in successfully in current browser
assert login_response.status_code == 200
# Verify that the logged-in cookies are set in current browser
self._assert_logged_in_cookies_present(login_response)
# Verify that the authenticated user can access the dashboard in current browser
response = self.client.get(self.dashboard_url)
assert response.status_code == 200
# simulating email change in current browser
activation_key = uuid.uuid4().hex
PendingEmailChange.objects.update_or_create(
user=self.user,
defaults={
'new_email': 'new_email@test.com',
'activation_key': activation_key,
}
)
email_change_response = self.client.get(
reverse('confirm_email_change', kwargs={'key': activation_key}),
)
# Verify that email change is successful
assert email_change_response.status_code == 200
self._assert_logged_in_cookies_present(email_change_response)
# Verify that jwt cookies are updated with new email and
# not equal to old logged-in cookies in current browser
self.assertNotEqual(
login_response.cookies[jwt_cookies.jwt_cookie_header_payload_name()].value,
email_change_response.cookies[jwt_cookies.jwt_cookie_header_payload_name()].value
)
self.assertNotEqual(
login_response.cookies[jwt_cookies.jwt_cookie_signature_name()].value,
email_change_response.cookies[jwt_cookies.jwt_cookie_signature_name()].value
)
@patch.dict("django.conf.settings.FEATURES", {"DISABLE_SET_JWT_COOKIES_FOR_TESTS": False})
@override_settings(ENFORCE_SESSION_EMAIL_MATCH=True)
def test_logged_in_user_unauthenticated_on_email_change_in_other_browser(self):
"""
Integration Test: Test that a user logged-in in one browser gets unauthenticated
when the email is changed in some other browser and the request and session emails mismatch.
Verify that the session is invalidated and cookies are deleted in current browser
and user gets unauthenticated.
"""
setup_login_oauth_client()
# Login the user with 'test@example.com` email and test password in current browser
response = self.client.post(self.login_url, {
"email_or_username": self.EMAIL,
"password": self.PASSWORD,
})
# Verify that the user is logged in successfully in current browser
assert response.status_code == 200
# Verify that the logged-in cookies are set in current browser
self._assert_logged_in_cookies_present(response)
# Verify that the authenticated user can access the dashboard in current browser
response = self.client.get(self.dashboard_url)
assert response.status_code == 200
# simulating email changed in some other browser (Email is changed in DB)
self.user.email = 'new_email@test.com'
self.user.save()
# Verify that the user gets unauthenticated in current browser and cannot access the dashboard
response = self.client.get(self.dashboard_url)
assert response.status_code == 302
self._assert_logged_in_cookies_not_present(response)
@patch.dict("django.conf.settings.FEATURES", {"DISABLE_SET_JWT_COOKIES_FOR_TESTS": False})
@override_settings(ENFORCE_SESSION_EMAIL_MATCH=True)
def test_logged_in_user_remains_authenticated_on_email_change_in_same_browser(self):
"""
Integration Test: test that a user logged-in in some browser remains authenticated
when the email is changed in same browser.
Verify that the session and cookies are updated in current browser and
user remains authenticated
"""
setup_login_oauth_client()
# Login the user with 'test@example.com` email and test password in current browser
response = self.client.post(self.login_url, {
"email_or_username": self.EMAIL,
"password": self.PASSWORD,
})
# Verify that the user is logged in successfully in current browser
assert response.status_code == 200
# Verify that the logged-in cookies are set in current browser
self._assert_logged_in_cookies_present(response)
# Verify that the authenticated user can access the dashboard in current browser
response = self.client.get(self.dashboard_url)
assert response.status_code == 200
# simulating email change in current browser
activation_key = uuid.uuid4().hex
PendingEmailChange.objects.update_or_create(
user=self.user,
defaults={
'new_email': 'new_email@test.com',
'activation_key': activation_key,
}
)
email_change_response = self.client.get(
reverse('confirm_email_change', kwargs={'key': activation_key}),
)
# Verify that email change is successful and all logged-in
# cookies are set in current browser
assert email_change_response.status_code == 200
self._assert_logged_in_cookies_present(email_change_response)
# Verify that the user remains authenticated in current browser and can access the dashboard
response = self.client.get(self.dashboard_url)
assert response.status_code == 200
@patch.dict("django.conf.settings.FEATURES", {"DISABLE_SET_JWT_COOKIES_FOR_TESTS": False})
@override_settings(ENFORCE_SESSION_EMAIL_MATCH=True)
def test_registered_user_unauthenticated_on_email_change_in_other_browser(self):
"""
Integration Test: Test that a user registered in one browser gets unauthenticated
when the email is changed in some other browser and the request and session emails mismatch.
Verify that the session is invalidated and cookies are deleted in current browser
and user gets unauthenticated
"""
setup_login_oauth_client()
# Register the user with 'john_doe@example.com` email and test password in current browser
response = self.client.post(self.register_url, {
"email": 'john_doe@example.com',
"name": 'John Doe',
"username": 'john_doe',
"password": 'password',
"honor_code": "true",
})
# Verify that the user is logged in successfully in current browser
assert response.status_code == 200
# Verify that the logged-in cookies are set in current browser
self._assert_logged_in_cookies_present(response)
# Verify that the authenticated user can access the dashboard in current browser
response = self.client.get(self.dashboard_url)
assert response.status_code == 200
# simulating email changed in some other browser (Email is changed in DB)
registered_user = User.objects.get(email='john_doe@example.com')
registered_user.email = 'new_email@test.com'
registered_user.save()
# Verify that the user get unauthenticated in current browser and cannot access the dashboard
response = self.client.get(self.dashboard_url)
assert response.status_code == 302
self._assert_logged_in_cookies_not_present(response)
@patch.dict("django.conf.settings.FEATURES", {"DISABLE_SET_JWT_COOKIES_FOR_TESTS": False})
@override_settings(ENFORCE_SESSION_EMAIL_MATCH=True)
def test_registered_user_remain_authenticated_on_email_change_in_same_browser(self):
"""
Integration Test: test that a user registered in one browser remains
authenticated in current browser when the email is changed in same browser.
Verify that the session and cookies updated and user remains
authenticated in current browser
"""
setup_login_oauth_client()
# Register the user with 'john_doe@example.com` email and test password in current browser
response = self.client.post(self.register_url, {
"email": 'john_doe@example.com',
"name": 'John Doe',
"username": 'john_doe',
"password": 'password',
"honor_code": "true",
})
# Verify that the user is logged in successfully in current browser
assert response.status_code == 200
# Verify that the logged-in cookies are set in current browser
self._assert_logged_in_cookies_present(response)
# Verify that the authenticated user can access the dashboard in current browser
response = self.client.get(self.dashboard_url)
assert response.status_code == 200
# getting newly created user
registered_user = User.objects.get(email='john_doe@example.com')
# simulating email change in current browser
activation_key = uuid.uuid4().hex
PendingEmailChange.objects.update_or_create(
user=registered_user,
defaults={
'new_email': 'new_email@test.com',
'activation_key': activation_key,
}
)
email_change_response = self.client.get(
reverse('confirm_email_change', kwargs={'key': activation_key}),
)
# Verify that email change is successful and all logged-in
# cookies are updated with new email in current browser
assert email_change_response.status_code == 200
self._assert_logged_in_cookies_present(email_change_response)
# Verify that the user remains authenticated in current browser and can access the dashboard
response = self.client.get(self.dashboard_url)
assert response.status_code == 200
def _assert_logged_in_cookies_present(self, response):
"""
Helper function to verify that all logged-in cookies are available
and have valid values (not empty strings)
"""
all_cookies = ALL_LOGGED_IN_COOKIE_NAMES + (settings.SESSION_COOKIE_NAME,)
for cookie in all_cookies:
# Check if the cookie is present in response.cookies.keys()
self.assertIn(cookie, response.cookies.keys())
# Assert that the value is not an empty string
self.assertNotEqual(response.cookies[cookie].value, "")
def _assert_logged_in_cookies_not_present(self, response):
"""
Helper function to verify that all logged-in cookies are cleared
and have empty values
"""
all_cookies = ALL_LOGGED_IN_COOKIE_NAMES + (settings.SESSION_COOKIE_NAME,)
for cookie in all_cookies:
# Check if the cookie is present in response.cookies.keys()
self.assertIn(cookie, response.cookies.keys())
# Assert that the value is not an empty string
self.assertEqual(response.cookies[cookie].value, "")

View File

@@ -232,7 +232,7 @@ class TestOwnUsernameAPI(FilteredQueryCountMixin, CacheIsolationTestCase, UserAP
Test that a client (logged in) can get her own username.
"""
self.client.login(username=self.user.username, password=TEST_PASSWORD)
self._verify_get_own_username(16)
self._verify_get_own_username(19)
def test_get_username_inactive(self):
"""
@@ -242,7 +242,7 @@ class TestOwnUsernameAPI(FilteredQueryCountMixin, CacheIsolationTestCase, UserAP
self.client.login(username=self.user.username, password=TEST_PASSWORD)
self.user.is_active = False
self.user.save()
self._verify_get_own_username(16)
self._verify_get_own_username(19)
def test_get_username_not_logged_in(self):
"""
@@ -358,7 +358,7 @@ class TestAccountsAPI(FilteredQueryCountMixin, CacheIsolationTestCase, UserAPITe
"""
ENABLED_CACHES = ['default']
TOTAL_QUERY_COUNT = 24
TOTAL_QUERY_COUNT = 27
FULL_RESPONSE_FIELD_COUNT = 29
def setUp(self):
@@ -811,7 +811,7 @@ class TestAccountsAPI(FilteredQueryCountMixin, CacheIsolationTestCase, UserAPITe
assert data['time_zone'] is None
self.client.login(username=self.user.username, password=TEST_PASSWORD)
verify_get_own_information(self._get_num_queries(22))
verify_get_own_information(self._get_num_queries(25))
# Now make sure that the user can get the same information, even if not active
self.user.is_active = False
@@ -831,7 +831,7 @@ class TestAccountsAPI(FilteredQueryCountMixin, CacheIsolationTestCase, UserAPITe
legacy_profile.save()
self.client.login(username=self.user.username, password=TEST_PASSWORD)
with self.assertNumQueries(self._get_num_queries(22), table_ignorelist=WAFFLE_TABLES):
with self.assertNumQueries(self._get_num_queries(25), table_ignorelist=WAFFLE_TABLES):
response = self.send_get(self.client)
for empty_field in ("level_of_education", "gender", "country", "state", "bio",):
assert response.data[empty_field] is None

View File

@@ -23,7 +23,7 @@ click>=8.0,<9.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.10.9
edx-enterprise==4.10.11
# django-oauth-toolkit version >=2.0.0 has breaking changes. More details
# mentioned on this issue https://github.com/openedx/edx-platform/issues/32884
@@ -107,3 +107,13 @@ openedx-learning==0.4.4
# Open AI version 1.0.0 dropped support for openai.ChatCompletion which is currently in use in enterprise.
openai<=0.28.1
# optimizely-sdk 5.0.0 is breaking following test with segmentation fault
# common/djangoapps/third_party_auth/tests/test_views.py::SAMLMetadataTest::test_secure_key_configuration
# needs to be fixed in the follow up issue
# https://github.com/openedx/edx-platform/issues/34103
optimizely-sdk<5.0
# lxml 5.1.0 introduced a breaking change in unit test shards
# This constraint can probably be removed once lxml==5.1.1 is released on PyPI
lxml<5.0

View File

@@ -22,7 +22,7 @@ cryptography==38.0.4
# -r requirements/edx-sandbox/py38.in
cycler==0.12.1
# via matplotlib
fonttools==4.46.0
fonttools==4.47.2
# via matplotlib
importlib-resources==6.1.1
# via matplotlib
@@ -30,11 +30,12 @@ joblib==1.3.2
# via nltk
kiwisolver==1.4.5
# via matplotlib
lxml==4.9.3
lxml==4.9.4
# via
# -c requirements/edx-sandbox/../constraints.txt
# -r requirements/edx-sandbox/py38.in
# openedx-calc
markupsafe==2.1.3
markupsafe==2.1.4
# via
# chem
# openedx-calc
@@ -59,7 +60,7 @@ openedx-calc==3.0.1
# via -r requirements/edx-sandbox/py38.in
packaging==23.2
# via matplotlib
pillow==10.1.0
pillow==10.2.0
# via matplotlib
pycparser==2.21
# via cffi
@@ -71,9 +72,9 @@ pyparsing==3.1.1
# openedx-calc
python-dateutil==2.8.2
# via matplotlib
random2==1.0.1
random2==1.0.2
# via -r requirements/edx-sandbox/py38.in
regex==2023.10.3
regex==2023.12.25
# via nltk
scipy==1.7.3
# via

View File

@@ -35,7 +35,7 @@ async-timeout==4.0.3
# via
# aiohttp
# redis
attrs==23.1.0
attrs==23.2.0
# via
# -r requirements/edx/kernel.in
# aiohttp
@@ -58,7 +58,7 @@ backports-zoneinfo[tzdata]==0.2.1
# celery
# icalendar
# kombu
beautifulsoup4==4.12.2
beautifulsoup4==4.12.3
# via pynliner
billiard==4.2.0
# via celery
@@ -73,13 +73,13 @@ bleach[css]==6.1.0
# xblock-poll
boto==2.49.0
# via -r requirements/edx/kernel.in
boto3==1.33.12
boto3==1.34.28
# via
# -r requirements/edx/kernel.in
# django-ses
# fs-s3fs
# ora2
botocore==1.33.12
botocore==1.34.28
# via
# -r requirements/edx/kernel.in
# boto3
@@ -243,6 +243,7 @@ django==3.2.23
# openedx-learning
# ora2
# super-csv
# xblock-google-drive
# xss-utils
django-appconf==1.0.6
# via django-statici18n
@@ -283,12 +284,12 @@ django-filter==23.5
# edx-enterprise
# lti-consumer-xblock
# openedx-blockstore
django-ipware==6.0.2
django-ipware==6.0.3
# via
# -r requirements/edx/kernel.in
# edx-enterprise
# edx-proctoring
django-js-asset==2.1.0
django-js-asset==2.2.0
# via django-mptt
django-method-override==1.0.4
# via -r requirements/edx/kernel.in
@@ -325,7 +326,7 @@ django-oauth-toolkit==1.7.1
# edx-enterprise
django-object-actions==4.2.0
# via edx-enterprise
django-pipeline==2.1.0
django-pipeline==3.0.0
# via -r requirements/edx/kernel.in
django-ratelimit==4.1.0
# via -r requirements/edx/kernel.in
@@ -398,9 +399,9 @@ done-xblock==2.2.0
# via -r requirements/edx/bundled.in
drf-jwt==1.19.2
# via edx-drf-extensions
drf-nested-routers==0.93.4
drf-nested-routers==0.93.5
# via openedx-blockstore
drf-spectacular==0.27.0
drf-spectacular==0.27.1
# via -r requirements/edx/kernel.in
drf-yasg==1.21.5
# via
@@ -418,7 +419,7 @@ edx-auth-backends==4.2.0
# via
# -r requirements/edx/kernel.in
# openedx-blockstore
edx-braze-client==0.1.8
edx-braze-client==0.2.1
# via
# -r requirements/edx/bundled.in
# edx-enterprise
@@ -446,7 +447,7 @@ edx-django-release-util==1.3.0
# openedx-blockstore
edx-django-sites-extensions==4.0.2
# via -r requirements/edx/kernel.in
edx-django-utils==5.9.0
edx-django-utils==5.10.1
# via
# -r requirements/edx/kernel.in
# django-config-models
@@ -462,7 +463,7 @@ edx-django-utils==5.9.0
# openedx-blockstore
# ora2
# super-csv
edx-drf-extensions==10.0.0
edx-drf-extensions==10.1.0
# via
# -r requirements/edx/kernel.in
# edx-completion
@@ -474,7 +475,7 @@ edx-drf-extensions==10.0.0
# edx-when
# edxval
# openedx-learning
edx-enterprise==4.10.9
edx-enterprise==4.10.11
# via
# -c requirements/edx/../constraints.txt
# -r requirements/edx/kernel.in
@@ -519,7 +520,7 @@ edx-rest-api-client==5.6.1
# edx-proctoring
edx-search==3.8.2
# via -r requirements/edx/kernel.in
edx-sga==0.23.0
edx-sga==0.23.1
# via -r requirements/edx/bundled.in
edx-submissions==3.6.0
# via
@@ -560,11 +561,11 @@ event-tracking==2.2.0
# edx-completion
# edx-proctoring
# edx-search
fastavro==1.9.1
fastavro==1.9.3
# via openedx-events
filelock==3.13.1
# via snowflake-connector-python
frozenlist==1.4.0
frozenlist==1.4.1
# via
# aiohttp
# aiosignal
@@ -601,7 +602,7 @@ idna==3.6
# requests
# snowflake-connector-python
# yarl
importlib-metadata==7.0.0
importlib-metadata==7.0.1
# via markdown
importlib-resources==5.13.0
# via
@@ -620,7 +621,7 @@ isodate==0.6.1
# via python3-saml
itypes==1.2.0
# via coreapi
jinja2==3.1.2
jinja2==3.1.3
# via
# code-annotations
# coreschema
@@ -641,17 +642,17 @@ jsonfield==3.1.0
# edx-submissions
# lti-consumer-xblock
# ora2
jsonschema==4.20.0
jsonschema==4.21.1
# via
# drf-spectacular
# optimizely-sdk
jsonschema-specifications==2023.11.2
jsonschema-specifications==2023.12.1
# via jsonschema
jwcrypto==1.5.0
jwcrypto==1.5.1
# via
# django-oauth-toolkit
# pylti1p3
kombu==5.3.4
kombu==5.3.5
# via celery
laboratory==1.0.2
# via -r requirements/edx/kernel.in
@@ -668,10 +669,11 @@ libsass==0.10.0
# -r requirements/edx/paver.txt
loremipsum==1.0.5
# via ora2
lti-consumer-xblock==9.8.1
lti-consumer-xblock==9.8.3
# via -r requirements/edx/kernel.in
lxml==4.9.3
lxml==4.9.4
# via
# -c requirements/edx/../constraints.txt
# -r requirements/edx/kernel.in
# edx-i18n-tools
# edxval
@@ -690,7 +692,6 @@ mako==1.3.0
# acid-xblock
# lti-consumer-xblock
# xblock
# xblock-google-drive
# xblock-utils
markdown==3.3.7
# via
@@ -701,7 +702,7 @@ markdown==3.3.7
# xblock-poll
markey==0.8
# via enmerkar-underscore
markupsafe==2.1.3
markupsafe==2.1.4
# via
# -r requirements/edx/paver.txt
# chem
@@ -709,7 +710,7 @@ markupsafe==2.1.3
# mako
# openedx-calc
# xblock
maxminddb==2.5.1
maxminddb==2.5.2
# via geoip2
mock==5.1.0
# via -r requirements/edx/paver.txt
@@ -725,11 +726,11 @@ multidict==6.0.4
# via
# aiohttp
# yarl
mysqlclient==2.2.0
mysqlclient==2.2.1
# via
# -r requirements/edx/kernel.in
# openedx-blockstore
newrelic==9.3.0
newrelic==9.6.0
# via
# -r requirements/edx/bundled.in
# edx-django-utils
@@ -756,13 +757,13 @@ openai==0.28.1
# via
# -c requirements/edx/../constraints.txt
# edx-enterprise
openedx-atlas==0.5.0
openedx-atlas==0.6.0
# via -r requirements/edx/kernel.in
openedx-blockstore==1.4.0
# via -r requirements/edx/kernel.in
openedx-calc==3.0.1
# via -r requirements/edx/kernel.in
openedx-django-pyfs==3.4.0
openedx-django-pyfs==3.4.1
# via
# lti-consumer-xblock
# xblock
@@ -786,8 +787,10 @@ openedx-learning==0.4.4
openedx-mongodbproxy==0.2.0
# via -r requirements/edx/kernel.in
optimizely-sdk==4.1.1
# via -r requirements/edx/bundled.in
ora2==6.0.29
# via
# -c requirements/edx/../constraints.txt
# -r requirements/edx/bundled.in
ora2==6.0.30
# via -r requirements/edx/bundled.in
packaging==23.2
# via
@@ -818,7 +821,7 @@ pgpy==0.6.0
# via edx-enterprise
piexif==1.1.3
# via -r requirements/edx/kernel.in
pillow==10.1.0
pillow==10.2.0
# via
# -r requirements/edx/kernel.in
# edx-enterprise
@@ -830,9 +833,9 @@ platformdirs==3.11.0
# via snowflake-connector-python
polib==1.2.0
# via edx-i18n-tools
prompt-toolkit==3.0.42
prompt-toolkit==3.0.43
# via click-repl
psutil==5.9.6
psutil==5.9.8
# via
# -r requirements/edx/paver.txt
# edx-django-utils
@@ -846,7 +849,7 @@ pycountry==23.12.11
# via -r requirements/edx/kernel.in
pycparser==2.21
# via cffi
pycryptodomex==3.19.0
pycryptodomex==3.20.0
# via
# -r requirements/edx/kernel.in
# edx-proctoring
@@ -919,11 +922,11 @@ python-dateutil==2.8.2
# olxcleaner
# ora2
# xblock
python-ipware==2.0.0
python-ipware==2.0.1
# via django-ipware
python-memcached==1.59
python-memcached==1.62
# via -r requirements/edx/paver.txt
python-slugify==8.0.1
python-slugify==8.0.2
# via code-annotations
python-swiftclient==4.4.0
# via ora2
@@ -965,19 +968,19 @@ pyyaml==6.0.1
# edx-django-release-util
# edx-i18n-tools
# xblock
random2==1.0.1
random2==1.0.2
# via -r requirements/edx/kernel.in
recommender-xblock==2.0.1
recommender-xblock==2.1.1
# via -r requirements/edx/bundled.in
redis==5.0.1
# via
# -r requirements/edx/kernel.in
# walrus
referencing==0.32.0
referencing==0.32.1
# via
# jsonschema
# jsonschema-specifications
regex==2023.10.3
regex==2023.12.25
# via nltk
requests==2.31.0
# via
@@ -1002,11 +1005,12 @@ requests==2.31.0
# slumber
# snowflake-connector-python
# social-auth-core
# xblock-google-drive
requests-oauthlib==1.3.1
# via
# -r requirements/edx/kernel.in
# social-auth-core
rpds-py==0.13.2
rpds-py==0.17.1
# via
# jsonschema
# referencing
@@ -1020,7 +1024,7 @@ rules==3.3
# edx-enterprise
# edx-proctoring
# openedx-learning
s3transfer==0.8.2
s3transfer==0.10.0
# via boto3
sailthru-client==2.2.3
# via edx-ace
@@ -1069,14 +1073,13 @@ six==1.16.0
# py2neo
# pyjwkest
# python-dateutil
# python-memcached
slumber==0.7.1
# via
# -r requirements/edx/kernel.in
# edx-bulk-grades
# edx-enterprise
# edx-rest-api-client
snowflake-connector-python==3.6.0
snowflake-connector-python==3.7.0
# via edx-enterprise
social-auth-app-django==5.0.0
# via
@@ -1141,7 +1144,7 @@ typing-extensions==4.9.0
# kombu
# pylti1p3
# snowflake-connector-python
tzdata==2023.3
tzdata==2023.4
# via
# backports-zoneinfo
# celery
@@ -1176,7 +1179,7 @@ walrus==0.9.3
# via edx-event-bus-redis
watchdog==3.0.0
# via -r requirements/edx/paver.txt
wcwidth==0.2.12
wcwidth==0.2.13
# via prompt-toolkit
web-fragments==2.1.0
# via
@@ -1199,7 +1202,7 @@ wrapt==1.16.0
# via
# -r requirements/edx/paver.txt
# deprecated
xblock[django]==1.9.0
xblock[django]==1.10.0
# via
# -r requirements/edx/kernel.in
# acid-xblock
@@ -1215,16 +1218,14 @@ xblock[django]==1.9.0
# xblock-google-drive
# xblock-poll
# xblock-utils
xblock-drag-and-drop-v2==3.3.0
xblock-drag-and-drop-v2==3.4.0
# via -r requirements/edx/bundled.in
xblock-google-drive==0.5.0
xblock-google-drive==0.6.1
# via -r requirements/edx/bundled.in
xblock-poll==1.13.0
# via -r requirements/edx/bundled.in
xblock-utils==4.0.0
# via
# edx-sga
# xblock-google-drive
# via edx-sga
xmlsec==1.3.13
# via python3-saml
xss-utils==0.5.0

View File

@@ -6,15 +6,15 @@
#
chardet==5.2.0
# via diff-cover
coverage==7.3.2
coverage==7.4.0
# via -r requirements/edx/coverage.in
diff-cover==8.0.1
diff-cover==8.0.3
# via -r requirements/edx/coverage.in
jinja2==3.1.2
jinja2==3.1.3
# via diff-cover
markupsafe==2.1.3
markupsafe==2.1.4
# via jinja2
pluggy==1.3.0
pluggy==1.4.0
# via diff-cover
pygments==2.17.2
# via diff-cover

View File

@@ -53,10 +53,9 @@ annotated-types==0.6.0
# via
# -r requirements/edx/testing.txt
# pydantic
anyio==3.7.1
anyio==4.2.0
# via
# -r requirements/edx/testing.txt
# fastapi
# starlette
appdirs==1.4.4
# via
@@ -86,7 +85,7 @@ async-timeout==4.0.3
# -r requirements/edx/testing.txt
# aiohttp
# redis
attrs==23.1.0
attrs==23.2.0
# via
# -r requirements/edx/doc.txt
# -r requirements/edx/testing.txt
@@ -119,7 +118,7 @@ backports-zoneinfo[tzdata]==0.2.1
# celery
# icalendar
# kombu
beautifulsoup4==4.12.2
beautifulsoup4==4.12.3
# via
# -r requirements/edx/doc.txt
# -r requirements/edx/testing.txt
@@ -145,14 +144,14 @@ boto==2.49.0
# via
# -r requirements/edx/doc.txt
# -r requirements/edx/testing.txt
boto3==1.33.12
boto3==1.34.28
# via
# -r requirements/edx/doc.txt
# -r requirements/edx/testing.txt
# django-ses
# fs-s3fs
# ora2
botocore==1.33.12
botocore==1.34.28
# via
# -r requirements/edx/doc.txt
# -r requirements/edx/testing.txt
@@ -281,7 +280,7 @@ coreschema==0.0.4
# -r requirements/edx/testing.txt
# coreapi
# drf-yasg
coverage[toml]==7.3.2
coverage[toml]==7.4.0
# via
# -r requirements/edx/testing.txt
# coverage
@@ -313,9 +312,9 @@ cssutils==2.9.0
# -r requirements/edx/doc.txt
# -r requirements/edx/testing.txt
# pynliner
ddt==1.7.0
ddt==1.7.1
# via -r requirements/edx/testing.txt
deepmerge==1.1.0
deepmerge==1.1.1
# via
# -r requirements/edx/doc.txt
# sphinxcontrib-openapi
@@ -332,7 +331,7 @@ deprecated==1.2.14
# -r requirements/edx/doc.txt
# -r requirements/edx/testing.txt
# jwcrypto
diff-cover==8.0.1
diff-cover==8.0.3
# via -r requirements/edx/testing.txt
dill==0.3.7
# via
@@ -416,6 +415,7 @@ django==3.2.23
# openedx-learning
# ora2
# super-csv
# xblock-google-drive
# xss-utils
django-appconf==1.0.6
# via
@@ -481,13 +481,13 @@ django-filter==23.5
# edx-enterprise
# lti-consumer-xblock
# openedx-blockstore
django-ipware==6.0.2
django-ipware==6.0.3
# via
# -r requirements/edx/doc.txt
# -r requirements/edx/testing.txt
# edx-enterprise
# edx-proctoring
django-js-asset==2.1.0
django-js-asset==2.2.0
# via
# -r requirements/edx/doc.txt
# -r requirements/edx/testing.txt
@@ -540,7 +540,7 @@ django-object-actions==4.2.0
# -r requirements/edx/doc.txt
# -r requirements/edx/testing.txt
# edx-enterprise
django-pipeline==2.1.0
django-pipeline==3.0.0
# via
# -r requirements/edx/doc.txt
# -r requirements/edx/testing.txt
@@ -655,12 +655,12 @@ drf-jwt==1.19.2
# -r requirements/edx/doc.txt
# -r requirements/edx/testing.txt
# edx-drf-extensions
drf-nested-routers==0.93.4
drf-nested-routers==0.93.5
# via
# -r requirements/edx/doc.txt
# -r requirements/edx/testing.txt
# openedx-blockstore
drf-spectacular==0.27.0
drf-spectacular==0.27.1
# via
# -r requirements/edx/doc.txt
# -r requirements/edx/testing.txt
@@ -686,7 +686,7 @@ edx-auth-backends==4.2.0
# -r requirements/edx/doc.txt
# -r requirements/edx/testing.txt
# openedx-blockstore
edx-braze-client==0.1.8
edx-braze-client==0.2.1
# via
# -r requirements/edx/doc.txt
# -r requirements/edx/testing.txt
@@ -725,7 +725,7 @@ edx-django-sites-extensions==4.0.2
# via
# -r requirements/edx/doc.txt
# -r requirements/edx/testing.txt
edx-django-utils==5.9.0
edx-django-utils==5.10.1
# via
# -r requirements/edx/doc.txt
# -r requirements/edx/testing.txt
@@ -742,7 +742,7 @@ edx-django-utils==5.9.0
# openedx-blockstore
# ora2
# super-csv
edx-drf-extensions==10.0.0
edx-drf-extensions==10.1.0
# via
# -r requirements/edx/doc.txt
# -r requirements/edx/testing.txt
@@ -755,7 +755,7 @@ edx-drf-extensions==10.0.0
# edx-when
# edxval
# openedx-learning
edx-enterprise==4.10.9
edx-enterprise==4.10.11
# via
# -c requirements/edx/../constraints.txt
# -r requirements/edx/doc.txt
@@ -824,7 +824,7 @@ edx-search==3.8.2
# via
# -r requirements/edx/doc.txt
# -r requirements/edx/testing.txt
edx-sga==0.23.0
edx-sga==0.23.1
# via
# -r requirements/edx/doc.txt
# -r requirements/edx/testing.txt
@@ -896,15 +896,15 @@ execnet==2.0.2
# pytest-xdist
factory-boy==3.3.0
# via -r requirements/edx/testing.txt
faker==20.1.0
faker==22.5.1
# via
# -r requirements/edx/testing.txt
# factory-boy
fastapi==0.105.0
fastapi==0.109.0
# via
# -r requirements/edx/testing.txt
# pact-python
fastavro==1.9.1
fastavro==1.9.3
# via
# -r requirements/edx/doc.txt
# -r requirements/edx/testing.txt
@@ -916,9 +916,9 @@ filelock==3.13.1
# snowflake-connector-python
# tox
# virtualenv
freezegun==1.3.1
freezegun==1.4.0
# via -r requirements/edx/testing.txt
frozenlist==1.4.0
frozenlist==1.4.1
# via
# -r requirements/edx/doc.txt
# -r requirements/edx/testing.txt
@@ -949,13 +949,13 @@ gitdb==4.0.11
# via
# -r requirements/edx/doc.txt
# gitpython
gitpython==3.1.40
gitpython==3.1.41
# via -r requirements/edx/doc.txt
glob2==0.7
# via
# -r requirements/edx/doc.txt
# -r requirements/edx/testing.txt
grimp==3.1
grimp==3.2
# via
# -r requirements/edx/testing.txt
# import-linter
@@ -995,9 +995,9 @@ imagesize==1.4.1
# via
# -r requirements/edx/doc.txt
# sphinx
import-linter==1.12.1
import-linter==2.0
# via -r requirements/edx/testing.txt
importlib-metadata==7.0.0
importlib-metadata==7.0.1
# via
# -r requirements/edx/../pip-tools.txt
# -r requirements/edx/doc.txt
@@ -1037,7 +1037,7 @@ isodate==0.6.1
# -r requirements/edx/doc.txt
# -r requirements/edx/testing.txt
# python3-saml
isort==5.13.1
isort==5.13.2
# via
# -r requirements/edx/testing.txt
# pylint
@@ -1046,7 +1046,7 @@ itypes==1.2.0
# -r requirements/edx/doc.txt
# -r requirements/edx/testing.txt
# coreapi
jinja2==3.1.2
jinja2==3.1.3
# via
# -r requirements/edx/doc.txt
# -r requirements/edx/testing.txt
@@ -1080,25 +1080,25 @@ jsonfield==3.1.0
# edx-submissions
# lti-consumer-xblock
# ora2
jsonschema==4.20.0
jsonschema==4.21.1
# via
# -r requirements/edx/doc.txt
# -r requirements/edx/testing.txt
# drf-spectacular
# optimizely-sdk
# sphinxcontrib-openapi
jsonschema-specifications==2023.11.2
jsonschema-specifications==2023.12.1
# via
# -r requirements/edx/doc.txt
# -r requirements/edx/testing.txt
# jsonschema
jwcrypto==1.5.0
jwcrypto==1.5.1
# via
# -r requirements/edx/doc.txt
# -r requirements/edx/testing.txt
# django-oauth-toolkit
# pylti1p3
kombu==5.3.4
kombu==5.3.5
# via
# -r requirements/edx/doc.txt
# -r requirements/edx/testing.txt
@@ -1115,7 +1115,7 @@ lazy==1.6
# lti-consumer-xblock
# ora2
# xblock
lazy-object-proxy==1.9.0
lazy-object-proxy==1.10.0
# via
# -r requirements/edx/testing.txt
# astroid
@@ -1130,12 +1130,13 @@ loremipsum==1.0.5
# -r requirements/edx/doc.txt
# -r requirements/edx/testing.txt
# ora2
lti-consumer-xblock==9.8.1
lti-consumer-xblock==9.8.3
# via
# -r requirements/edx/doc.txt
# -r requirements/edx/testing.txt
lxml==4.9.3
lxml==4.9.4
# via
# -c requirements/edx/../constraints.txt
# -r requirements/edx/doc.txt
# -r requirements/edx/testing.txt
# edx-i18n-tools
@@ -1159,7 +1160,6 @@ mako==1.3.0
# acid-xblock
# lti-consumer-xblock
# xblock
# xblock-google-drive
# xblock-utils
markdown==3.3.7
# via
@@ -1174,7 +1174,7 @@ markey==0.8
# -r requirements/edx/doc.txt
# -r requirements/edx/testing.txt
# enmerkar-underscore
markupsafe==2.1.3
markupsafe==2.1.4
# via
# -r requirements/edx/doc.txt
# -r requirements/edx/testing.txt
@@ -1183,7 +1183,7 @@ markupsafe==2.1.3
# mako
# openedx-calc
# xblock
maxminddb==2.5.1
maxminddb==2.5.2
# via
# -r requirements/edx/doc.txt
# -r requirements/edx/testing.txt
@@ -1221,19 +1221,19 @@ multidict==6.0.4
# -r requirements/edx/testing.txt
# aiohttp
# yarl
mypy==1.7.1
mypy==1.8.0
# via
# -r requirements/edx/development.in
# django-stubs
# djangorestframework-stubs
mypy-extensions==1.0.0
# via mypy
mysqlclient==2.2.0
mysqlclient==2.2.1
# via
# -r requirements/edx/doc.txt
# -r requirements/edx/testing.txt
# openedx-blockstore
newrelic==9.3.0
newrelic==9.6.0
# via
# -r requirements/edx/doc.txt
# -r requirements/edx/testing.txt
@@ -1274,7 +1274,7 @@ openai==0.28.1
# -r requirements/edx/doc.txt
# -r requirements/edx/testing.txt
# edx-enterprise
openedx-atlas==0.5.0
openedx-atlas==0.6.0
# via
# -r requirements/edx/doc.txt
# -r requirements/edx/testing.txt
@@ -1286,7 +1286,7 @@ openedx-calc==3.0.1
# via
# -r requirements/edx/doc.txt
# -r requirements/edx/testing.txt
openedx-django-pyfs==3.4.0
openedx-django-pyfs==3.4.1
# via
# -r requirements/edx/doc.txt
# -r requirements/edx/testing.txt
@@ -1322,9 +1322,10 @@ openedx-mongodbproxy==0.2.0
# -r requirements/edx/testing.txt
optimizely-sdk==4.1.1
# via
# -c requirements/edx/../constraints.txt
# -r requirements/edx/doc.txt
# -r requirements/edx/testing.txt
ora2==6.0.29
ora2==6.0.30
# via
# -r requirements/edx/doc.txt
# -r requirements/edx/testing.txt
@@ -1385,7 +1386,7 @@ piexif==1.1.3
# via
# -r requirements/edx/doc.txt
# -r requirements/edx/testing.txt
pillow==10.1.0
pillow==10.2.0
# via
# -r requirements/edx/doc.txt
# -r requirements/edx/testing.txt
@@ -1407,7 +1408,7 @@ platformdirs==3.11.0
# snowflake-connector-python
# tox
# virtualenv
pluggy==1.3.0
pluggy==1.4.0
# via
# -r requirements/edx/testing.txt
# diff-cover
@@ -1418,12 +1419,12 @@ polib==1.2.0
# -r requirements/edx/doc.txt
# -r requirements/edx/testing.txt
# edx-i18n-tools
prompt-toolkit==3.0.42
prompt-toolkit==3.0.43
# via
# -r requirements/edx/doc.txt
# -r requirements/edx/testing.txt
# click-repl
psutil==5.9.6
psutil==5.9.8
# via
# -r requirements/edx/doc.txt
# -r requirements/edx/testing.txt
@@ -1455,18 +1456,18 @@ pycparser==2.21
# -r requirements/edx/doc.txt
# -r requirements/edx/testing.txt
# cffi
pycryptodomex==3.19.0
pycryptodomex==3.20.0
# via
# -r requirements/edx/doc.txt
# -r requirements/edx/testing.txt
# edx-proctoring
# lti-consumer-xblock
# pyjwkest
pydantic==2.5.2
pydantic==2.5.3
# via
# -r requirements/edx/testing.txt
# fastapi
pydantic-core==2.14.5
pydantic-core==2.14.6
# via
# -r requirements/edx/testing.txt
# pydantic
@@ -1591,7 +1592,7 @@ pysrt==1.1.2
# -r requirements/edx/doc.txt
# -r requirements/edx/testing.txt
# edxval
pytest==7.4.3
pytest==7.4.4
# via
# -r requirements/edx/testing.txt
# pylint-pytest
@@ -1636,16 +1637,16 @@ python-dateutil==2.8.2
# olxcleaner
# ora2
# xblock
python-ipware==2.0.0
python-ipware==2.0.1
# via
# -r requirements/edx/doc.txt
# -r requirements/edx/testing.txt
# django-ipware
python-memcached==1.59
python-memcached==1.62
# via
# -r requirements/edx/doc.txt
# -r requirements/edx/testing.txt
python-slugify==8.0.1
python-slugify==8.0.2
# via
# -r requirements/edx/doc.txt
# -r requirements/edx/testing.txt
@@ -1703,11 +1704,11 @@ pyyaml==6.0.1
# edx-i18n-tools
# sphinxcontrib-openapi
# xblock
random2==1.0.1
random2==1.0.2
# via
# -r requirements/edx/doc.txt
# -r requirements/edx/testing.txt
recommender-xblock==2.0.1
recommender-xblock==2.1.1
# via
# -r requirements/edx/doc.txt
# -r requirements/edx/testing.txt
@@ -1716,13 +1717,13 @@ redis==5.0.1
# -r requirements/edx/doc.txt
# -r requirements/edx/testing.txt
# walrus
referencing==0.32.0
referencing==0.32.1
# via
# -r requirements/edx/doc.txt
# -r requirements/edx/testing.txt
# jsonschema
# jsonschema-specifications
regex==2023.10.3
regex==2023.12.25
# via
# -r requirements/edx/doc.txt
# -r requirements/edx/testing.txt
@@ -1754,12 +1755,13 @@ requests==2.31.0
# snowflake-connector-python
# social-auth-core
# sphinx
# xblock-google-drive
requests-oauthlib==1.3.1
# via
# -r requirements/edx/doc.txt
# -r requirements/edx/testing.txt
# social-auth-core
rpds-py==0.13.2
rpds-py==0.17.1
# via
# -r requirements/edx/doc.txt
# -r requirements/edx/testing.txt
@@ -1782,7 +1784,7 @@ rules==3.3
# edx-enterprise
# edx-proctoring
# openedx-learning
s3transfer==0.8.2
s3transfer==0.10.0
# via
# -r requirements/edx/doc.txt
# -r requirements/edx/testing.txt
@@ -1850,7 +1852,6 @@ six==1.16.0
# py2neo
# pyjwkest
# python-dateutil
# python-memcached
# sphinxcontrib-httpdomain
slumber==0.7.1
# via
@@ -1871,7 +1872,7 @@ snowballstemmer==2.2.0
# via
# -r requirements/edx/doc.txt
# sphinx
snowflake-connector-python==3.6.0
snowflake-connector-python==3.7.0
# via
# -r requirements/edx/doc.txt
# -r requirements/edx/testing.txt
@@ -1969,7 +1970,7 @@ staff-graded-xblock==2.2.0
# via
# -r requirements/edx/doc.txt
# -r requirements/edx/testing.txt
starlette==0.27.0
starlette==0.35.1
# via
# -r requirements/edx/testing.txt
# fastapi
@@ -2007,8 +2008,6 @@ tinycss2==1.2.1
# -r requirements/edx/doc.txt
# -r requirements/edx/testing.txt
# bleach
toml==0.10.2
# via vulture
tomli==2.0.1
# via
# -r requirements/edx/../pip-tools.txt
@@ -2024,6 +2023,7 @@ tomli==2.0.1
# pyproject-hooks
# pytest
# tox
# vulture
tomlkit==0.12.3
# via
# -r requirements/edx/doc.txt
@@ -2053,6 +2053,7 @@ typing-extensions==4.9.0
# -r requirements/edx/doc.txt
# -r requirements/edx/testing.txt
# annotated-types
# anyio
# asgiref
# astroid
# django-countries
@@ -2075,7 +2076,7 @@ typing-extensions==4.9.0
# snowflake-connector-python
# starlette
# uvicorn
tzdata==2023.3
tzdata==2023.4
# via
# -r requirements/edx/doc.txt
# -r requirements/edx/testing.txt
@@ -2109,7 +2110,7 @@ user-util==1.0.0
# via
# -r requirements/edx/doc.txt
# -r requirements/edx/testing.txt
uvicorn==0.24.0.post1
uvicorn==0.27.0
# via
# -r requirements/edx/testing.txt
# pact-python
@@ -2129,7 +2130,7 @@ voluptuous==0.14.1
# -r requirements/edx/doc.txt
# -r requirements/edx/testing.txt
# ora2
vulture==2.10
vulture==2.11
# via -r requirements/edx/development.in
walrus==0.9.3
# via
@@ -2141,7 +2142,7 @@ watchdog==3.0.0
# -r requirements/edx/development.in
# -r requirements/edx/doc.txt
# -r requirements/edx/testing.txt
wcwidth==0.2.12
wcwidth==0.2.13
# via
# -r requirements/edx/doc.txt
# -r requirements/edx/testing.txt
@@ -2177,7 +2178,7 @@ wrapt==1.16.0
# -r requirements/edx/testing.txt
# astroid
# deprecated
xblock[django]==1.9.0
xblock[django]==1.10.0
# via
# -r requirements/edx/doc.txt
# -r requirements/edx/testing.txt
@@ -2195,11 +2196,11 @@ xblock[django]==1.9.0
# xblock-google-drive
# xblock-poll
# xblock-utils
xblock-drag-and-drop-v2==3.3.0
xblock-drag-and-drop-v2==3.4.0
# via
# -r requirements/edx/doc.txt
# -r requirements/edx/testing.txt
xblock-google-drive==0.5.0
xblock-google-drive==0.6.1
# via
# -r requirements/edx/doc.txt
# -r requirements/edx/testing.txt
@@ -2212,7 +2213,6 @@ xblock-utils==4.0.0
# -r requirements/edx/doc.txt
# -r requirements/edx/testing.txt
# edx-sga
# xblock-google-drive
xmlsec==1.3.13
# via
# -r requirements/edx/doc.txt

View File

@@ -52,7 +52,7 @@ async-timeout==4.0.3
# -r requirements/edx/base.txt
# aiohttp
# redis
attrs==23.1.0
attrs==23.2.0
# via
# -r requirements/edx/base.txt
# aiohttp
@@ -81,7 +81,7 @@ backports-zoneinfo[tzdata]==0.2.1
# celery
# icalendar
# kombu
beautifulsoup4==4.12.2
beautifulsoup4==4.12.3
# via
# -r requirements/edx/base.txt
# pydata-sphinx-theme
@@ -102,13 +102,13 @@ bleach[css]==6.1.0
# xblock-poll
boto==2.49.0
# via -r requirements/edx/base.txt
boto3==1.33.12
boto3==1.34.28
# via
# -r requirements/edx/base.txt
# django-ses
# fs-s3fs
# ora2
botocore==1.33.12
botocore==1.34.28
# via
# -r requirements/edx/base.txt
# boto3
@@ -210,7 +210,7 @@ cssutils==2.9.0
# via
# -r requirements/edx/base.txt
# pynliner
deepmerge==1.1.0
deepmerge==1.1.1
# via sphinxcontrib-openapi
defusedxml==0.7.1
# via
@@ -293,6 +293,7 @@ django==3.2.23
# openedx-learning
# ora2
# super-csv
# xblock-google-drive
# xss-utils
django-appconf==1.0.6
# via
@@ -343,12 +344,12 @@ django-filter==23.5
# edx-enterprise
# lti-consumer-xblock
# openedx-blockstore
django-ipware==6.0.2
django-ipware==6.0.3
# via
# -r requirements/edx/base.txt
# edx-enterprise
# edx-proctoring
django-js-asset==2.1.0
django-js-asset==2.2.0
# via
# -r requirements/edx/base.txt
# django-mptt
@@ -391,7 +392,7 @@ django-object-actions==4.2.0
# via
# -r requirements/edx/base.txt
# edx-enterprise
django-pipeline==2.1.0
django-pipeline==3.0.0
# via -r requirements/edx/base.txt
django-ratelimit==4.1.0
# via -r requirements/edx/base.txt
@@ -473,11 +474,11 @@ drf-jwt==1.19.2
# via
# -r requirements/edx/base.txt
# edx-drf-extensions
drf-nested-routers==0.93.4
drf-nested-routers==0.93.5
# via
# -r requirements/edx/base.txt
# openedx-blockstore
drf-spectacular==0.27.0
drf-spectacular==0.27.1
# via -r requirements/edx/base.txt
drf-yasg==1.21.5
# via
@@ -496,7 +497,7 @@ edx-auth-backends==4.2.0
# via
# -r requirements/edx/base.txt
# openedx-blockstore
edx-braze-client==0.1.8
edx-braze-client==0.2.1
# via
# -r requirements/edx/base.txt
# edx-enterprise
@@ -524,7 +525,7 @@ edx-django-release-util==1.3.0
# openedx-blockstore
edx-django-sites-extensions==4.0.2
# via -r requirements/edx/base.txt
edx-django-utils==5.9.0
edx-django-utils==5.10.1
# via
# -r requirements/edx/base.txt
# django-config-models
@@ -540,7 +541,7 @@ edx-django-utils==5.9.0
# openedx-blockstore
# ora2
# super-csv
edx-drf-extensions==10.0.0
edx-drf-extensions==10.1.0
# via
# -r requirements/edx/base.txt
# edx-completion
@@ -552,7 +553,7 @@ edx-drf-extensions==10.0.0
# edx-when
# edxval
# openedx-learning
edx-enterprise==4.10.9
edx-enterprise==4.10.11
# via
# -c requirements/edx/../constraints.txt
# -r requirements/edx/base.txt
@@ -601,7 +602,7 @@ edx-rest-api-client==5.6.1
# edx-proctoring
edx-search==3.8.2
# via -r requirements/edx/base.txt
edx-sga==0.23.0
edx-sga==0.23.1
# via -r requirements/edx/base.txt
edx-submissions==3.6.0
# via
@@ -647,7 +648,7 @@ event-tracking==2.2.0
# edx-completion
# edx-proctoring
# edx-search
fastavro==1.9.1
fastavro==1.9.3
# via
# -r requirements/edx/base.txt
# openedx-events
@@ -655,7 +656,7 @@ filelock==3.13.1
# via
# -r requirements/edx/base.txt
# snowflake-connector-python
frozenlist==1.4.0
frozenlist==1.4.1
# via
# -r requirements/edx/base.txt
# aiohttp
@@ -678,7 +679,7 @@ geoip2==4.8.0
# via -r requirements/edx/base.txt
gitdb==4.0.11
# via gitpython
gitpython==3.1.40
gitpython==3.1.41
# via -r requirements/edx/doc.in
glob2==0.7
# via -r requirements/edx/base.txt
@@ -701,7 +702,7 @@ idna==3.6
# yarl
imagesize==1.4.1
# via sphinx
importlib-metadata==7.0.0
importlib-metadata==7.0.1
# via
# -r requirements/edx/base.txt
# markdown
@@ -731,7 +732,7 @@ itypes==1.2.0
# via
# -r requirements/edx/base.txt
# coreapi
jinja2==3.1.2
jinja2==3.1.3
# via
# -r requirements/edx/base.txt
# code-annotations
@@ -759,22 +760,22 @@ jsonfield==3.1.0
# edx-submissions
# lti-consumer-xblock
# ora2
jsonschema==4.20.0
jsonschema==4.21.1
# via
# -r requirements/edx/base.txt
# drf-spectacular
# optimizely-sdk
# sphinxcontrib-openapi
jsonschema-specifications==2023.11.2
jsonschema-specifications==2023.12.1
# via
# -r requirements/edx/base.txt
# jsonschema
jwcrypto==1.5.0
jwcrypto==1.5.1
# via
# -r requirements/edx/base.txt
# django-oauth-toolkit
# pylti1p3
kombu==5.3.4
kombu==5.3.5
# via
# -r requirements/edx/base.txt
# celery
@@ -795,10 +796,11 @@ loremipsum==1.0.5
# via
# -r requirements/edx/base.txt
# ora2
lti-consumer-xblock==9.8.1
lti-consumer-xblock==9.8.3
# via -r requirements/edx/base.txt
lxml==4.9.3
lxml==4.9.4
# via
# -c requirements/edx/../constraints.txt
# -r requirements/edx/base.txt
# edx-i18n-tools
# edxval
@@ -817,7 +819,6 @@ mako==1.3.0
# acid-xblock
# lti-consumer-xblock
# xblock
# xblock-google-drive
# xblock-utils
markdown==3.3.7
# via
@@ -830,7 +831,7 @@ markey==0.8
# via
# -r requirements/edx/base.txt
# enmerkar-underscore
markupsafe==2.1.3
markupsafe==2.1.4
# via
# -r requirements/edx/base.txt
# chem
@@ -838,7 +839,7 @@ markupsafe==2.1.3
# mako
# openedx-calc
# xblock
maxminddb==2.5.1
maxminddb==2.5.2
# via
# -r requirements/edx/base.txt
# geoip2
@@ -862,11 +863,11 @@ multidict==6.0.4
# -r requirements/edx/base.txt
# aiohttp
# yarl
mysqlclient==2.2.0
mysqlclient==2.2.1
# via
# -r requirements/edx/base.txt
# openedx-blockstore
newrelic==9.3.0
newrelic==9.6.0
# via
# -r requirements/edx/base.txt
# edx-django-utils
@@ -897,13 +898,13 @@ openai==0.28.1
# -c requirements/edx/../constraints.txt
# -r requirements/edx/base.txt
# edx-enterprise
openedx-atlas==0.5.0
openedx-atlas==0.6.0
# via -r requirements/edx/base.txt
openedx-blockstore==1.4.0
# via -r requirements/edx/base.txt
openedx-calc==3.0.1
# via -r requirements/edx/base.txt
openedx-django-pyfs==3.4.0
openedx-django-pyfs==3.4.1
# via
# -r requirements/edx/base.txt
# lti-consumer-xblock
@@ -928,8 +929,10 @@ openedx-learning==0.4.4
openedx-mongodbproxy==0.2.0
# via -r requirements/edx/base.txt
optimizely-sdk==4.1.1
# via -r requirements/edx/base.txt
ora2==6.0.29
# via
# -c requirements/edx/../constraints.txt
# -r requirements/edx/base.txt
ora2==6.0.30
# via -r requirements/edx/base.txt
packaging==23.2
# via
@@ -969,7 +972,7 @@ picobox==4.0.0
# via sphinxcontrib-openapi
piexif==1.1.3
# via -r requirements/edx/base.txt
pillow==10.1.0
pillow==10.2.0
# via
# -r requirements/edx/base.txt
# edx-enterprise
@@ -987,11 +990,11 @@ polib==1.2.0
# via
# -r requirements/edx/base.txt
# edx-i18n-tools
prompt-toolkit==3.0.42
prompt-toolkit==3.0.43
# via
# -r requirements/edx/base.txt
# click-repl
psutil==5.9.6
psutil==5.9.8
# via
# -r requirements/edx/base.txt
# edx-django-utils
@@ -1009,7 +1012,7 @@ pycparser==2.21
# via
# -r requirements/edx/base.txt
# cffi
pycryptodomex==3.19.0
pycryptodomex==3.20.0
# via
# -r requirements/edx/base.txt
# edx-proctoring
@@ -1096,13 +1099,13 @@ python-dateutil==2.8.2
# olxcleaner
# ora2
# xblock
python-ipware==2.0.0
python-ipware==2.0.1
# via
# -r requirements/edx/base.txt
# django-ipware
python-memcached==1.59
python-memcached==1.62
# via -r requirements/edx/base.txt
python-slugify==8.0.1
python-slugify==8.0.2
# via
# -r requirements/edx/base.txt
# code-annotations
@@ -1149,20 +1152,20 @@ pyyaml==6.0.1
# edx-i18n-tools
# sphinxcontrib-openapi
# xblock
random2==1.0.1
random2==1.0.2
# via -r requirements/edx/base.txt
recommender-xblock==2.0.1
recommender-xblock==2.1.1
# via -r requirements/edx/base.txt
redis==5.0.1
# via
# -r requirements/edx/base.txt
# walrus
referencing==0.32.0
referencing==0.32.1
# via
# -r requirements/edx/base.txt
# jsonschema
# jsonschema-specifications
regex==2023.10.3
regex==2023.12.25
# via
# -r requirements/edx/base.txt
# nltk
@@ -1190,11 +1193,12 @@ requests==2.31.0
# snowflake-connector-python
# social-auth-core
# sphinx
# xblock-google-drive
requests-oauthlib==1.3.1
# via
# -r requirements/edx/base.txt
# social-auth-core
rpds-py==0.13.2
rpds-py==0.17.1
# via
# -r requirements/edx/base.txt
# jsonschema
@@ -1213,7 +1217,7 @@ rules==3.3
# edx-enterprise
# edx-proctoring
# openedx-learning
s3transfer==0.8.2
s3transfer==0.10.0
# via
# -r requirements/edx/base.txt
# boto3
@@ -1268,7 +1272,6 @@ six==1.16.0
# py2neo
# pyjwkest
# python-dateutil
# python-memcached
# sphinxcontrib-httpdomain
slumber==0.7.1
# via
@@ -1280,7 +1283,7 @@ smmap==5.0.1
# via gitdb
snowballstemmer==2.2.0
# via sphinx
snowflake-connector-python==3.6.0
snowflake-connector-python==3.7.0
# via
# -r requirements/edx/base.txt
# edx-enterprise
@@ -1398,7 +1401,7 @@ typing-extensions==4.9.0
# pydata-sphinx-theme
# pylti1p3
# snowflake-connector-python
tzdata==2023.3
tzdata==2023.4
# via
# -r requirements/edx/base.txt
# backports-zoneinfo
@@ -1440,7 +1443,7 @@ walrus==0.9.3
# edx-event-bus-redis
watchdog==3.0.0
# via -r requirements/edx/base.txt
wcwidth==0.2.12
wcwidth==0.2.13
# via
# -r requirements/edx/base.txt
# prompt-toolkit
@@ -1466,7 +1469,7 @@ wrapt==1.16.0
# via
# -r requirements/edx/base.txt
# deprecated
xblock[django]==1.9.0
xblock[django]==1.10.0
# via
# -r requirements/edx/base.txt
# acid-xblock
@@ -1483,9 +1486,9 @@ xblock[django]==1.9.0
# xblock-google-drive
# xblock-poll
# xblock-utils
xblock-drag-and-drop-v2==3.3.0
xblock-drag-and-drop-v2==3.4.0
# via -r requirements/edx/base.txt
xblock-google-drive==0.5.0
xblock-google-drive==0.6.1
# via -r requirements/edx/base.txt
xblock-poll==1.13.0
# via -r requirements/edx/base.txt
@@ -1493,7 +1496,6 @@ xblock-utils==4.0.0
# via
# -r requirements/edx/base.txt
# edx-sga
# xblock-google-drive
xmlsec==1.3.13
# via
# -r requirements/edx/base.txt

View File

@@ -20,7 +20,7 @@ libsass==0.10.0
# via
# -c requirements/edx/../constraints.txt
# -r requirements/edx/paver.in
markupsafe==2.1.3
markupsafe==2.1.4
# via -r requirements/edx/paver.in
mock==5.1.0
# via -r requirements/edx/paver.in
@@ -30,7 +30,7 @@ paver==1.3.4
# via -r requirements/edx/paver.in
pbr==6.0.0
# via stevedore
psutil==5.9.6
psutil==5.9.8
# via -r requirements/edx/paver.in
pymemcache==4.0.0
# via -r requirements/edx/paver.in
@@ -39,7 +39,7 @@ pymongo==3.13.0
# -c requirements/edx/../constraints.txt
# -r requirements/edx/paver.in
# edx-opaque-keys
python-memcached==1.59
python-memcached==1.62
# via -r requirements/edx/paver.in
requests==2.31.0
# via -r requirements/edx/paver.in
@@ -47,7 +47,6 @@ six==1.16.0
# via
# libsass
# paver
# python-memcached
stevedore==5.1.0
# via
# -r requirements/edx/paver.in

View File

@@ -4,7 +4,7 @@
#
# make upgrade
#
attrs==23.1.0
attrs==23.2.0
# via
# glom
# jsonschema
@@ -44,9 +44,9 @@ importlib-resources==6.1.1
# via
# jsonschema
# jsonschema-specifications
jsonschema==4.20.0
jsonschema==4.21.1
# via semgrep
jsonschema-specifications==2023.11.2
jsonschema-specifications==2023.12.1
# via jsonschema
markdown-it-py==3.0.0
# via rich
@@ -60,7 +60,7 @@ pkgutil-resolve-name==1.3.10
# via jsonschema
pygments==2.17.2
# via rich
referencing==0.32.0
referencing==0.32.1
# via
# jsonschema
# jsonschema-specifications
@@ -68,7 +68,7 @@ requests==2.31.0
# via semgrep
rich==13.7.0
# via semgrep
rpds-py==0.13.2
rpds-py==0.17.1
# via
# jsonschema
# referencing

View File

@@ -31,10 +31,8 @@ aniso8601==9.0.1
# edx-tincan-py35
annotated-types==0.6.0
# via pydantic
anyio==3.7.1
# via
# fastapi
# starlette
anyio==4.2.0
# via starlette
appdirs==1.4.4
# via
# -r requirements/edx/base.txt
@@ -58,7 +56,7 @@ async-timeout==4.0.3
# -r requirements/edx/base.txt
# aiohttp
# redis
attrs==23.1.0
attrs==23.2.0
# via
# -r requirements/edx/base.txt
# aiohttp
@@ -85,7 +83,7 @@ backports-zoneinfo[tzdata]==0.2.1
# celery
# icalendar
# kombu
beautifulsoup4==4.12.2
beautifulsoup4==4.12.3
# via
# -r requirements/edx/base.txt
# -r requirements/edx/testing.in
@@ -106,13 +104,13 @@ bleach[css]==6.1.0
# xblock-poll
boto==2.49.0
# via -r requirements/edx/base.txt
boto3==1.33.12
boto3==1.34.28
# via
# -r requirements/edx/base.txt
# django-ses
# fs-s3fs
# ora2
botocore==1.33.12
botocore==1.34.28
# via
# -r requirements/edx/base.txt
# boto3
@@ -210,7 +208,7 @@ coreschema==0.0.4
# -r requirements/edx/base.txt
# coreapi
# drf-yasg
coverage[toml]==7.3.2
coverage[toml]==7.4.0
# via
# -r requirements/edx/coverage.txt
# pytest-cov
@@ -237,7 +235,7 @@ cssutils==2.9.0
# via
# -r requirements/edx/base.txt
# pynliner
ddt==1.7.0
ddt==1.7.1
# via -r requirements/edx/testing.in
defusedxml==0.7.1
# via
@@ -250,7 +248,7 @@ deprecated==1.2.14
# via
# -r requirements/edx/base.txt
# jwcrypto
diff-cover==8.0.1
diff-cover==8.0.3
# via -r requirements/edx/coverage.txt
dill==0.3.7
# via pylint
@@ -326,6 +324,7 @@ django==3.2.23
# openedx-learning
# ora2
# super-csv
# xblock-google-drive
# xss-utils
django-appconf==1.0.6
# via
@@ -376,12 +375,12 @@ django-filter==23.5
# edx-enterprise
# lti-consumer-xblock
# openedx-blockstore
django-ipware==6.0.2
django-ipware==6.0.3
# via
# -r requirements/edx/base.txt
# edx-enterprise
# edx-proctoring
django-js-asset==2.1.0
django-js-asset==2.2.0
# via
# -r requirements/edx/base.txt
# django-mptt
@@ -424,7 +423,7 @@ django-object-actions==4.2.0
# via
# -r requirements/edx/base.txt
# edx-enterprise
django-pipeline==2.1.0
django-pipeline==3.0.0
# via -r requirements/edx/base.txt
django-ratelimit==4.1.0
# via -r requirements/edx/base.txt
@@ -501,11 +500,11 @@ drf-jwt==1.19.2
# via
# -r requirements/edx/base.txt
# edx-drf-extensions
drf-nested-routers==0.93.4
drf-nested-routers==0.93.5
# via
# -r requirements/edx/base.txt
# openedx-blockstore
drf-spectacular==0.27.0
drf-spectacular==0.27.1
# via -r requirements/edx/base.txt
drf-yasg==1.21.5
# via
@@ -524,7 +523,7 @@ edx-auth-backends==4.2.0
# via
# -r requirements/edx/base.txt
# openedx-blockstore
edx-braze-client==0.1.8
edx-braze-client==0.2.1
# via
# -r requirements/edx/base.txt
# edx-enterprise
@@ -552,7 +551,7 @@ edx-django-release-util==1.3.0
# openedx-blockstore
edx-django-sites-extensions==4.0.2
# via -r requirements/edx/base.txt
edx-django-utils==5.9.0
edx-django-utils==5.10.1
# via
# -r requirements/edx/base.txt
# django-config-models
@@ -568,7 +567,7 @@ edx-django-utils==5.9.0
# openedx-blockstore
# ora2
# super-csv
edx-drf-extensions==10.0.0
edx-drf-extensions==10.1.0
# via
# -r requirements/edx/base.txt
# edx-completion
@@ -580,7 +579,7 @@ edx-drf-extensions==10.0.0
# edx-when
# edxval
# openedx-learning
edx-enterprise==4.10.9
edx-enterprise==4.10.11
# via
# -c requirements/edx/../constraints.txt
# -r requirements/edx/base.txt
@@ -632,7 +631,7 @@ edx-rest-api-client==5.6.1
# edx-proctoring
edx-search==3.8.2
# via -r requirements/edx/base.txt
edx-sga==0.23.0
edx-sga==0.23.1
# via -r requirements/edx/base.txt
edx-submissions==3.6.0
# via
@@ -686,11 +685,11 @@ execnet==2.0.2
# via pytest-xdist
factory-boy==3.3.0
# via -r requirements/edx/testing.in
faker==20.1.0
faker==22.5.1
# via factory-boy
fastapi==0.105.0
fastapi==0.109.0
# via pact-python
fastavro==1.9.1
fastavro==1.9.3
# via
# -r requirements/edx/base.txt
# openedx-events
@@ -700,9 +699,9 @@ filelock==3.13.1
# snowflake-connector-python
# tox
# virtualenv
freezegun==1.3.1
freezegun==1.4.0
# via -r requirements/edx/testing.in
frozenlist==1.4.0
frozenlist==1.4.1
# via
# -r requirements/edx/base.txt
# aiohttp
@@ -725,7 +724,7 @@ geoip2==4.8.0
# via -r requirements/edx/base.txt
glob2==0.7
# via -r requirements/edx/base.txt
grimp==3.1
grimp==3.2
# via import-linter
gunicorn==21.2.0
# via -r requirements/edx/base.txt
@@ -749,9 +748,9 @@ idna==3.6
# requests
# snowflake-connector-python
# yarl
import-linter==1.12.1
import-linter==2.0
# via -r requirements/edx/testing.in
importlib-metadata==7.0.0
importlib-metadata==7.0.1
# via
# -r requirements/edx/base.txt
# markdown
@@ -779,7 +778,7 @@ isodate==0.6.1
# via
# -r requirements/edx/base.txt
# python3-saml
isort==5.13.1
isort==5.13.2
# via
# -r requirements/edx/testing.in
# pylint
@@ -787,7 +786,7 @@ itypes==1.2.0
# via
# -r requirements/edx/base.txt
# coreapi
jinja2==3.1.2
jinja2==3.1.3
# via
# -r requirements/edx/base.txt
# -r requirements/edx/coverage.txt
@@ -816,21 +815,21 @@ jsonfield==3.1.0
# edx-submissions
# lti-consumer-xblock
# ora2
jsonschema==4.20.0
jsonschema==4.21.1
# via
# -r requirements/edx/base.txt
# drf-spectacular
# optimizely-sdk
jsonschema-specifications==2023.11.2
jsonschema-specifications==2023.12.1
# via
# -r requirements/edx/base.txt
# jsonschema
jwcrypto==1.5.0
jwcrypto==1.5.1
# via
# -r requirements/edx/base.txt
# django-oauth-toolkit
# pylti1p3
kombu==5.3.4
kombu==5.3.5
# via
# -r requirements/edx/base.txt
# celery
@@ -843,7 +842,7 @@ lazy==1.6
# lti-consumer-xblock
# ora2
# xblock
lazy-object-proxy==1.9.0
lazy-object-proxy==1.10.0
# via astroid
libsass==0.10.0
# via
@@ -853,10 +852,11 @@ loremipsum==1.0.5
# via
# -r requirements/edx/base.txt
# ora2
lti-consumer-xblock==9.8.1
lti-consumer-xblock==9.8.3
# via -r requirements/edx/base.txt
lxml==4.9.3
lxml==4.9.4
# via
# -c requirements/edx/../constraints.txt
# -r requirements/edx/base.txt
# edx-i18n-tools
# edxval
@@ -876,7 +876,6 @@ mako==1.3.0
# acid-xblock
# lti-consumer-xblock
# xblock
# xblock-google-drive
# xblock-utils
markdown==3.3.7
# via
@@ -889,7 +888,7 @@ markey==0.8
# via
# -r requirements/edx/base.txt
# enmerkar-underscore
markupsafe==2.1.3
markupsafe==2.1.4
# via
# -r requirements/edx/base.txt
# -r requirements/edx/coverage.txt
@@ -898,7 +897,7 @@ markupsafe==2.1.3
# mako
# openedx-calc
# xblock
maxminddb==2.5.1
maxminddb==2.5.2
# via
# -r requirements/edx/base.txt
# geoip2
@@ -922,11 +921,11 @@ multidict==6.0.4
# -r requirements/edx/base.txt
# aiohttp
# yarl
mysqlclient==2.2.0
mysqlclient==2.2.1
# via
# -r requirements/edx/base.txt
# openedx-blockstore
newrelic==9.3.0
newrelic==9.6.0
# via
# -r requirements/edx/base.txt
# edx-django-utils
@@ -957,13 +956,13 @@ openai==0.28.1
# -c requirements/edx/../constraints.txt
# -r requirements/edx/base.txt
# edx-enterprise
openedx-atlas==0.5.0
openedx-atlas==0.6.0
# via -r requirements/edx/base.txt
openedx-blockstore==1.4.0
# via -r requirements/edx/base.txt
openedx-calc==3.0.1
# via -r requirements/edx/base.txt
openedx-django-pyfs==3.4.0
openedx-django-pyfs==3.4.1
# via
# -r requirements/edx/base.txt
# lti-consumer-xblock
@@ -988,8 +987,10 @@ openedx-learning==0.4.4
openedx-mongodbproxy==0.2.0
# via -r requirements/edx/base.txt
optimizely-sdk==4.1.1
# via -r requirements/edx/base.txt
ora2==6.0.29
# via
# -c requirements/edx/../constraints.txt
# -r requirements/edx/base.txt
ora2==6.0.30
# via -r requirements/edx/base.txt
packaging==23.2
# via
@@ -1030,7 +1031,7 @@ pgpy==0.6.0
# edx-enterprise
piexif==1.1.3
# via -r requirements/edx/base.txt
pillow==10.1.0
pillow==10.2.0
# via
# -r requirements/edx/base.txt
# edx-enterprise
@@ -1047,7 +1048,7 @@ platformdirs==3.11.0
# snowflake-connector-python
# tox
# virtualenv
pluggy==1.3.0
pluggy==1.4.0
# via
# -r requirements/edx/coverage.txt
# diff-cover
@@ -1058,11 +1059,11 @@ polib==1.2.0
# -r requirements/edx/base.txt
# -r requirements/edx/testing.in
# edx-i18n-tools
prompt-toolkit==3.0.42
prompt-toolkit==3.0.43
# via
# -r requirements/edx/base.txt
# click-repl
psutil==5.9.6
psutil==5.9.8
# via
# -r requirements/edx/base.txt
# edx-django-utils
@@ -1088,15 +1089,15 @@ pycparser==2.21
# via
# -r requirements/edx/base.txt
# cffi
pycryptodomex==3.19.0
pycryptodomex==3.20.0
# via
# -r requirements/edx/base.txt
# edx-proctoring
# lti-consumer-xblock
# pyjwkest
pydantic==2.5.2
pydantic==2.5.3
# via fastapi
pydantic-core==2.14.5
pydantic-core==2.14.6
# via pydantic
pygments==2.17.2
# via
@@ -1184,7 +1185,7 @@ pysrt==1.1.2
# via
# -r requirements/edx/base.txt
# edxval
pytest==7.4.3
pytest==7.4.4
# via
# -r requirements/edx/testing.in
# pylint-pytest
@@ -1226,13 +1227,13 @@ python-dateutil==2.8.2
# olxcleaner
# ora2
# xblock
python-ipware==2.0.0
python-ipware==2.0.1
# via
# -r requirements/edx/base.txt
# django-ipware
python-memcached==1.59
python-memcached==1.62
# via -r requirements/edx/base.txt
python-slugify==8.0.1
python-slugify==8.0.2
# via
# -r requirements/edx/base.txt
# code-annotations
@@ -1278,20 +1279,20 @@ pyyaml==6.0.1
# edx-django-release-util
# edx-i18n-tools
# xblock
random2==1.0.1
random2==1.0.2
# via -r requirements/edx/base.txt
recommender-xblock==2.0.1
recommender-xblock==2.1.1
# via -r requirements/edx/base.txt
redis==5.0.1
# via
# -r requirements/edx/base.txt
# walrus
referencing==0.32.0
referencing==0.32.1
# via
# -r requirements/edx/base.txt
# jsonschema
# jsonschema-specifications
regex==2023.10.3
regex==2023.12.25
# via
# -r requirements/edx/base.txt
# nltk
@@ -1319,11 +1320,12 @@ requests==2.31.0
# slumber
# snowflake-connector-python
# social-auth-core
# xblock-google-drive
requests-oauthlib==1.3.1
# via
# -r requirements/edx/base.txt
# social-auth-core
rpds-py==0.13.2
rpds-py==0.17.1
# via
# -r requirements/edx/base.txt
# jsonschema
@@ -1342,7 +1344,7 @@ rules==3.3
# edx-enterprise
# edx-proctoring
# openedx-learning
s3transfer==0.8.2
s3transfer==0.10.0
# via
# -r requirements/edx/base.txt
# boto3
@@ -1401,7 +1403,6 @@ six==1.16.0
# py2neo
# pyjwkest
# python-dateutil
# python-memcached
slumber==0.7.1
# via
# -r requirements/edx/base.txt
@@ -1410,7 +1411,7 @@ slumber==0.7.1
# edx-rest-api-client
sniffio==1.3.0
# via anyio
snowflake-connector-python==3.6.0
snowflake-connector-python==3.7.0
# via
# -r requirements/edx/base.txt
# edx-enterprise
@@ -1444,7 +1445,7 @@ sqlparse==0.4.4
# openedx-blockstore
staff-graded-xblock==2.2.0
# via -r requirements/edx/base.txt
starlette==0.27.0
starlette==0.35.1
# via fastapi
stevedore==5.1.0
# via
@@ -1499,6 +1500,7 @@ typing-extensions==4.9.0
# via
# -r requirements/edx/base.txt
# annotated-types
# anyio
# asgiref
# astroid
# django-countries
@@ -1516,7 +1518,7 @@ typing-extensions==4.9.0
# snowflake-connector-python
# starlette
# uvicorn
tzdata==2023.3
tzdata==2023.4
# via
# -r requirements/edx/base.txt
# backports-zoneinfo
@@ -1544,7 +1546,7 @@ urllib3==1.26.18
# snowflake-connector-python
user-util==1.0.0
# via -r requirements/edx/base.txt
uvicorn==0.24.0.post1
uvicorn==0.27.0
# via pact-python
vine==5.1.0
# via
@@ -1564,7 +1566,7 @@ walrus==0.9.3
# edx-event-bus-redis
watchdog==3.0.0
# via -r requirements/edx/base.txt
wcwidth==0.2.12
wcwidth==0.2.13
# via
# -r requirements/edx/base.txt
# prompt-toolkit
@@ -1591,7 +1593,7 @@ wrapt==1.16.0
# -r requirements/edx/base.txt
# astroid
# deprecated
xblock[django]==1.9.0
xblock[django]==1.10.0
# via
# -r requirements/edx/base.txt
# acid-xblock
@@ -1608,9 +1610,9 @@ xblock[django]==1.9.0
# xblock-google-drive
# xblock-poll
# xblock-utils
xblock-drag-and-drop-v2==3.3.0
xblock-drag-and-drop-v2==3.4.0
# via -r requirements/edx/base.txt
xblock-google-drive==0.5.0
xblock-google-drive==0.6.1
# via -r requirements/edx/base.txt
xblock-poll==1.13.0
# via -r requirements/edx/base.txt
@@ -1618,7 +1620,6 @@ xblock-utils==4.0.0
# via
# -r requirements/edx/base.txt
# edx-sga
# xblock-google-drive
xmlsec==1.3.13
# via
# -r requirements/edx/base.txt

View File

@@ -10,7 +10,7 @@ click==8.1.6
# via
# -c requirements/constraints.txt
# pip-tools
importlib-metadata==7.0.0
importlib-metadata==7.0.1
# via build
packaging==23.2
# via build

View File

@@ -8,7 +8,7 @@ wheel==0.42.0
# via -r requirements/pip.in
# The following packages are considered to be unsafe in a requirements file:
pip==23.3.1
pip==23.3.2
# via -r requirements/pip.in
setuptools==69.0.2
setuptools==69.0.3
# via -r requirements/pip.in