openedx.core.djangoapps.notifications package#

Subpackages#

Submodules#

openedx.core.djangoapps.notifications.apps module#

Config for notifications app

class openedx.core.djangoapps.notifications.apps.NotificationsConfig(app_name, app_module)#

Bases: AppConfig

Config for notifications app

name = 'openedx.core.djangoapps.notifications'#
ready()#

Import signals

verbose_name = 'Notifications'#

openedx.core.djangoapps.notifications.base_notification module#

Base setup for Notification Apps and Types.

class openedx.core.djangoapps.notifications.base_notification.NotificationAppManager#

Bases: object

Notification app manager

add_core_notification_non_editable(notification_app_attrs, non_editable_channels)#

Adds non_editable for core notification.

add_core_notification_preference(notification_app_attrs, notification_types)#

Adds core notification preference for the given notification app.

get_notification_app_preferences()#

Returns notification app preferences for the given name.

class openedx.core.djangoapps.notifications.base_notification.NotificationPreferenceSyncManager#

Bases: object

Sync Manager for Notification Preferences

static denormalize_preferences(normalized_preferences)#

Denormalizes preference from simplified to normal structure for saving it in database

static normalize_preferences(preferences)#

Normalizes preferences to reduce depth of structure. This simplifies matching of preferences reducing effort to get difference.

static update_preferences(preferences)#

Creates a new preference version from old preferences. New preference is created instead of updating old preference

Steps to update existing user preference
  1. Normalize existing user preference

  2. Normalize default preferences

  3. Iterate over all the apps in default preference, if app_name exists in existing preference, update new preference app enabled value as existing enabled value

  4. Iterate over all preferences, if preference_name exists in existing preference, update new preference values of web, email and push as existing web, email and push respectively

  5. Denormalize new preference

class openedx.core.djangoapps.notifications.base_notification.NotificationTypeManager#

Bases: object

Manager for notification types

get_core_and_non_core_notification_types(notification_app)#

Returns core notification types for the given app name.

static get_non_core_notification_type_preferences(non_core_notification_types)#

Returns non-core notification type preferences for the given notification types.

static get_non_editable_notification_channels(notification_types)#

Returns non_editable notification channels for the given notification types.

get_notification_app_preference(notification_app)#

Returns notification app preferences for the given notification app.

get_notification_types_by_app(notification_app)#

Returns notification types for the given notification app.

openedx.core.djangoapps.notifications.base_notification.get_default_values_of_preference(notification_app, notification_type)#

Returns default preference for notification_type

openedx.core.djangoapps.notifications.base_notification.get_notification_content(notification_type, context)#

Returns notification content for the given notification type with provided context.

openedx.core.djangoapps.notifications.events module#

Events for notification app.

openedx.core.djangoapps.notifications.events.get_user_course_roles(user, course_id)#

Get the user’s roles in the course.

openedx.core.djangoapps.notifications.events.get_user_forums_roles(user, course_id)#

Get the user’s roles in the course forums.

openedx.core.djangoapps.notifications.events.notification_event_context(user, course_id, notification)#
openedx.core.djangoapps.notifications.events.notification_generated_event(user_ids, app_name, notification_type, course_key, content_url, content)#

Emit an event when a notification is generated.

openedx.core.djangoapps.notifications.events.notification_preference_update_event(user, course_id, updated_preference)#

Emit an event when a notification preference is updated.

openedx.core.djangoapps.notifications.events.notification_preferences_viewed_event(request, course_id)#

Emit an event when a user views their notification preferences.

openedx.core.djangoapps.notifications.events.notification_read_event(user, notification, first_read=False)#

Emit an event when a notification app is marked read for a user.

openedx.core.djangoapps.notifications.events.notification_tray_opened_event(user, unseen_notifications_count)#

Emit an event when a notification tray is opened.

openedx.core.djangoapps.notifications.events.notifications_app_all_read_event(user, app_name)#

Emit an event when a notification is read.

openedx.core.djangoapps.notifications.handlers module#

Handlers for notifications

openedx.core.djangoapps.notifications.handlers.course_enrollment_post_save(signal, sender, enrollment, metadata, **kwargs)#

Watches for post_save signal for creates on the CourseEnrollment table. Generate a CourseNotificationPreference if new Enrollment is created

openedx.core.djangoapps.notifications.handlers.generate_user_notifications(signal, sender, notification_data, metadata, **kwargs)#

