|
1 | 1 | """ |
2 | 2 | Base setup for Notification Apps and Types. |
3 | 3 | """ |
| 4 | +from typing import Any, Literal, TypedDict, NotRequired |
| 5 | + |
4 | 6 | from django.utils.translation import gettext_lazy as _ |
5 | 7 |
|
6 | 8 | from .email_notifications import EmailCadence |
|
11 | 13 |
|
12 | 14 | FILTER_AUDIT_EXPIRED_USERS_WITH_NO_ROLE = 'filter_audit_expired_users_with_no_role' |
13 | 15 |
|
| 16 | + |
| 17 | +class NotificationType(TypedDict): |
| 18 | + """ |
| 19 | + Define the fields for values in COURSE_NOTIFICATION_TYPES |
| 20 | + """ |
| 21 | + # The notification app associated with this notification. |
| 22 | + # Must be a key in COURSE_NOTIFICATION_APPS. |
| 23 | + notification_app: str |
| 24 | + # Unique identifier for this notification type. |
| 25 | + name: str |
| 26 | + # Mark this as a core notification. |
| 27 | + # When True, user preferences are taken from the notification app's `core_*` configuration, |
| 28 | + # overriding the `web`, `email`, `push`, `email_cadence`, and `non_editable` attributes set here. |
| 29 | + is_core: bool |
| 30 | + # Template string for notification content (see ./docs/templates.md). |
| 31 | + # Wrap in gettext_lazy (_) for translation support. |
| 32 | + content_template: str |
| 33 | + # A map of variable names that can be used in the template, along with their descriptions. |
| 34 | + # The values for these variables are passed to the templates when generating the notification. |
| 35 | + # NOTE: this field is for documentation purposes only; it is not used. |
| 36 | + content_context: dict[str, Any] |
| 37 | + # Template used when delivering notifications via email. |
| 38 | + email_template: str |
| 39 | + filters: list[str] |
| 40 | + |
| 41 | + # All fields below are required unless `is_core` is True. |
| 42 | + # Core notifications take this config from the associated notification app instead (and ignore anything set here). |
| 43 | + |
| 44 | + # Set to True to enable delivery on web. |
| 45 | + web: NotRequired[bool] |
| 46 | + # Set to True to enable delivery via email. |
| 47 | + email: NotRequired[bool] |
| 48 | + # Set to True to enable delivery via push notifications. |
| 49 | + # NOTE: push notifications are not implemented yet |
| 50 | + push: NotRequired[bool] |
| 51 | + # How often email notifications are sent. |
| 52 | + email_cadence: NotRequired[Literal[ |
| 53 | + EmailCadence.DAILY, EmailCadence.WEEKLY, EmailCadence.IMMEDIATELY, EmailCadence.NEVER |
| 54 | + ]] |
| 55 | + # Items in the list represent delivery channels |
| 56 | + # where the user is blocked from changing from what is defined for the notification here |
| 57 | + # (see `web`, `email`, and `push` above). |
| 58 | + non_editable: NotRequired[list[Literal["web", "email", "push"]]] |
| 59 | + # Descriptive information about the notification. |
| 60 | + info: NotRequired[str] |
| 61 | + |
| 62 | + |
| 63 | +# For help defining new notifications, see ./docs/creating_a_new_notification_guide.md |
14 | 64 | COURSE_NOTIFICATION_TYPES = { |
15 | 65 | 'new_comment_on_response': { |
16 | 66 | 'notification_app': 'discussion', |
|
250 | 300 | }, |
251 | 301 | } |
252 | 302 |
|
253 | | -COURSE_NOTIFICATION_APPS = { |
| 303 | + |
| 304 | +class NotificationApp(TypedDict): |
| 305 | + """ |
| 306 | + Define the fields for values in COURSE_NOTIFICATION_APPS |
| 307 | +
|
| 308 | + An instance of this type describes a notification app, |
| 309 | + which is a way of grouping configuration of types of notifications for users. |
| 310 | +
|
| 311 | + Each notification type defined in COURSE_NOTIFICATION_TYPES also references an app. |
| 312 | +
|
| 313 | + Each notification type can also be optionally defined as a core notification. |
| 314 | + In this case, the delivery preferences for that notification are taken |
| 315 | + from the `core_*` fields of the associated notification app. |
| 316 | + """ |
| 317 | + # Set to True to enable this app and linked notification types. |
| 318 | + enabled: bool |
| 319 | + # Description to be displayed about core notifications for this app. |
| 320 | + # This string should be wrapped in the gettext_lazy function (imported as `_`) to support translation. |
| 321 | + core_info: str |
| 322 | + # Set to True to enable delivery for associated core notifications on web. |
| 323 | + core_web: bool |
| 324 | + # Set to True to enable delivery for associated core notifications via emails. |
| 325 | + core_email: bool |
| 326 | + # Set to True to enable delivery for associated core notifications via push notifications. |
| 327 | + # NOTE: push notifications are not implemented yet |
| 328 | + core_push: bool |
| 329 | + # How often email notifications are sent for associated core notifications. |
| 330 | + core_email_cadence: Literal[EmailCadence.DAILY, EmailCadence.WEEKLY, EmailCadence.IMMEDIATELY, EmailCadence.NEVER] |
| 331 | + # Items in the list represent core notification delivery channels |
| 332 | + # where the user is blocked from changing from what is defined for the app here |
| 333 | + # (see `core_web`, `core_email`, and `core_push` above). |
| 334 | + non_editable: list[Literal["web", "email", "push"]] |
| 335 | + |
| 336 | + |
| 337 | +# For help defining new notifications and notification apps, see ./docs/creating_a_new_notification_guide.md |
| 338 | +COURSE_NOTIFICATION_APPS: dict[str, NotificationApp] = { |
254 | 339 | 'discussion': { |
255 | 340 | 'enabled': True, |
256 | 341 | 'core_info': _('Notifications for responses and comments on your posts, and the ones you’re ' |
@@ -391,18 +476,22 @@ class NotificationTypeManager: |
391 | 476 | def __init__(self): |
392 | 477 | self.notification_types = COURSE_NOTIFICATION_TYPES |
393 | 478 |
|
394 | | - def get_notification_types_by_app(self, notification_app): |
| 479 | + def get_notification_types_by_app(self, notification_app: str): |
395 | 480 | """ |
396 | | - Returns notification types for the given notification app. |
| 481 | + Returns notification types for the given notification app name. |
397 | 482 | """ |
398 | 483 | return [ |
399 | 484 | notification_type.copy() for _, notification_type in self.notification_types.items() |
400 | 485 | if notification_type.get('notification_app', None) == notification_app |
401 | 486 | ] |
402 | 487 |
|
403 | | - def get_core_and_non_core_notification_types(self, notification_app): |
| 488 | + def get_core_and_non_core_notification_types( |
| 489 | + self, notification_app: str |
| 490 | + ) -> tuple[NotificationType, NotificationType]: |
404 | 491 | """ |
405 | | - Returns core notification types for the given app name. |
| 492 | + Returns notification types for the given app name, split by core and non core. |
| 493 | +
|
| 494 | + Return type is a tuple of (core_notification_types, non_core_notification_types). |
406 | 495 | """ |
407 | 496 | notification_types = self.get_notification_types_by_app(notification_app) |
408 | 497 | core_notification_types = [] |
@@ -498,7 +587,7 @@ def get_notification_app_preferences(self, email_opt_out=False): |
498 | 587 | return course_notification_preference_config |
499 | 588 |
|
500 | 589 |
|
501 | | -def get_notification_content(notification_type, context): |
| 590 | +def get_notification_content(notification_type: str, context: dict[str, Any]): |
502 | 591 | """ |
503 | 592 | Returns notification content for the given notification type with provided context. |
504 | 593 |
|
|
0 commit comments