|
| 1 | +# Enrollment by Domain Filter |
| 2 | + |
| 3 | +This OpenEdX extension allows restricting course enrollment based on user email domains. It integrates with the `openedx-filters` framework to automatically validate domains during the enrollment process. |
| 4 | + |
| 5 | +## Features |
| 6 | + |
| 7 | +- **Automatic Domain Filtering**: Blocks enrollment for users whose email domains are not in the allowed list |
| 8 | +- **Course-Level Configuration**: Enable/disable filtering per course via Advanced Settings |
| 9 | +- **Simple Domain Management**: Import domains via command or manage through Django Admin |
| 10 | +- **Custom Error Messages**: Configure personalized error messages at course or list level |
| 11 | +- **Instructor Override**: Preserves compatibility with manual enrollment allowlists |
| 12 | + |
| 13 | +## Quick Start |
| 14 | + |
| 15 | + |
| 16 | +### 1. Configure OpenEdX Filters |
| 17 | +Add to your Tutor plugin configuration: |
| 18 | + |
| 19 | +```python |
| 20 | +from tutor import hooks |
| 21 | + |
| 22 | +hooks.Filters.ENV_PATCHES.add_item( |
| 23 | + ( |
| 24 | + "openedx-lms-common-settings", |
| 25 | + """ |
| 26 | +OPEN_EDX_FILTERS_CONFIG = { |
| 27 | + "org.openedx.learning.course.enrollment.started.v1": { |
| 28 | + "fail_silently": False, |
| 29 | + "pipeline": [ |
| 30 | + "nau_openedx_extensions.enrollment_by_domain.domain_filter.FilterEnrollmentByAllowedList" |
| 31 | + ] |
| 32 | + } |
| 33 | +} |
| 34 | +""" |
| 35 | + ) |
| 36 | +) |
| 37 | +``` |
| 38 | + |
| 39 | + |
| 40 | +### 2. Create Domain List |
| 41 | +```bash |
| 42 | +# Basic import with minimal options |
| 43 | +python manage.py lms import_enrollment_domains example_domains.txt university-partners |
| 44 | +``` |
| 45 | +> [!NOTE] You must use the files relative or absolute path, example: ../extra/nau-openedx-extensions/nau_openedx_extensions/enrollment_by_domain/example_domains.txt |
| 46 | +
|
| 47 | + |
| 48 | +### 3. Configure Course |
| 49 | +In **Studio** → **Advanced Settings** → **Other Course Settings**: |
| 50 | +```json |
| 51 | +{ |
| 52 | + "filter_enrollment_allowed_list_code": "university-partners" |
| 53 | +} |
| 54 | +``` |
| 55 | + |
| 56 | +## Domain Management |
| 57 | + |
| 58 | +### Import Command Syntax |
| 59 | +```bash |
| 60 | +python manage.py lms import_enrollment_domains <file.txt> <list-code> [options] |
| 61 | +``` |
| 62 | + |
| 63 | +### Command Options |
| 64 | + |
| 65 | +| Option | Description | |
| 66 | +|--------|-------------| |
| 67 | +| `--description "text"` | List description | |
| 68 | +| `--custom-message "text"` | Custom error message | |
| 69 | + |
| 70 | +### Domain File Format |
| 71 | +```txt |
| 72 | +# University domains (comments start with #) |
| 73 | +university.edu |
| 74 | +student.university.edu |
| 75 | +faculty.university.edu |
| 76 | +
|
| 77 | +# Partner institutions |
| 78 | +partner.org |
| 79 | +collaborator.ac.uk |
| 80 | +alumni.university.edu |
| 81 | +
|
| 82 | +# Empty lines and comments are ignored |
| 83 | +``` |
| 84 | + |
| 85 | +## Usage Examples |
| 86 | + |
| 87 | +### Basic Usage |
| 88 | +```bash |
| 89 | +# Simple domain import |
| 90 | +python manage.py lms import_enrollment_domains domains.txt list-code |
| 91 | + |
| 92 | +# With description |
| 93 | +python manage.py lms import_enrollment_domains domains.txt list-code --description "Partner universities" |
| 94 | + |
| 95 | +# With custom error message |
| 96 | +python manage.py lms import_enrollment_domains domains.txt list-code --custom-message "Contact admissions@university.edu for access" |
| 97 | + |
| 98 | +# Full configuration |
| 99 | +python manage.py lms import_enrollment_domains domains.txt list-code --description "Partner universities" --custom-message "Only partner university students can enroll" |
| 100 | +``` |
| 101 | + |
| 102 | +### Example 1: University Partners |
| 103 | +```bash |
| 104 | +# txt file |
| 105 | +# Main universities |
| 106 | +university.edu |
| 107 | +partneruniv.edu |
| 108 | +college.edu |
| 109 | + |
| 110 | +# Student domains |
| 111 | +students.university.edu |
| 112 | +alumni.university.edu |
| 113 | + |
| 114 | + |
| 115 | +# Import domains |
| 116 | +python manage.py lms import_enrollment_domains university_domains.txt university-partners --description "Partner universities" --custom-message "Only students from partner universities can enroll. Contact admissions@university.edu for assistance." |
| 117 | +``` |
| 118 | + |
| 119 | +**Course Configuration in Studio:** |
| 120 | +```json |
| 121 | +{ |
| 122 | + "filter_enrollment_allowed_list_code": "university-partners" |
| 123 | +} |
| 124 | +``` |
| 125 | + |
| 126 | +### Example 2: Corporate Training Program |
| 127 | +```bash |
| 128 | +# Create corporate domains .txt file |
| 129 | +# Primary companies |
| 130 | +company.com |
| 131 | +corporation.org |
| 132 | +business.net |
| 133 | + |
| 134 | +# Subsidiaries |
| 135 | +subsidiary1.company.com |
| 136 | +subsidiary2.company.com |
| 137 | + |
| 138 | + |
| 139 | +# Import corporate domains |
| 140 | +python manage.py lms import_enrollment_domains corporate_domains.txt corporate-training --description "Corporate training participants" --custom-message "This course is restricted to employees of partner companies." |
| 141 | +``` |
| 142 | + |
| 143 | +### Example 3: Multiple Domain Lists |
| 144 | +```bash |
| 145 | +# University partners list |
| 146 | +python manage.py lms import_enrollment_domains university_domains.txt uni-partners --description "University partners" |
| 147 | + |
| 148 | +# Corporate partners list |
| 149 | +python manage.py lms import_enrollment_domains corporate_domains.txt corp-partners --description "Corporate partners" |
| 150 | + |
| 151 | +# Alumni program list |
| 152 | +python manage.py lms import_enrollment_domains alumni_domains.txt alumni-program --description "Alumni program participants" |
| 153 | +``` |
| 154 | + |
| 155 | +### Example 4: Adding More Domains |
| 156 | +```bash |
| 157 | +# Add new domains to existing list |
| 158 | +python manage.py lms import_enrollment_domains additional_partners.txt university-partners |
| 159 | + |
| 160 | +# Update existing list with new description and message |
| 161 | +python manage.py lms import_enrollment_domains updated_domains.txt university-partners --description "Updated partner list" --custom-message "New enrollment policy applies" |
| 162 | +``` |
| 163 | + |
| 164 | +**Note**: The command only adds new domains. Existing domains are preserved and duplicates are automatically skipped. |
| 165 | + |
| 166 | +## Course Configuration |
| 167 | + |
| 168 | +### Enable Filter for a Course |
| 169 | + |
| 170 | +1. Go to **Studio** → **Settings** → **Advanced Settings** |
| 171 | +2. Find **"Other Course Settings"** or add new field |
| 172 | +3. Add configuration: |
| 173 | + |
| 174 | +```json |
| 175 | +{ |
| 176 | + "filter_enrollment_allowed_list_code": "your-list-code" |
| 177 | +} |
| 178 | +``` |
| 179 | + |
| 180 | +### Custom Error Messages |
| 181 | + |
| 182 | +**Option 1: List-level message (affects all courses using this list)** |
| 183 | +```bash |
| 184 | +python manage.py lms import_enrollment_domains domains.txt my-list --custom-message "Contact support@example.com for enrollment assistance." |
| 185 | +``` |
| 186 | + |
| 187 | +**Option 2: Course-level message (overrides list message for this course)** |
| 188 | +```json |
| 189 | +{ |
| 190 | + "filter_enrollment_allowed_list_code": "my-list", |
| 191 | + "filter_enrollment_by_domain_custom_exception_message": "This course is restricted to university partners only." |
| 192 | +} |
| 193 | +``` |
| 194 | + |
| 195 | +If the custom exception message is not defined, it will use a default message |
| 196 | + |
| 197 | +### Priority Order for Error Messages |
| 198 | +1. **Course-level custom message** (from Advanced Settings) |
| 199 | +2. **List-level custom message** (from import command or Django admin) |
| 200 | +3. **Default message**: "You can't enroll on this course because your email domain is not allowed. If you think this is an error, contact the course support." |
| 201 | + |
| 202 | + |
| 203 | +## Command Output Examples |
| 204 | + |
| 205 | +### New List Creation |
| 206 | +``` |
| 207 | +============================================================ |
| 208 | + IMPORT SUMMARY: university-partners |
| 209 | +============================================================ |
| 210 | + Created new allowed list |
| 211 | +
|
| 212 | + Domain Statistics: |
| 213 | + Domains in file: 8 |
| 214 | + Domains to add: 8 |
| 215 | + Domains unchanged: 0 |
| 216 | + Import completed successfully! |
| 217 | + Added: 8 domains |
| 218 | + Total domains in list: 8 |
| 219 | +============================================================ |
| 220 | +``` |
| 221 | + |
| 222 | +### Adding to Existing List |
| 223 | +``` |
| 224 | +============================================================ |
| 225 | + IMPORT SUMMARY: university-partners |
| 226 | +============================================================ |
| 227 | + Found existing allowed list |
| 228 | +
|
| 229 | + Domain Statistics: |
| 230 | + Domains in file: 10 |
| 231 | + Domains to add: 2 |
| 232 | + Domains unchanged: 8 |
| 233 | +
|
| 234 | + Import completed successfully! |
| 235 | + Added: 2 domains |
| 236 | + Total domains in list: 10 |
| 237 | +============================================================ |
| 238 | +``` |
| 239 | + |
| 240 | +### No Changes Needed |
| 241 | +``` |
| 242 | +============================================================ |
| 243 | + IMPORT SUMMARY: university-partners |
| 244 | +============================================================ |
| 245 | + Found existing allowed list |
| 246 | +
|
| 247 | + Domain Statistics: |
| 248 | + Domains in file: 8 |
| 249 | + Domains to add: 0 |
| 250 | + Domains unchanged: 8 |
| 251 | +
|
| 252 | + No changes needed |
| 253 | + All domains already in list |
| 254 | + Total domains in list: 8 |
| 255 | +============================================================ |
| 256 | +``` |
| 257 | + |
| 258 | +## How It Works |
| 259 | + |
| 260 | +### Filter Activation |
| 261 | +1. **User attempts enrollment** in a course |
| 262 | +2. **OpenEdX Event** `org.openedx.learning.course.enrollment.started.v1` |
| 263 | +3. **Filter checks** if course has `filter_enrollment_allowed_list_code` configured |
| 264 | +4. **If configured**, validates user's email domain against the allowed list |
| 265 | +5. **Blocks enrollment** if domain is not allowed |
| 266 | +6. **Shows custom message** to the user |
| 267 | + |
| 268 | + |
| 269 | + |
| 270 | +## Django Admin Management |
| 271 | + |
| 272 | +Access domain management through Django Admin: |
| 273 | + |
| 274 | +1. Go to `/admin/` |
| 275 | +2. Navigate to **"Enrollment By Domain"** section |
| 276 | +3. Manage **"Enrollment Allowed Lists"** and **"Enrollment Allowed Domains"** |
| 277 | + |
| 278 | +## Best Practices |
| 279 | + |
| 280 | +1. **Use descriptive list codes** (`university-partners`, not `list1`) |
| 281 | +2. **Set custom messages** for better user experience |
| 282 | +3. **Test thoroughly** after configuration changes |
| 283 | + |
0 commit comments