Watches for USER_NOTIFICATION_REQUESTED signal and calls send_web_notifications task

openedx.core.djangoapps.notifications.handlers.on_user_course_unenrollment(enrollment, **kwargs)#

Removes user notification preference when user un-enrolls from the course

openedx.core.djangoapps.notifications.models module#

Models for notifications

class openedx.core.djangoapps.notifications.models.CourseNotificationPreference(*args, **kwargs)#

Bases: TimeStampedModel

Model to store notification preferences for users

exception DoesNotExist#

Bases: ObjectDoesNotExist

exception MultipleObjectsReturned#

Bases: MultipleObjectsReturned

config_version#

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

course_id#

DO NOT REUSE THIS CLASS. Provided for backwards compatibility only!

A placeholder class that provides a way to set the attribute on the model.

created#

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

get_app_config(app_name) Dict#

Returns the app config for the given app name.

get_core_config(app_name) Dict#

Returns the core config for the given app name.

Sample Response: {

‘email’: True, ‘push’: True, ‘web’: True, ‘info’: ‘comment on post and response on comment’

}

get_next_by_created(*, field=<model_utils.fields.AutoCreatedField: created>, is_next=True, **kwargs)#
get_next_by_modified(*, field=<model_utils.fields.AutoLastModifiedField: modified>, is_next=True, **kwargs)#
get_notification_type_config(app_name, notification_type) Dict#

Returns the notification type config for the given app name and notification type.

Sample Response: {

‘email’: True, ‘push’: True, ‘web’: True, ‘info’: ‘Comment on post’

}

get_notification_types(app_name) Dict#

Returns the notification types for the given app name.

