Skip to content

Commit bac7e12

Browse files
feat: make email cadence overrideable from settings (#37822)
1 parent b94ccde commit bac7e12

3 files changed

Lines changed: 53 additions & 11 deletions

File tree

openedx/core/djangoapps/notifications/docs/settings.md

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
21
# Notification Configuration Guide
32

43
This guide explains how to override default notification settings for the platform without modifying the core code base. You can customize delivery channels (Web, Email) and behavior for specific notification types or entire notification apps using your Django settings.
@@ -31,24 +30,27 @@ You can only modify the following fields for a notification type. Any other fiel
3130
| `email` | `bool` | Enable/Disable email delivery. |
3231
| `push` | `bool` | Enable/Disable push notifications. |
3332
| `non_editable` | `list` | Prevent users from changing preferences for these channels. |
33+
| `email_cadence` | `str` or `EmailCadence` | How often emails are sent. Allowed values: `Daily`, `Weekly`, `Immediately`, `Never` (or use the `EmailCadence` enum constants).
3434

3535
### Example Configuration
3636

3737
In your `settings.py` (or equivalent):
3838

3939
```python
4040
NOTIFICATION_TYPES_OVERRIDE = {
41-
# CASE 1: Disable emails for new discussion posts by default
41+
# Disable emails for new discussion posts by default and set daily cadence
4242
'new_discussion_post': {
4343
'email': False,
44-
'web': True
44+
'web': True,
45+
'email_cadence': 'Daily',
4546
},
4647

47-
# CASE 2: Force "Course Updates" to be strictly email-only (users cannot disable it)
48+
# Force "Course Updates" to be strictly email-only and deliver immediately
4849
'course_updates': {
4950
'email': True,
5051
'web': False,
51-
'non_editable': ['email'] # User UI will lock the email toggle
52+
'non_editable': ['email'],
53+
'email_cadence': 'Immediately',
5254
}
5355
}
5456

@@ -79,23 +81,25 @@ These keys affect all "Core" notifications belonging to the app.
7981
| `core_email` | `bool` | Enable/Disable email delivery for core events. |
8082
| `core_push` | `bool` | Enable/Disable push delivery for core events. |
8183
| `non_editable` | `list` | Channels users cannot modify (e.g., `['email']`). |
84+
| `core_email_cadence` | `str` or `EmailCadence` | Default email cadence for core notifications. Allowed values: `Daily`, `Weekly`, `Immediately`, `Never` (or use the `EmailCadence` enum constants).
8285

8386
### Example Configuration
8487

8588
```python
8689
NOTIFICATION_APPS_OVERRIDE = {
87-
# CASE: Make all Discussion notifications (comments, responses, etc.)
88-
# Web-only by default to reduce email spam.
90+
# Make all Discussion core notifications Web-only and weekly cadence
8991
'discussion': {
9092
'core_email': False,
9193
'core_web': True,
94+
'core_email_cadence': 'Weekly',
9295
},
9396

94-
# CASE: Ensure Grading notifications are always delivered via email
97+
# Ensure Grading core notifications are always delivered via email immediately
9598
# and users cannot disable them.
9699
'grading': {
97100
'core_email': True,
98-
'non_editable': ['email']
101+
'non_editable': ['email'],
102+
'core_email_cadence': 'Immediately',
99103
}
100104
}
101105

openedx/core/djangoapps/notifications/settings_override.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ def get_notification_types_config() -> Dict[str, Any]:
4545
return _apply_overrides(
4646
default_config=DEFAULT_TYPES,
4747
setting_name='NOTIFICATION_TYPES_OVERRIDE',
48-
allowed_keys={'web', 'email', 'push', 'non_editable'}
48+
allowed_keys={'web', 'email', 'push', 'non_editable', 'email_cadence'}
4949
)
5050

5151

@@ -58,5 +58,5 @@ def get_notification_apps_config() -> Dict[str, Any]:
5858
return _apply_overrides(
5959
default_config=DEFAULT_APPS,
6060
setting_name='NOTIFICATION_APPS_OVERRIDE',
61-
allowed_keys={'core_web', 'core_email', 'core_push', 'non_editable'}
61+
allowed_keys={'core_web', 'core_email', 'core_push', 'non_editable', 'core_email_cadence'}
6262
)

openedx/core/djangoapps/notifications/tests/test_settings_override.py

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,3 +106,41 @@ def test_partial_update_preserves_other_fields(self):
106106
target['email'],
107107
"The 'email' field should be preserved from the default config."
108108
)
109+
110+
@override_settings(NOTIFICATION_TYPES_OVERRIDE={
111+
'new_discussion_post': {
112+
'email_cadence': 'Weekly'
113+
}
114+
})
115+
def test_override_notification_types_email_cadence(self):
116+
"""
117+
Test overriding email_cadence for an existing notification type.
118+
Ensures the override is applied and the module-level default isn't mutated.
119+
"""
120+
config = get_notification_types_config()
121+
target = config['new_discussion_post']
122+
123+
self.assertEqual(
124+
target.get('email_cadence'),
125+
'Weekly',
126+
"The 'email_cadence' setting should be overridden to 'Weekly'."
127+
)
128+
129+
@override_settings(NOTIFICATION_APPS_OVERRIDE={
130+
'discussion': {
131+
'core_email_cadence': 'Immediately'
132+
}
133+
})
134+
def test_override_notification_apps_email_cadence(self):
135+
"""
136+
Test overriding core_email_cadence for an existing notification app.
137+
Ensures the override is applied and the module-level default isn't mutated.
138+
"""
139+
config = get_notification_apps_config()
140+
target_app = config['discussion']
141+
142+
self.assertEqual(
143+
target_app.get('core_email_cadence'),
144+
'Immediately',
145+
"The 'core_email_cadence' setting should be overridden to 'Immediately'."
146+
)

0 commit comments

Comments
 (0)