diff --git a/lms/djangoapps/mobile_api/notifications/urls.py b/lms/djangoapps/mobile_api/notifications/urls.py new file mode 100644 index 000000000000..17b970916a47 --- /dev/null +++ b/lms/djangoapps/mobile_api/notifications/urls.py @@ -0,0 +1,10 @@ +from django.urls import path +from .views import GCMDeviceViewSet + + +CREATE_GCM_DEVICE = GCMDeviceViewSet.as_view({'post': 'create'}) + + +urlpatterns = [ + path('create-token/', CREATE_GCM_DEVICE, name='gcmdevice-list'), +] diff --git a/lms/djangoapps/mobile_api/notifications/views.py b/lms/djangoapps/mobile_api/notifications/views.py new file mode 100644 index 000000000000..aeab8c5445c9 --- /dev/null +++ b/lms/djangoapps/mobile_api/notifications/views.py @@ -0,0 +1,50 @@ +from django.conf import settings +from rest_framework import status +from rest_framework.response import Response + +from edx_ace.push_notifications.views import GCMDeviceViewSet as GCMDeviceViewSetBase + +from ..decorators import mobile_view + + +@mobile_view(is_user=True) +class GCMDeviceViewSet(GCMDeviceViewSetBase): + """ + **Use Case** + This endpoint allows clients to register a device for push notifications. + + If the device is already registered, the existing registration will be updated. + If setting PUSH_NOTIFICATIONS_SETTINGS is not configured, the endpoint will return a 501 error. + + **Example Request** + POST /api/mobile/{version}/notifications/create-token/ + **POST Parameters** + The body of the POST request can include the following parameters. + * name (optional) - A name of the device. + * registration_id (required) - The device token of the device. + * device_id (optional) - ANDROID_ID / TelephonyManager.getDeviceId() (always as hex) + * active (optional) - Whether the device is active, default is True. + If False, the device will not receive notifications. + * cloud_message_type (required) - You should choose FCM or GCM. Currently, only FCM is supported. + * application_id (optional) - Opaque application identity, should be filled in for multiple + key/certificate access. + **Example Response** + ```json + { + "id": 1, + "name": "My Device", + "registration_id": "fj3j4", + "device_id": 1234, + "active": true, + "date_created": "2024-04-18T07:39:37.132787Z", + "cloud_message_type": "FCM", + "application_id": "my_app_id" + } + ``` + """ + + def create(self, request, *args, **kwargs): + if not getattr(settings, 'PUSH_NOTIFICATIONS_SETTINGS', None): + return Response('Push notifications are not configured.', status.HTTP_501_NOT_IMPLEMENTED) + + return super().create(request, *args, **kwargs) diff --git a/lms/djangoapps/mobile_api/urls.py b/lms/djangoapps/mobile_api/urls.py index 1ad34ced5de9..c7aacc0b669a 100644 --- a/lms/djangoapps/mobile_api/urls.py +++ b/lms/djangoapps/mobile_api/urls.py @@ -10,5 +10,6 @@ urlpatterns = [ path('users/', include('lms.djangoapps.mobile_api.users.urls')), path('my_user_info', my_user_info, name='user-info'), + path('notifications/', include('lms.djangoapps.mobile_api.notifications.urls')), path('course_info/', include('lms.djangoapps.mobile_api.course_info.urls')), ] diff --git a/openedx/core/djangoapps/ace_common/settings/common.py b/openedx/core/djangoapps/ace_common/settings/common.py index 11bfbce5c59f..58341470ed8d 100644 --- a/openedx/core/djangoapps/ace_common/settings/common.py +++ b/openedx/core/djangoapps/ace_common/settings/common.py @@ -1,11 +1,14 @@ """ Settings for ace_common app. """ +from openedx.core.djangoapps.ace_common.utils import setup_firebase_app ACE_ROUTING_KEY = 'edx.lms.core.default' def plugin_settings(settings): # lint-amnesty, pylint: disable=missing-function-docstring, missing-module-docstring + if 'push_notifications' not in settings.INSTALLED_APPS: + settings.INSTALLED_APPS.append('push_notifications') settings.ACE_ENABLED_CHANNELS = [ 'django_email' ] @@ -22,3 +25,29 @@ def plugin_settings(settings): # lint-amnesty, pylint: disable=missing-function settings.ACE_ROUTING_KEY = ACE_ROUTING_KEY settings.FEATURES['test_django_plugin'] = True + settings.FCM_APP_NAME = 'fcm-edx-platform' + + if getattr(settings, 'FIREBASE_SETUP_STATUS', None) is None: + settings.ACE_CHANNEL_DEFAULT_PUSH = 'push_notification' + + # Note: To local development with Firebase, you must set FIREBASE_CREDENTIALS. + settings.FCM_APP_NAME = 'fcm-edx-platform' + settings.FIREBASE_CREDENTIALS = None + + if firebase_app := setup_firebase_app(settings.FIREBASE_CREDENTIALS, settings.FCM_APP_NAME): + settings.ACE_ENABLED_CHANNELS.append(settings.ACE_CHANNEL_DEFAULT_PUSH) + settings.ACE_ENABLED_POLICIES.append(settings.ACE_CHANNEL_DEFAULT_PUSH) + + settings.PUSH_NOTIFICATIONS_SETTINGS = { + 'CONFIG': 'push_notifications.conf.AppConfig', + 'APPLICATIONS': { + settings.FCM_APP_NAME: { + 'PLATFORM': 'FCM', + 'FIREBASE_APP': firebase_app, + }, + }, + 'UPDATE_ON_DUPLICATE_REG_ID': True, + } + settings.FIREBASE_SETUP_STATUS = True + else: + settings.FIREBASE_SETUP_STATUS = False diff --git a/openedx/core/djangoapps/ace_common/settings/production.py b/openedx/core/djangoapps/ace_common/settings/production.py index cc4da91c18db..b7ac5b12db17 100644 --- a/openedx/core/djangoapps/ace_common/settings/production.py +++ b/openedx/core/djangoapps/ace_common/settings/production.py @@ -1,4 +1,5 @@ """Common environment variables unique to the ace_common plugin.""" +from openedx.core.djangoapps.ace_common.utils import setup_firebase_app def plugin_settings(settings): @@ -26,3 +27,24 @@ def plugin_settings(settings): settings.ACE_CHANNEL_TRANSACTIONAL_EMAIL = settings.ENV_TOKENS.get( 'ACE_CHANNEL_TRANSACTIONAL_EMAIL', settings.ACE_CHANNEL_TRANSACTIONAL_EMAIL ) + settings.FCM_APP_NAME = settings.ENV_TOKENS.get('FCM_APP_NAME', 'fcm-edx-platform') + settings.FIREBASE_CREDENTIALS = settings.ENV_TOKENS.get('FIREBASE_CREDENTIALS', {}) + + if getattr(settings, 'FIREBASE_SETUP_STATUS', None) is None: + if firebase_app := setup_firebase_app(settings.FIREBASE_CREDENTIALS, settings.FCM_APP_NAME): + settings.ACE_ENABLED_CHANNELS.append(settings.ACE_CHANNEL_DEFAULT_PUSH) + settings.ACE_ENABLED_POLICIES.append(settings.ACE_CHANNEL_DEFAULT_PUSH) + + settings.PUSH_NOTIFICATIONS_SETTINGS = { + 'CONFIG': 'push_notifications.conf.AppConfig', + 'APPLICATIONS': { + settings.FCM_APP_NAME: { + 'PLATFORM': 'FCM', + 'FIREBASE_APP': firebase_app, + }, + }, + 'UPDATE_ON_DUPLICATE_REG_ID': True, + } + settings.FIREBASE_SETUP_STATUS = True + else: + settings.FIREBASE_SETUP_STATUS = False diff --git a/openedx/core/djangoapps/ace_common/utils.py b/openedx/core/djangoapps/ace_common/utils.py new file mode 100644 index 000000000000..adf5586dc449 --- /dev/null +++ b/openedx/core/djangoapps/ace_common/utils.py @@ -0,0 +1,20 @@ +""" +Utility functions for edx-ace. +""" +import logging + +log = logging.getLogger(__name__) + + +def setup_firebase_app(firebase_credentials, app_name='fcm-app'): + """ + Returns a Firebase app instance if the Firebase credentials are provided. + """ + try: + import firebase_admin # pylint: disable=import-outside-toplevel + except ImportError: + log.error('Could not import firebase_admin package.') + return + if firebase_credentials: + certificate = firebase_admin.credentials.Certificate(firebase_credentials) + return firebase_admin.initialize_app(certificate, name=app_name) diff --git a/openedx/core/djangoapps/notifications/policies.py b/openedx/core/djangoapps/notifications/policies.py new file mode 100644 index 000000000000..768d05e62efd --- /dev/null +++ b/openedx/core/djangoapps/notifications/policies.py @@ -0,0 +1,41 @@ +"""Policies for the notifications app.""" + +from edx_ace.channel import ChannelType +from edx_ace.policy import Policy, PolicyResult +from opaque_keys.edx.keys import CourseKey + +from .models import CourseNotificationPreference + + +class CoursePushNotificationOptout(Policy): + """ + Course Push Notification optOut Policy. + """ + + def check(self, message): + """ + Check if the user has opted out of push notifications for the given course. + :param message: + :return: + """ + course_ids = message.context.get('course_ids', []) + app_label = message.context.get('app_label') + + if not (app_label or message.context.get('send_push_notification', False)): + return PolicyResult(deny={ChannelType.PUSH}) + + course_keys = [CourseKey.from_string(course_id) for course_id in course_ids] + for course_key in course_keys: + course_notification_preference = CourseNotificationPreference.get_user_course_preference( + message.recipient.lms_user_id, + course_key + ) + push_notification_preference = course_notification_preference.get_notification_type_config( + app_label, + notification_type='push', + ).get('push', False) + + if not push_notification_preference: + return PolicyResult(deny={ChannelType.PUSH}) + + return PolicyResult(deny=frozenset()) diff --git a/requirements/edx/base.txt b/requirements/edx/base.txt index 08008f51b3aa..a1beff142591 100644 --- a/requirements/edx/base.txt +++ b/requirements/edx/base.txt @@ -4,6 +4,12 @@ # # make upgrade # +-e git+https://github.com/jazzband/django-push-notifications.git@906fe52058bad36b6af2bb292fdb9292ccaa94e5#egg=django_push_notifications + # via -r requirements/edx/github.in +-e git+https://github.com/raccoongang/edx-ace.git@mob-develop#egg=edx_ace + # via + # -r requirements/edx/github.in + # -r requirements/edx/kernel.in -e git+https://github.com/anupdhabarde/edx-proctoring-proctortrack.git@31c6c9923a51c903ae83760ecbbac191363aa2a2#egg=edx_proctoring_proctortrack # via -r requirements/edx/github.in acid-xblock==0.3.0 @@ -90,6 +96,10 @@ botocore==1.34.45 # s3transfer bridgekeeper==0.9 # via -r requirements/edx/kernel.in +cachecontrol==0.14.0 + # via firebase-admin +cachetools==5.3.3 + # via google-auth camel-converter[pydantic]==3.1.1 # via meilisearch celery==5.3.6 @@ -196,6 +206,7 @@ django==4.2.10 # django-multi-email-field # django-mysql # django-oauth-toolkit + # django-push-notifications # django-sekizai # django-ses # django-statici18n @@ -411,8 +422,6 @@ drf-yasg==1.21.5 # -c requirements/edx/../constraints.txt # django-user-tasks # edx-api-doc-tools -edx-ace==1.8.0 - # via -r requirements/edx/kernel.in edx-api-doc-tools==1.8.0 # via # -r requirements/edx/kernel.in @@ -572,6 +581,8 @@ fastavro==1.9.4 # via openedx-events filelock==3.13.1 # via snowflake-connector-python +firebase-admin==5.0.0 + # via edx-ace frozenlist==1.4.1 # via # aiohttp @@ -592,6 +603,49 @@ geoip2==4.8.0 # via -r requirements/edx/kernel.in glob2==0.7 # via -r requirements/edx/kernel.in +google-api-core[grpc]==1.34.1 + # via + # firebase-admin + # google-api-python-client + # google-cloud-core + # google-cloud-firestore + # google-cloud-storage +google-api-python-client==2.127.0 + # via firebase-admin +google-auth==2.29.0 + # via + # google-api-core + # google-api-python-client + # google-auth-httplib2 + # google-cloud-core + # google-cloud-firestore + # google-cloud-storage +google-auth-httplib2==0.2.0 + # via google-api-python-client +google-cloud-core==2.4.1 + # via + # google-cloud-firestore + # google-cloud-storage +google-cloud-firestore==2.16.0 + # via firebase-admin +google-cloud-storage==2.14.0 + # via firebase-admin +google-crc32c==1.5.0 + # via + # google-cloud-storage + # google-resumable-media +google-resumable-media==2.7.0 + # via google-cloud-storage +googleapis-common-protos==1.63.0 + # via + # google-api-core + # grpcio-status +grpcio==1.62.2 + # via + # google-api-core + # grpcio-status +grpcio-status==1.48.2 + # via google-api-core gunicorn==22.0.0 # via -r requirements/edx/kernel.in help-tokens==2.4.0 @@ -600,6 +654,10 @@ html5lib==1.1 # via # -r requirements/edx/kernel.in # ora2 +httplib2==0.22.0 + # via + # google-api-python-client + # google-auth-httplib2 icalendar==5.0.11 # via -r requirements/edx/kernel.in idna==3.6 @@ -733,6 +791,8 @@ monotonic==1.6 # py2neo mpmath==1.3.0 # via sympy +msgpack==1.0.8 + # via cachecontrol multidict==6.0.5 # via # aiohttp @@ -850,6 +910,15 @@ polib==1.2.0 # via edx-i18n-tools prompt-toolkit==3.0.43 # via click-repl +proto-plus==1.23.0 + # via google-cloud-firestore +protobuf==3.20.3 + # via + # google-api-core + # google-cloud-firestore + # googleapis-common-protos + # grpcio-status + # proto-plus psutil==5.9.8 # via # -r requirements/edx/paver.txt @@ -859,7 +928,12 @@ py2neo @ https://github.com/overhangio/py2neo/releases/download/2021.2.3/py2neo- # -c requirements/edx/../constraints.txt # -r requirements/edx/bundled.in pyasn1==0.5.1 - # via pgpy + # via + # pgpy + # pyasn1-modules + # rsa +pyasn1-modules==0.4.0 + # via google-auth pycountry==23.12.11 # via -r requirements/edx/kernel.in pycparser==2.21 @@ -921,6 +995,7 @@ pyopenssl==22.0.0 pyparsing==3.1.1 # via # chem + # httplib2 # openedx-calc pyrsistent==0.20.0 # via optimizely-sdk @@ -1005,6 +1080,7 @@ requests==2.31.0 # -r requirements/edx/paver.txt # algoliasearch # analytics-python + # cachecontrol # coreapi # django-oauth-toolkit # edx-bulk-grades @@ -1012,6 +1088,8 @@ requests==2.31.0 # edx-enterprise # edx-rest-api-client # geoip2 + # google-api-core + # google-cloud-storage # mailsnake # meilisearch # openai @@ -1033,6 +1111,8 @@ rpds-py==0.18.0 # via # jsonschema # referencing +rsa==4.9 + # via google-auth ruamel-yaml==0.18.6 # via drf-yasg ruamel-yaml-clib==0.2.8 @@ -1179,6 +1259,7 @@ uritemplate==4.1.1 # coreapi # drf-spectacular # drf-yasg + # google-api-python-client urllib3==1.26.18 # via # -c requirements/edx/../constraints.txt diff --git a/requirements/edx/development.txt b/requirements/edx/development.txt index f02192e91499..a6c67ba9e317 100644 --- a/requirements/edx/development.txt +++ b/requirements/edx/development.txt @@ -4,6 +4,14 @@ # # make upgrade # +-e git+https://github.com/jazzband/django-push-notifications.git@906fe52058bad36b6af2bb292fdb9292ccaa94e5#egg=django_push_notifications + # via + # -r requirements/edx/doc.txt + # -r requirements/edx/testing.txt +-e git+https://github.com/raccoongang/edx-ace.git@mob-develop#egg=edx_ace + # via + # -r requirements/edx/doc.txt + # -r requirements/edx/testing.txt -e git+https://github.com/anupdhabarde/edx-proctoring-proctortrack.git@31c6c9923a51c903ae83760ecbbac191363aa2a2#egg=edx_proctoring_proctortrack # via # -r requirements/edx/doc.txt @@ -166,9 +174,16 @@ build==1.0.3 # via # -r requirements/edx/../pip-tools.txt # pip-tools -cachetools==5.3.2 +cachecontrol==0.14.0 + # via + # -r requirements/edx/doc.txt + # -r requirements/edx/testing.txt + # firebase-admin +cachetools==5.3.3 # via + # -r requirements/edx/doc.txt # -r requirements/edx/testing.txt + # google-auth # tox camel-converter[pydantic]==3.1.1 # via @@ -362,6 +377,7 @@ django==4.2.10 # django-multi-email-field # django-mysql # django-oauth-toolkit + # django-push-notifications # django-sekizai # django-ses # django-statici18n @@ -668,10 +684,6 @@ drf-yasg==1.21.5 # -r requirements/edx/testing.txt # django-user-tasks # edx-api-doc-tools -edx-ace==1.8.0 - # via - # -r requirements/edx/doc.txt - # -r requirements/edx/testing.txt edx-api-doc-tools==1.8.0 # via # -r requirements/edx/doc.txt @@ -914,6 +926,11 @@ filelock==3.13.1 # snowflake-connector-python # tox # virtualenv +firebase-admin==5.0.0 + # via + # -r requirements/edx/doc.txt + # -r requirements/edx/testing.txt + # edx-ace freezegun==1.4.0 # via -r requirements/edx/testing.txt frozenlist==1.4.1 @@ -953,10 +970,83 @@ glob2==0.7 # via # -r requirements/edx/doc.txt # -r requirements/edx/testing.txt +google-api-core[grpc]==1.34.1 + # via + # -r requirements/edx/doc.txt + # -r requirements/edx/testing.txt + # firebase-admin + # google-api-python-client + # google-cloud-core + # google-cloud-firestore + # google-cloud-storage +google-api-python-client==2.127.0 + # via + # -r requirements/edx/doc.txt + # -r requirements/edx/testing.txt + # firebase-admin +google-auth==2.29.0 + # via + # -r requirements/edx/doc.txt + # -r requirements/edx/testing.txt + # google-api-core + # google-api-python-client + # google-auth-httplib2 + # google-cloud-core + # google-cloud-firestore + # google-cloud-storage +google-auth-httplib2==0.2.0 + # via + # -r requirements/edx/doc.txt + # -r requirements/edx/testing.txt + # google-api-python-client +google-cloud-core==2.4.1 + # via + # -r requirements/edx/doc.txt + # -r requirements/edx/testing.txt + # google-cloud-firestore + # google-cloud-storage +google-cloud-firestore==2.16.0 + # via + # -r requirements/edx/doc.txt + # -r requirements/edx/testing.txt + # firebase-admin +google-cloud-storage==2.14.0 + # via + # -r requirements/edx/doc.txt + # -r requirements/edx/testing.txt + # firebase-admin +google-crc32c==1.5.0 + # via + # -r requirements/edx/doc.txt + # -r requirements/edx/testing.txt + # google-cloud-storage + # google-resumable-media +google-resumable-media==2.7.0 + # via + # -r requirements/edx/doc.txt + # -r requirements/edx/testing.txt + # google-cloud-storage +googleapis-common-protos==1.63.0 + # via + # -r requirements/edx/doc.txt + # -r requirements/edx/testing.txt + # google-api-core + # grpcio-status grimp==3.2 # via # -r requirements/edx/testing.txt # import-linter +grpcio==1.62.2 + # via + # -r requirements/edx/doc.txt + # -r requirements/edx/testing.txt + # google-api-core + # grpcio-status +grpcio-status==1.48.2 + # via + # -r requirements/edx/doc.txt + # -r requirements/edx/testing.txt + # google-api-core gunicorn==22.0.0 # via # -r requirements/edx/doc.txt @@ -974,6 +1064,12 @@ html5lib==1.1 # -r requirements/edx/doc.txt # -r requirements/edx/testing.txt # ora2 +httplib2==0.22.0 + # via + # -r requirements/edx/doc.txt + # -r requirements/edx/testing.txt + # google-api-python-client + # google-auth-httplib2 httpretty==1.1.4 # via -r requirements/edx/testing.txt icalendar==5.0.11 @@ -1218,6 +1314,11 @@ mpmath==1.3.0 # -r requirements/edx/doc.txt # -r requirements/edx/testing.txt # sympy +msgpack==1.0.8 + # via + # -r requirements/edx/doc.txt + # -r requirements/edx/testing.txt + # cachecontrol multidict==6.0.5 # via # -r requirements/edx/doc.txt @@ -1431,6 +1532,20 @@ prompt-toolkit==3.0.43 # -r requirements/edx/doc.txt # -r requirements/edx/testing.txt # click-repl +proto-plus==1.23.0 + # via + # -r requirements/edx/doc.txt + # -r requirements/edx/testing.txt + # google-cloud-firestore +protobuf==3.20.3 + # via + # -r requirements/edx/doc.txt + # -r requirements/edx/testing.txt + # google-api-core + # google-cloud-firestore + # googleapis-common-protos + # grpcio-status + # proto-plus psutil==5.9.8 # via # -r requirements/edx/doc.txt @@ -1450,6 +1565,13 @@ pyasn1==0.5.1 # -r requirements/edx/doc.txt # -r requirements/edx/testing.txt # pgpy + # pyasn1-modules + # rsa +pyasn1-modules==0.4.0 + # via + # -r requirements/edx/doc.txt + # -r requirements/edx/testing.txt + # google-auth pycodestyle==2.8.0 # via # -c requirements/edx/../constraints.txt @@ -1580,6 +1702,7 @@ pyparsing==3.1.1 # -r requirements/edx/doc.txt # -r requirements/edx/testing.txt # chem + # httplib2 # openedx-calc pyproject-api==1.6.1 # via @@ -1741,6 +1864,7 @@ requests==2.31.0 # -r requirements/edx/testing.txt # algoliasearch # analytics-python + # cachecontrol # coreapi # django-oauth-toolkit # djangorestframework-stubs @@ -1749,6 +1873,8 @@ requests==2.31.0 # edx-enterprise # edx-rest-api-client # geoip2 + # google-api-core + # google-cloud-storage # mailsnake # meilisearch # openai @@ -1775,6 +1901,11 @@ rpds-py==0.18.0 # -r requirements/edx/testing.txt # jsonschema # referencing +rsa==4.9 + # via + # -r requirements/edx/doc.txt + # -r requirements/edx/testing.txt + # google-auth ruamel-yaml==0.18.6 # via # -r requirements/edx/doc.txt @@ -2102,6 +2233,7 @@ uritemplate==4.1.1 # coreapi # drf-spectacular # drf-yasg + # google-api-python-client urllib3==1.26.18 # via # -c requirements/edx/../constraints.txt diff --git a/requirements/edx/doc.txt b/requirements/edx/doc.txt index fb3b487a8162..f7a805afc772 100644 --- a/requirements/edx/doc.txt +++ b/requirements/edx/doc.txt @@ -4,6 +4,10 @@ # # make upgrade # +-e git+https://github.com/jazzband/django-push-notifications.git@906fe52058bad36b6af2bb292fdb9292ccaa94e5#egg=django_push_notifications + # via -r requirements/edx/base.txt +-e git+https://github.com/raccoongang/edx-ace.git@mob-develop#egg=edx_ace + # via -r requirements/edx/base.txt -e git+https://github.com/anupdhabarde/edx-proctoring-proctortrack.git@31c6c9923a51c903ae83760ecbbac191363aa2a2#egg=edx_proctoring_proctortrack # via -r requirements/edx/base.txt accessible-pygments==0.0.4 @@ -119,6 +123,14 @@ botocore==1.34.45 # s3transfer bridgekeeper==0.9 # via -r requirements/edx/base.txt +cachecontrol==0.14.0 + # via + # -r requirements/edx/base.txt + # firebase-admin +cachetools==5.3.3 + # via + # -r requirements/edx/base.txt + # google-auth camel-converter[pydantic]==3.1.1 # via # -r requirements/edx/base.txt @@ -246,6 +258,7 @@ django==4.2.10 # django-multi-email-field # django-mysql # django-oauth-toolkit + # django-push-notifications # django-sekizai # django-ses # django-statici18n @@ -489,8 +502,6 @@ drf-yasg==1.21.5 # -r requirements/edx/base.txt # django-user-tasks # edx-api-doc-tools -edx-ace==1.8.0 - # via -r requirements/edx/base.txt edx-api-doc-tools==1.8.0 # via # -r requirements/edx/base.txt @@ -660,6 +671,10 @@ filelock==3.13.1 # via # -r requirements/edx/base.txt # snowflake-connector-python +firebase-admin==5.0.0 + # via + # -r requirements/edx/base.txt + # edx-ace frozenlist==1.4.1 # via # -r requirements/edx/base.txt @@ -687,6 +702,67 @@ gitpython==3.1.42 # via -r requirements/edx/doc.in glob2==0.7 # via -r requirements/edx/base.txt +google-api-core[grpc]==1.34.1 + # via + # -r requirements/edx/base.txt + # firebase-admin + # google-api-python-client + # google-cloud-core + # google-cloud-firestore + # google-cloud-storage +google-api-python-client==2.127.0 + # via + # -r requirements/edx/base.txt + # firebase-admin +google-auth==2.29.0 + # via + # -r requirements/edx/base.txt + # google-api-core + # google-api-python-client + # google-auth-httplib2 + # google-cloud-core + # google-cloud-firestore + # google-cloud-storage +google-auth-httplib2==0.2.0 + # via + # -r requirements/edx/base.txt + # google-api-python-client +google-cloud-core==2.4.1 + # via + # -r requirements/edx/base.txt + # google-cloud-firestore + # google-cloud-storage +google-cloud-firestore==2.16.0 + # via + # -r requirements/edx/base.txt + # firebase-admin +google-cloud-storage==2.14.0 + # via + # -r requirements/edx/base.txt + # firebase-admin +google-crc32c==1.5.0 + # via + # -r requirements/edx/base.txt + # google-cloud-storage + # google-resumable-media +google-resumable-media==2.7.0 + # via + # -r requirements/edx/base.txt + # google-cloud-storage +googleapis-common-protos==1.63.0 + # via + # -r requirements/edx/base.txt + # google-api-core + # grpcio-status +grpcio==1.62.2 + # via + # -r requirements/edx/base.txt + # google-api-core + # grpcio-status +grpcio-status==1.48.2 + # via + # -r requirements/edx/base.txt + # google-api-core gunicorn==22.0.0 # via -r requirements/edx/base.txt help-tokens==2.4.0 @@ -695,6 +771,11 @@ html5lib==1.1 # via # -r requirements/edx/base.txt # ora2 +httplib2==0.22.0 + # via + # -r requirements/edx/base.txt + # google-api-python-client + # google-auth-httplib2 icalendar==5.0.11 # via -r requirements/edx/base.txt idna==3.6 @@ -865,6 +946,10 @@ mpmath==1.3.0 # via # -r requirements/edx/base.txt # sympy +msgpack==1.0.8 + # via + # -r requirements/edx/base.txt + # cachecontrol multidict==6.0.5 # via # -r requirements/edx/base.txt @@ -1005,6 +1090,18 @@ prompt-toolkit==3.0.43 # via # -r requirements/edx/base.txt # click-repl +proto-plus==1.23.0 + # via + # -r requirements/edx/base.txt + # google-cloud-firestore +protobuf==3.20.3 + # via + # -r requirements/edx/base.txt + # google-api-core + # google-cloud-firestore + # googleapis-common-protos + # grpcio-status + # proto-plus psutil==5.9.8 # via # -r requirements/edx/base.txt @@ -1017,6 +1114,12 @@ pyasn1==0.5.1 # via # -r requirements/edx/base.txt # pgpy + # pyasn1-modules + # rsa +pyasn1-modules==0.4.0 + # via + # -r requirements/edx/base.txt + # google-auth pycountry==23.12.11 # via -r requirements/edx/base.txt pycparser==2.21 @@ -1095,6 +1198,7 @@ pyparsing==3.1.1 # via # -r requirements/edx/base.txt # chem + # httplib2 # openedx-calc pyrsistent==0.20.0 # via @@ -1191,6 +1295,7 @@ requests==2.31.0 # -r requirements/edx/base.txt # algoliasearch # analytics-python + # cachecontrol # coreapi # django-oauth-toolkit # edx-bulk-grades @@ -1198,6 +1303,8 @@ requests==2.31.0 # edx-enterprise # edx-rest-api-client # geoip2 + # google-api-core + # google-cloud-storage # mailsnake # meilisearch # openai @@ -1221,6 +1328,10 @@ rpds-py==0.18.0 # -r requirements/edx/base.txt # jsonschema # referencing +rsa==4.9 + # via + # -r requirements/edx/base.txt + # google-auth ruamel-yaml==0.18.6 # via # -r requirements/edx/base.txt @@ -1437,6 +1548,7 @@ uritemplate==4.1.1 # coreapi # drf-spectacular # drf-yasg + # google-api-python-client urllib3==1.26.18 # via # -c requirements/edx/../constraints.txt diff --git a/requirements/edx/github.in b/requirements/edx/github.in index ea6d47eec8a0..0d01c506c7a6 100644 --- a/requirements/edx/github.in +++ b/requirements/edx/github.in @@ -90,3 +90,6 @@ # django42 support PR merged but new release is pending. # https://github.com/openedx/edx-platform/issues/33431 -e git+https://github.com/anupdhabarde/edx-proctoring-proctortrack.git@31c6c9923a51c903ae83760ecbbac191363aa2a2#egg=edx_proctoring_proctortrack + +-e git+https://github.com/raccoongang/edx-ace.git@mob-develop#egg=edx_ace +-e git+https://github.com/jazzband/django-push-notifications.git@906fe52058bad36b6af2bb292fdb9292ccaa94e5#egg=django_push_notifications diff --git a/requirements/edx/testing.txt b/requirements/edx/testing.txt index 566bacd6af65..7bf02b869f64 100644 --- a/requirements/edx/testing.txt +++ b/requirements/edx/testing.txt @@ -4,6 +4,10 @@ # # make upgrade # +-e git+https://github.com/jazzband/django-push-notifications.git@906fe52058bad36b6af2bb292fdb9292ccaa94e5#egg=django_push_notifications + # via -r requirements/edx/base.txt +-e git+https://github.com/raccoongang/edx-ace.git@mob-develop#egg=edx_ace + # via -r requirements/edx/base.txt -e git+https://github.com/anupdhabarde/edx-proctoring-proctortrack.git@31c6c9923a51c903ae83760ecbbac191363aa2a2#egg=edx_proctoring_proctortrack # via -r requirements/edx/base.txt acid-xblock==0.3.0 @@ -119,8 +123,15 @@ botocore==1.34.45 # s3transfer bridgekeeper==0.9 # via -r requirements/edx/base.txt -cachetools==5.3.2 - # via tox +cachecontrol==0.14.0 + # via + # -r requirements/edx/base.txt + # firebase-admin +cachetools==5.3.3 + # via + # -r requirements/edx/base.txt + # google-auth + # tox camel-converter[pydantic]==3.1.1 # via # -r requirements/edx/base.txt @@ -275,6 +286,7 @@ django==4.2.10 # django-multi-email-field # django-mysql # django-oauth-toolkit + # django-push-notifications # django-sekizai # django-ses # django-statici18n @@ -513,8 +525,6 @@ drf-yasg==1.21.5 # -r requirements/edx/base.txt # django-user-tasks # edx-api-doc-tools -edx-ace==1.8.0 - # via -r requirements/edx/base.txt edx-api-doc-tools==1.8.0 # via # -r requirements/edx/base.txt @@ -700,6 +710,10 @@ filelock==3.13.1 # snowflake-connector-python # tox # virtualenv +firebase-admin==5.0.0 + # via + # -r requirements/edx/base.txt + # edx-ace freezegun==1.4.0 # via -r requirements/edx/testing.in frozenlist==1.4.1 @@ -725,8 +739,69 @@ geoip2==4.8.0 # via -r requirements/edx/base.txt glob2==0.7 # via -r requirements/edx/base.txt +google-api-core[grpc]==1.34.1 + # via + # -r requirements/edx/base.txt + # firebase-admin + # google-api-python-client + # google-cloud-core + # google-cloud-firestore + # google-cloud-storage +google-api-python-client==2.127.0 + # via + # -r requirements/edx/base.txt + # firebase-admin +google-auth==2.29.0 + # via + # -r requirements/edx/base.txt + # google-api-core + # google-api-python-client + # google-auth-httplib2 + # google-cloud-core + # google-cloud-firestore + # google-cloud-storage +google-auth-httplib2==0.2.0 + # via + # -r requirements/edx/base.txt + # google-api-python-client +google-cloud-core==2.4.1 + # via + # -r requirements/edx/base.txt + # google-cloud-firestore + # google-cloud-storage +google-cloud-firestore==2.16.0 + # via + # -r requirements/edx/base.txt + # firebase-admin +google-cloud-storage==2.14.0 + # via + # -r requirements/edx/base.txt + # firebase-admin +google-crc32c==1.5.0 + # via + # -r requirements/edx/base.txt + # google-cloud-storage + # google-resumable-media +google-resumable-media==2.7.0 + # via + # -r requirements/edx/base.txt + # google-cloud-storage +googleapis-common-protos==1.63.0 + # via + # -r requirements/edx/base.txt + # google-api-core + # grpcio-status grimp==3.2 # via import-linter +grpcio==1.62.2 + # via + # -r requirements/edx/base.txt + # google-api-core + # grpcio-status +grpcio-status==1.48.2 + # via + # -r requirements/edx/base.txt + # google-api-core gunicorn==22.0.0 # via -r requirements/edx/base.txt h11==0.14.0 @@ -737,6 +812,11 @@ html5lib==1.1 # via # -r requirements/edx/base.txt # ora2 +httplib2==0.22.0 + # via + # -r requirements/edx/base.txt + # google-api-python-client + # google-auth-httplib2 httpretty==1.1.4 # via -r requirements/edx/testing.in icalendar==5.0.11 @@ -920,6 +1000,10 @@ mpmath==1.3.0 # via # -r requirements/edx/base.txt # sympy +msgpack==1.0.8 + # via + # -r requirements/edx/base.txt + # cachecontrol multidict==6.0.5 # via # -r requirements/edx/base.txt @@ -1071,6 +1155,18 @@ prompt-toolkit==3.0.43 # via # -r requirements/edx/base.txt # click-repl +proto-plus==1.23.0 + # via + # -r requirements/edx/base.txt + # google-cloud-firestore +protobuf==3.20.3 + # via + # -r requirements/edx/base.txt + # google-api-core + # google-cloud-firestore + # googleapis-common-protos + # grpcio-status + # proto-plus psutil==5.9.8 # via # -r requirements/edx/base.txt @@ -1087,6 +1183,12 @@ pyasn1==0.5.1 # via # -r requirements/edx/base.txt # pgpy + # pyasn1-modules + # rsa +pyasn1-modules==0.4.0 + # via + # -r requirements/edx/base.txt + # google-auth pycodestyle==2.8.0 # via # -c requirements/edx/../constraints.txt @@ -1184,6 +1286,7 @@ pyparsing==3.1.1 # via # -r requirements/edx/base.txt # chem + # httplib2 # openedx-calc pyproject-api==1.6.1 # via tox @@ -1312,6 +1415,7 @@ requests==2.31.0 # -r requirements/edx/base.txt # algoliasearch # analytics-python + # cachecontrol # coreapi # django-oauth-toolkit # edx-bulk-grades @@ -1319,6 +1423,8 @@ requests==2.31.0 # edx-enterprise # edx-rest-api-client # geoip2 + # google-api-core + # google-cloud-storage # mailsnake # meilisearch # openai @@ -1342,6 +1448,10 @@ rpds-py==0.18.0 # -r requirements/edx/base.txt # jsonschema # referencing +rsa==4.9 + # via + # -r requirements/edx/base.txt + # google-auth ruamel-yaml==0.18.6 # via # -r requirements/edx/base.txt @@ -1547,6 +1657,7 @@ uritemplate==4.1.1 # coreapi # drf-spectacular # drf-yasg + # google-api-python-client urllib3==1.26.18 # via # -c requirements/edx/../constraints.txt diff --git a/setup.py b/setup.py index 4bbbe894fc77..188072354fd2 100644 --- a/setup.py +++ b/setup.py @@ -129,7 +129,8 @@ 'discussions_link = openedx.core.djangoapps.discussions.transformers:DiscussionsTopicLinkTransformer', ], "openedx.ace.policy": [ - "bulk_email_optout = lms.djangoapps.bulk_email.policies:CourseEmailOptout" + "bulk_email_optout = lms.djangoapps.bulk_email.policies:CourseEmailOptout", + "bulk_push_notification_optout = openedx.core.djangoapps.notifications.policies:CoursePushNotificationOptout", # lint-amnesty, pylint: disable=line-too-long ], "openedx.call_to_action": [ "personalized_learner_schedules = openedx.features.personalized_learner_schedules.call_to_action:PersonalizedLearnerScheduleCallToAction" # lint-amnesty, pylint: disable=line-too-long