Sample Response: {

‘new_comment_on_post’: {

‘email’: True, ‘push’: True, ‘web’: True, ‘info’: ‘Comment on post’

}, ‘new_response_on_comment’: {

‘email’: True, ‘push’: True, ‘web’: True, ‘info’: ‘Response on comment’

},

get_previous_by_created(*, field=<model_utils.fields.AutoCreatedField: created>, is_next=False, **kwargs)#
get_previous_by_modified(*, field=<model_utils.fields.AutoLastModifiedField: modified>, is_next=False, **kwargs)#
static get_updated_user_course_preferences(user, course_id)#
static get_user_course_preference(user_id, course_id)#

Returns updated courses preferences for a user

get_web_config(app_name, notification_type) bool#

Returns the web config for the given app name and notification type.

id#

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

is_active#

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

is_core(app_name, notification_type) bool#

Returns True if the given notification type is a core notification type.

modified#

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

notification_preference_config#

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

objects = <django.db.models.manager.Manager object>#
user#

Accessor to the related object on the forward side of a many-to-one or one-to-one (via ForwardOneToOneDescriptor subclass) relation.

In the example:

class Child(Model):
    parent = ForeignKey(Parent, related_name='children')

Child.parent is a ForwardManyToOneDescriptor instance.

user_id#
class openedx.core.djangoapps.notifications.models.Notification(*args, **kwargs)#

Bases: TimeStampedModel

Model to store notifications for users

exception DoesNotExist#

Bases: ObjectDoesNotExist

exception MultipleObjectsReturned#

Bases: MultipleObjectsReturned

app_name#

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

property content#

Returns the content for the notification.

content_context#

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

content_url#

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

course_id#

DO NOT REUSE THIS CLASS. Provided for backwards compatibility only!

A placeholder class that provides a way to set the attribute on the model.

created#

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

get_next_by_created(*, field=<model_utils.fields.AutoCreatedField: created>, is_next=True, **kwargs)#
get_next_by_modified(*, field=<model_utils.fields.AutoLastModifiedField: modified>, is_next=True, **kwargs)#
get_previous_by_created(*, field=<model_utils.fields.AutoCreatedField: created>, is_next=False, **kwargs)#
get_previous_by_modified(*, field=<model_utils.fields.AutoLastModifiedField: modified>, is_next=False, **kwargs)#
id#

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

last_read#

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

last_seen#

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

modified#

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

notification_type#

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

objects = <django.db.models.manager.Manager object>#
user#

Accessor to the related object on the forward side of a many-to-one or one-to-one (via ForwardOneToOneDescriptor subclass) relation.

In the example:

class Child(Model):
    parent = ForeignKey(Parent, related_name='children')

Child.parent is a ForwardManyToOneDescriptor instance.

user_id#
openedx.core.djangoapps.notifications.models.get_course_notification_preference_config()#

Returns the course specific notification preference config.

Sample Response: {

‘discussion’: {

‘enabled’: True, ‘not_editable’: {

‘new_comment_on_post’: [‘push’], ‘new_response_on_post’: [‘web’], ‘new_response_on_comment’: [‘web’, ‘push’]

}, ‘notification_types’: {

‘new_comment_on_post’: {

‘email’: True, ‘push’: True, ‘web’: True, ‘info’: ‘Comment on post’

}, ‘new_response_on_comment’: {

‘email’: True, ‘push’: True, ‘web’: True, ‘info’: ‘Response on comment’

}, ‘new_response_on_post’: {

‘email’: True, ‘push’: True, ‘web’: True, ‘info’: ‘New Response on Post’

}, ‘core’: {

‘email’: True, ‘push’: True, ‘web’: True, ‘info’: ‘comment on post and response on comment’

}

}, ‘core_notification_types’: []

}

}

openedx.core.djangoapps.notifications.models.get_course_notification_preference_config_version()#

Returns the notification preference config version.

openedx.core.djangoapps.notifications.models.get_notification_channels()#

Returns the notification channels.

openedx.core.djangoapps.notifications.permissions module#

Permissions for notifications

openedx.core.djangoapps.notifications.permissions.allow_any_authenticated_user()#

Function and class decorator that abstracts the authentication and permission checks for api views. Allows both verified and non-verified users

openedx.core.djangoapps.notifications.serializers module#

Serializers for the notifications API.

class openedx.core.djangoapps.notifications.serializers.CourseOverviewSerializer(*args, **kwargs)#

Bases: ModelSerializer

Serializer for CourseOverview model.

class Meta#

Bases: object

fields = ('id', 'display_name')#
model#

alias of CourseOverview

class openedx.core.djangoapps.notifications.serializers.NotificationCourseEnrollmentSerializer(*args, **kwargs)#

Bases: ModelSerializer

Serializer for CourseEnrollment model.

class Meta#

Bases: object

fields = ('course',)#
model#

alias of CourseEnrollment

class openedx.core.djangoapps.notifications.serializers.NotificationSerializer(*args, **kwargs)#

Bases: ModelSerializer

Serializer for the Notification model.

class Meta#

Bases: object

fields = ('id', 'app_name', 'notification_type', 'content_context', 'content', 'content_url', 'last_read', 'last_seen', 'created')#
model#

alias of Notification

class openedx.core.djangoapps.notifications.serializers.UserCourseNotificationPreferenceSerializer(*args, **kwargs)#

Bases: ModelSerializer

Serializer for user notification preferences.

class Meta#

Bases: object

fields = ('id', 'course_name', 'course_id', 'notification_preference_config')#
model#

alias of CourseNotificationPreference

read_only_fields = ('id', 'course_name', 'course_id')#
write_only_fields = ('notification_preference_config',)#
get_course_name(obj)#

Returns course name from course id.

to_representation(instance)#

Override to_representation to add info of all notification types

class openedx.core.djangoapps.notifications.serializers.UserNotificationPreferenceUpdateSerializer(*args, **kwargs)#

Bases: Serializer

Serializer for user notification preferences update.

update(instance, validated_data)#

Update notification preference config.

validate(attrs)#

Validation for notification preference update form

openedx.core.djangoapps.notifications.tasks module#

This file contains celery tasks for notifications.

openedx.core.djangoapps.notifications.tasks.create_notification_pref_if_not_exists(user_ids: List, preferences: List, course_id: CourseKey)#

Create notification preference if not exist.

openedx.core.djangoapps.notifications.tasks.update_user_preference(preference: CourseNotificationPreference, user_id, course_id)#

Update user preference if config version is changed.

openedx.core.djangoapps.notifications.urls module#

URLs for the notifications API.

openedx.core.djangoapps.notifications.utils module#

Utils function for notifications app

openedx.core.djangoapps.notifications.utils.find_app_in_normalized_apps(app_name, apps_list)#

Returns app preference based on app_name

openedx.core.djangoapps.notifications.utils.find_pref_in_normalized_prefs(pref_name, app_name, prefs_list)#

Returns preference based on preference_name and app_name

openedx.core.djangoapps.notifications.utils.get_list_in_batches(input_list, batch_size)#

Divides the list of objects into list of list of objects each of length batch_size.

openedx.core.djangoapps.notifications.utils.get_show_notifications_tray(user)#

Returns show_notifications_tray as boolean for the courses in which user is enrolled

openedx.core.djangoapps.notifications.views module#

Views for the notifications API.

class openedx.core.djangoapps.notifications.views.CourseEnrollmentListView(**kwargs)#

Bases: ListAPIView

API endpoint to get active CourseEnrollments for requester.

Permissions: User must be authenticated. Response Format (paginated):

{

“next”: (str) url_to_next_page_of_courses, “previous”: (str) url_to_previous_page_of_courses, “count”: (int) total_number_of_courses, “num_pages”: (int) total_number_of_pages, “current_page”: (int) current_page_number, “start”: (int) index_of_first_course_on_page, “results” : [

{
“course”: {

“id”: (int) course_id, “display_name”: (str) course_display_name

},

],

}

Response Error Codes: - 403: The requester cannot access resource.

authentication_classes = (<class 'edx_rest_framework_extensions.auth.jwt.authentication.JwtAuthentication'>, <class 'openedx.core.lib.api.authentication.BearerAuthenticationAllowInactiveUser'>, <class 'edx_rest_framework_extensions.auth.session.authentication.SessionAuthenticationAllowInactiveUser'>)#
get_paginated_response(data)#

Return a response given serialized page data with show_preferences flag.

get_queryset()#

Get the list of items for this view. This must be an iterable, and may be a queryset. Defaults to using self.queryset.

This method should always be used rather than accessing self.queryset directly, as self.queryset gets evaluated only once, and those results are cached for all subsequent requests.

You may want to override this if you need to provide different querysets depending on the incoming request.

(Eg. return a list of items that is specific to the user)

list(request, *args, **kwargs)#

Returns the list of active course enrollments for which ENABLE_NOTIFICATIONS Waffle flag is enabled

permission_classes = (<class 'rest_framework.permissions.IsAuthenticated'>,)#
serializer_class#

alias of NotificationCourseEnrollmentSerializer

class openedx.core.djangoapps.notifications.views.MarkNotificationsSeenAPIView(**kwargs)#

Bases: UpdateAPIView

API view for marking user’s all notifications seen for a provided app_name.

authentication_classes = (<class 'edx_rest_framework_extensions.auth.jwt.authentication.JwtAuthentication'>, <class 'openedx.core.lib.api.authentication.BearerAuthenticationAllowInactiveUser'>, <class 'edx_rest_framework_extensions.auth.session.authentication.SessionAuthenticationAllowInactiveUser'>)#
permission_classes = (<class 'rest_framework.permissions.IsAuthenticated'>,)#
update(request, *args, **kwargs)#

Marks all notifications for the given app name seen for the authenticated user.

Args:

app_name: The name of the app to mark notifications seen for.

Response Format:

A Response object with a 200 OK status code if the notifications were successfully marked seen.

Response Error Codes: - 400: Bad Request status code if the app name is invalid.

class openedx.core.djangoapps.notifications.views.NotificationCountView(**kwargs)#

Bases: APIView

API view for getting the unseen notifications count and show_notification_tray flag for a user.

authentication_classes = (<class 'edx_rest_framework_extensions.auth.jwt.authentication.JwtAuthentication'>, <class 'openedx.core.lib.api.authentication.BearerAuthenticationAllowInactiveUser'>, <class 'edx_rest_framework_extensions.auth.session.authentication.SessionAuthenticationAllowInactiveUser'>)#
get(request)#

Get the unseen notifications count and show_notification_tray flag for a user.

Permissions: User must be authenticated. Response Format: ```json {

“show_notifications_tray”: (bool) show_notifications_tray, “count”: (int) total_number_of_unseen_notifications, “count_by_app_name”: {

(str) app_name: (int) number_of_unseen_notifications, …

}, “notification_expiry_days”: 60

}#

Response Error Codes: - 403: The requester cannot access resource.

permission_classes = (<class 'rest_framework.permissions.IsAuthenticated'>,)#
class openedx.core.djangoapps.notifications.views.NotificationListAPIView(**kwargs)#

Bases: ListAPIView

API view for listing notifications for a user.

Permissions: User must be authenticated. Response Format (paginated):

{
“results”[
{

“id”: (int) notification_id, “app_name”: (str) app_name, “notification_type”: (str) notification_type, “content”: (str) content, “content_context”: (dict) content_context, “content_url”: (str) content_url, “last_read”: (datetime) last_read, “last_seen”: (datetime) last_seen

], “count”: (int) total_number_of_notifications, “next”: (str) url_to_next_page_of_notifications, “previous”: (str) url_to_previous_page_of_notifications, “page_size”: (int) number_of_notifications_per_page,

}

Response Error Codes: - 403: The requester cannot access resource.

authentication_classes = (<class 'edx_rest_framework_extensions.auth.jwt.authentication.JwtAuthentication'>, <class 'openedx.core.lib.api.authentication.BearerAuthenticationAllowInactiveUser'>, <class 'edx_rest_framework_extensions.auth.session.authentication.SessionAuthenticationAllowInactiveUser'>)#
get_queryset()#

Override the get_queryset method to filter the queryset by app name, request.user and created

permission_classes = (<class 'rest_framework.permissions.IsAuthenticated'>,)#
serializer_class#

alias of NotificationSerializer

class openedx.core.djangoapps.notifications.views.NotificationReadAPIView(**kwargs)#

Bases: APIView

API view for marking user notifications as read, either all notifications or a single notification

authentication_classes = (<class 'edx_rest_framework_extensions.auth.jwt.authentication.JwtAuthentication'>, <class 'openedx.core.lib.api.authentication.BearerAuthenticationAllowInactiveUser'>, <class 'edx_rest_framework_extensions.auth.session.authentication.SessionAuthenticationAllowInactiveUser'>)#
patch(request, *args, **kwargs)#

Marks all notifications or single notification read for the given app name or notification id for the authenticated user.

Requests: PATCH /api/notifications/read/

Parameters:

request (Request) –

The request object containing the app name or notification id. {

”app_name”: (str) app_name, “notification_id”: (int) notification_id

}

Returns: - 200: OK status code if the notification or notifications were successfully marked read. - 400: Bad Request status code if the app name is invalid. - 403: Forbidden status code if the user is not authenticated. - 404: Not Found status code if the notification was not found.

permission_classes = (<class 'rest_framework.permissions.IsAuthenticated'>,)#
class openedx.core.djangoapps.notifications.views.UserNotificationPreferenceView(**kwargs)#

Bases: APIView

Supports retrieving and patching the UserNotificationPreference model.

Example Requests

GET /api/notifications/configurations/{course_id} PATCH /api/notifications/configurations/{course_id}

Example Response: {

‘id’: 1, ‘course_name’: ‘testcourse’, ‘course_id’: ‘course-v1:testorg+testcourse+testrun’, ‘notification_preference_config’: {

‘discussion’: {

‘enabled’: False, ‘core’: {

‘info’: ‘’, ‘web’: False, ‘push’: False, ‘email’: False,

}, ‘notification_types’: {

‘new_post’: {

‘info’: ‘’, ‘web’: False, ‘push’: False, ‘email’: False,

},

}, ‘not_editable’: {},

},

}

}

authentication_classes = (<class 'edx_rest_framework_extensions.auth.jwt.authentication.JwtAuthentication'>, <class 'openedx.core.lib.api.authentication.BearerAuthenticationAllowInactiveUser'>, <class 'edx_rest_framework_extensions.auth.session.authentication.SessionAuthenticationAllowInactiveUser'>)#
get(request, course_key_string)#

Returns notification preference for user for a course.

Parameters:

request (Request): The request object. course_key_string (int): The ID of the course to retrieve notification preference.

Returns:
{

‘id’: 1, ‘course_name’: ‘testcourse’, ‘course_id’: ‘course-v1:testorg+testcourse+testrun’, ‘notification_preference_config’: {

‘discussion’: {

‘enabled’: False, ‘core’: {

‘info’: ‘’, ‘web’: False, ‘push’: False, ‘email’: False,

}, ‘notification_types’: {

‘new_post’: {

‘info’: ‘’, ‘web’: False, ‘push’: False, ‘email’: False,

},

}, ‘not_editable’: {},

},

}

}

patch(request, course_key_string)#

Update an existing user notification preference with the data in the request body.

Parameters:
  • request (Request) – The request object

  • course_key_string (int) – The ID of the course of the notification preference to be updated.

Returns:

The updated preference, serialized using the UserNotificationPreferenceSerializer 404: If the preference does not exist 403: If the user does not have permission to update the preference 400: Validation error

Return type:

200

permission_classes = (<class 'rest_framework.permissions.IsAuthenticated'>,)#

Module contents#