openedx-webhooks 22.0.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- openedx_webhooks/__init__.py +7 -0
- openedx_webhooks/admin.py +40 -0
- openedx_webhooks/apps.py +130 -0
- openedx_webhooks/filters.py +2276 -0
- openedx_webhooks/migrations/0001_initial.py +30 -0
- openedx_webhooks/migrations/0002_webfilter.py +37 -0
- openedx_webhooks/migrations/0003_auto_20230607_1246.py +23 -0
- openedx_webhooks/migrations/0004_auto_20230613_1033.py +28 -0
- openedx_webhooks/migrations/0005_alter_webfilter_event.py +18 -0
- openedx_webhooks/migrations/0006_alter_webfilter_event.py +18 -0
- openedx_webhooks/migrations/0007_alter_webfilter_event.py +18 -0
- openedx_webhooks/migrations/0008_verawood.py +51 -0
- openedx_webhooks/migrations/__init__.py +0 -0
- openedx_webhooks/models.py +185 -0
- openedx_webhooks/receivers.py +434 -0
- openedx_webhooks/settings/__init__.py +0 -0
- openedx_webhooks/settings/cms.py +21 -0
- openedx_webhooks/settings/common.py +191 -0
- openedx_webhooks/settings/test.py +10 -0
- openedx_webhooks/urls.py +10 -0
- openedx_webhooks/utils.py +124 -0
- openedx_webhooks-22.0.0.dist-info/METADATA +415 -0
- openedx_webhooks-22.0.0.dist-info/RECORD +27 -0
- openedx_webhooks-22.0.0.dist-info/WHEEL +5 -0
- openedx_webhooks-22.0.0.dist-info/entry_points.txt +5 -0
- openedx_webhooks-22.0.0.dist-info/licenses/LICENSE.txt +674 -0
- openedx_webhooks-22.0.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# Generated by Django 3.2.19 on 2023-06-01 14:16
|
|
2
|
+
|
|
3
|
+
from django.db import migrations, models
|
|
4
|
+
import django.utils.timezone
|
|
5
|
+
import model_utils.fields
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class Migration(migrations.Migration):
|
|
9
|
+
|
|
10
|
+
initial = True
|
|
11
|
+
|
|
12
|
+
dependencies = [
|
|
13
|
+
]
|
|
14
|
+
|
|
15
|
+
operations = [
|
|
16
|
+
migrations.CreateModel(
|
|
17
|
+
name='Webhook',
|
|
18
|
+
fields=[
|
|
19
|
+
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
|
20
|
+
('created', model_utils.fields.AutoCreatedField(default=django.utils.timezone.now, editable=False, verbose_name='created')),
|
|
21
|
+
('modified', model_utils.fields.AutoLastModifiedField(default=django.utils.timezone.now, editable=False, verbose_name='modified')),
|
|
22
|
+
('event', models.CharField(choices=[('STUDENT_REGISTRATION_COMPLETED', 'Student registration completed'), ('SESSION_LOGIN_COMPLETED', 'Session login completed'), ('COURSE_ENROLLMENT_CREATED', 'Course enrollment created'), ('COURSE_ENROLLMENT_CHANGED', 'Course enrollment changed'), ('COURSE_UNENROLLMENT_COMPLETED', 'Course unenrollment completed'), ('CERTIFICATE_CREATED', 'Certificate created'), ('CERTIFICATE_CHANGED', 'Certificate changed'), ('CERTIFICATE_REVOKED', 'Certificate revoked'), ('COHORT_MEMBERSHIP_CHANGED', 'Cohort membership changed'), ('COURSE_DISCUSSIONS_CHANGED', 'Course discussions changed')], default='', help_text='Event type', max_length=50)),
|
|
23
|
+
('webhook_url', models.URLField(help_text='URL to call when the event is triggered', max_length=255)),
|
|
24
|
+
('enabled', models.BooleanField(default=True, verbose_name='Enabled')),
|
|
25
|
+
],
|
|
26
|
+
options={
|
|
27
|
+
'abstract': False,
|
|
28
|
+
},
|
|
29
|
+
),
|
|
30
|
+
]
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# Generated by Django 3.2.19 on 2023-06-07 10:39
|
|
2
|
+
|
|
3
|
+
from django.db import migrations, models
|
|
4
|
+
import django.utils.timezone
|
|
5
|
+
import model_utils.fields
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class Migration(migrations.Migration):
|
|
9
|
+
|
|
10
|
+
dependencies = [
|
|
11
|
+
('openedx_webhooks', '0001_initial'),
|
|
12
|
+
]
|
|
13
|
+
|
|
14
|
+
operations = [
|
|
15
|
+
migrations.CreateModel(
|
|
16
|
+
name='Webfilter',
|
|
17
|
+
fields=[
|
|
18
|
+
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
|
19
|
+
('created', model_utils.fields.AutoCreatedField(default=django.utils.timezone.now, editable=False, verbose_name='created')),
|
|
20
|
+
('modified', model_utils.fields.AutoLastModifiedField(default=django.utils.timezone.now, editable=False, verbose_name='modified')),
|
|
21
|
+
('description', models.TextField(blank=True, default='', help_text='Description')),
|
|
22
|
+
('event', models.CharField(choices=[('StudentRegistrationRequested', 'Student Registration Requested'), ('StudentLoginRequested', 'Student Login Requested'), ('CourseEnrollmentStarted', 'Course Enrollment Started'), ('CourseUnenrollmentStarted', 'Course Unenrollment Started'), ('CertificateCreationRequested', 'Certificate Creation Requested'), ('CertificateRenderStarted', 'Certificate Render Started'), ('CohortChangeRequested', 'Cohort Change Requested'), ('CohortAssignmentRequested', 'Cohort Assignment Requested'), ('Course_aboutRenderStarted', 'Course_about Render Started'), ('DashboardRenderStarted', 'Dashboard Render Started'), ('Veritical_block_childRenderStarted', 'Veritical_block_child Render Started'), ('Veritical_blockRenderCompleted', 'Veritical_block Render Completed')], default='', help_text='Event type', max_length=50)),
|
|
23
|
+
('webhook_url', models.URLField(help_text='URL to call when the event is triggered', max_length=255)),
|
|
24
|
+
('enabled', models.BooleanField(default=True, verbose_name='Enabled')),
|
|
25
|
+
('disable_halt', models.BooleanField(default=False, help_text="Don't stop the process.", verbose_name='Disable halting')),
|
|
26
|
+
('halt_on_4xx', models.BooleanField(default=False, help_text='Halt the process if the server returns a status response of 4xx (client error).', verbose_name='Halt on 4xx')),
|
|
27
|
+
('redirect_on_4xx', models.URLField(blank=True, help_text='URL to redirect on result code 4xx (client error)', max_length=255)),
|
|
28
|
+
('halt_on_5xx', models.BooleanField(default=False, help_text='Halt the process if the server returns a status response of 5xx (server error).', verbose_name='Halt on 4xx')),
|
|
29
|
+
('redirect_on_5xx', models.URLField(blank=True, help_text='URL to redirect on result code 5XX (server error)', max_length=255)),
|
|
30
|
+
('halt_on_request_exception', models.BooleanField(default=False, help_text="Halt the process if the server doesn't response or there is an exception sending the request.", verbose_name='Halt on request exception')),
|
|
31
|
+
('redirect_on_request_exception', models.URLField(blank=True, help_text='URL to redirect on request exception', max_length=255)),
|
|
32
|
+
],
|
|
33
|
+
options={
|
|
34
|
+
'abstract': False,
|
|
35
|
+
},
|
|
36
|
+
),
|
|
37
|
+
]
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# Generated by Django 3.2.19 on 2023-06-07 12:46
|
|
2
|
+
|
|
3
|
+
from django.db import migrations, models
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class Migration(migrations.Migration):
|
|
7
|
+
|
|
8
|
+
dependencies = [
|
|
9
|
+
('openedx_webhooks', '0002_webfilter'),
|
|
10
|
+
]
|
|
11
|
+
|
|
12
|
+
operations = [
|
|
13
|
+
migrations.AddField(
|
|
14
|
+
model_name='webfilter',
|
|
15
|
+
name='disable_filtering',
|
|
16
|
+
field=models.BooleanField(default=False, help_text='Do not update the data with the response of the webhook call.', verbose_name='Disable Filtering'),
|
|
17
|
+
),
|
|
18
|
+
migrations.AlterField(
|
|
19
|
+
model_name='webfilter',
|
|
20
|
+
name='halt_on_5xx',
|
|
21
|
+
field=models.BooleanField(default=False, help_text='Halt the process if the server returns a status response of 5xx (server error).', verbose_name='Halt on 5xx'),
|
|
22
|
+
),
|
|
23
|
+
]
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# Generated by Django 3.2.19 on 2023-06-13 10:33
|
|
2
|
+
|
|
3
|
+
from django.db import migrations, models
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class Migration(migrations.Migration):
|
|
7
|
+
|
|
8
|
+
dependencies = [
|
|
9
|
+
('openedx_webhooks', '0003_auto_20230607_1246'),
|
|
10
|
+
]
|
|
11
|
+
|
|
12
|
+
operations = [
|
|
13
|
+
migrations.AddField(
|
|
14
|
+
model_name='webfilter',
|
|
15
|
+
name='use_www_form_encoding',
|
|
16
|
+
field=models.BooleanField(default=False, help_text='When enabled, data will be sent in form format, instead of JSON', verbose_name='Use WWW form encoding'),
|
|
17
|
+
),
|
|
18
|
+
migrations.AddField(
|
|
19
|
+
model_name='webhook',
|
|
20
|
+
name='use_www_form_encoding',
|
|
21
|
+
field=models.BooleanField(default=False, help_text='When enabled, data will be sent in form format, instead of JSON', verbose_name='Use WWW form encoding'),
|
|
22
|
+
),
|
|
23
|
+
migrations.AlterField(
|
|
24
|
+
model_name='webfilter',
|
|
25
|
+
name='disable_halt',
|
|
26
|
+
field=models.BooleanField(default=False, help_text="Don't stop the process even if the response includes exception data.", verbose_name='Disable halting'),
|
|
27
|
+
),
|
|
28
|
+
]
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# Generated by Django 3.2.19 on 2023-08-07 06:52
|
|
2
|
+
|
|
3
|
+
from django.db import migrations, models
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class Migration(migrations.Migration):
|
|
7
|
+
|
|
8
|
+
dependencies = [
|
|
9
|
+
('openedx_webhooks', '0004_auto_20230613_1033'),
|
|
10
|
+
]
|
|
11
|
+
|
|
12
|
+
operations = [
|
|
13
|
+
migrations.AlterField(
|
|
14
|
+
model_name='webfilter',
|
|
15
|
+
name='event',
|
|
16
|
+
field=models.CharField(choices=[], default='', help_text='Event type', max_length=50),
|
|
17
|
+
),
|
|
18
|
+
]
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# Generated by Django 3.2.19 on 2023-08-08 10:16
|
|
2
|
+
|
|
3
|
+
from django.db import migrations, models
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class Migration(migrations.Migration):
|
|
7
|
+
|
|
8
|
+
dependencies = [
|
|
9
|
+
('openedx_webhooks', '0005_alter_webfilter_event'),
|
|
10
|
+
]
|
|
11
|
+
|
|
12
|
+
operations = [
|
|
13
|
+
migrations.AlterField(
|
|
14
|
+
model_name='webfilter',
|
|
15
|
+
name='event',
|
|
16
|
+
field=models.CharField(choices=[('StudentRegistrationRequested', 'Student Registration Requested'), ('StudentLoginRequested', 'Student Login Requested'), ('CourseEnrollmentStarted', 'Course Enrollment Started'), ('CourseUnenrollmentStarted', 'Course Unenrollment Started'), ('CertificateCreationRequested', 'Certificate Creation Requested'), ('CertificateRenderStarted', 'Certificate Render Started'), ('CohortChangeRequested', 'Cohort Change Requested'), ('CohortAssignmentRequested', 'Cohort Assignment Requested'), ('CourseAboutRenderStarted', 'Course About Render Started'), ('DashboardRenderStarted', 'Dashboard Render Started'), ('VeriticalBlockChildRenderStarted', 'Veritical Block Child Render Started'), ('VeriticalBlockRenderCompleted', 'Veritical Block Render Completed')], default='', help_text='Event type', max_length=50),
|
|
17
|
+
),
|
|
18
|
+
]
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# Generated by Django 3.2.19 on 2023-08-15 14:14
|
|
2
|
+
|
|
3
|
+
from django.db import migrations, models
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class Migration(migrations.Migration):
|
|
7
|
+
|
|
8
|
+
dependencies = [
|
|
9
|
+
('openedx_webhooks', '0006_alter_webfilter_event'),
|
|
10
|
+
]
|
|
11
|
+
|
|
12
|
+
operations = [
|
|
13
|
+
migrations.AlterField(
|
|
14
|
+
model_name='webfilter',
|
|
15
|
+
name='event',
|
|
16
|
+
field=models.CharField(choices=[('StudentRegistrationRequested', 'Student Registration Requested'), ('StudentLoginRequested', 'Student Login Requested'), ('CourseEnrollmentStarted', 'Course Enrollment Started'), ('CourseUnenrollmentStarted', 'Course Unenrollment Started'), ('CertificateCreationRequested', 'Certificate Creation Requested'), ('CertificateRenderStarted', 'Certificate Render Started'), ('CohortChangeRequested', 'Cohort Change Requested'), ('CohortAssignmentRequested', 'Cohort Assignment Requested'), ('CourseAboutRenderStarted', 'Course About Render Started'), ('DashboardRenderStarted', 'Dashboard Render Started')], default='', help_text='Event type', max_length=50),
|
|
17
|
+
),
|
|
18
|
+
]
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
# Generated by Django 5.2.13 on 2026-09-10 03:45
|
|
2
|
+
|
|
3
|
+
from django.db import migrations, models
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
# These values were derived from filter_type strings instead of handler names.
|
|
7
|
+
# Canonical values already in use must remain unchanged.
|
|
8
|
+
EVENT_ALIASES = {
|
|
9
|
+
'StudentSettingsRenderStarted': 'AccountSettingsRenderStarted',
|
|
10
|
+
'XblockRenderStarted': 'RenderXBlockStarted',
|
|
11
|
+
'CourseHomepageUrlCreationStarted': 'CourseHomeUrlCreationStarted',
|
|
12
|
+
'HomeEnrollmentApiRendered': 'CourseEnrollmentAPIRenderStarted',
|
|
13
|
+
'HomeCourserunApiRenderedStarted': 'CourseRunAPIRenderStarted',
|
|
14
|
+
'OraSubmissionViewRenderStarted': 'ORASubmissionViewRenderStarted',
|
|
15
|
+
'IdvPageUrlRequested': 'IDVPageURLRequested',
|
|
16
|
+
'CourseAboutPageUrlRequested': 'CourseAboutPageURLRequested',
|
|
17
|
+
'ScheduleQuerysetRequested': 'ScheduleQuerySetRequested',
|
|
18
|
+
'AuthoringLmsPageUrlRequested': 'LMSPageURLRequested',
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def correct_event_names(apps, schema_editor):
|
|
23
|
+
"""Retain existing endpoint configuration while making its event dispatchable."""
|
|
24
|
+
webfilters = apps.get_model('openedx_webhooks', 'Webfilter')
|
|
25
|
+
for old_name, new_name in EVENT_ALIASES.items():
|
|
26
|
+
webfilters.objects.using(schema_editor.connection.alias).filter(event=old_name).update(event=new_name)
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class Migration(migrations.Migration):
|
|
30
|
+
|
|
31
|
+
dependencies = [
|
|
32
|
+
('openedx_webhooks', '0007_alter_webfilter_event'),
|
|
33
|
+
]
|
|
34
|
+
|
|
35
|
+
operations = [
|
|
36
|
+
migrations.RunPython(correct_event_names, migrations.RunPython.noop),
|
|
37
|
+
migrations.AlterModelOptions(
|
|
38
|
+
name='webfilter',
|
|
39
|
+
options={'ordering': ['pk']},
|
|
40
|
+
),
|
|
41
|
+
migrations.AlterField(
|
|
42
|
+
model_name='webfilter',
|
|
43
|
+
name='event',
|
|
44
|
+
field=models.CharField(choices=[('StudentLoginRequested', 'Student Login Requested'), ('StudentRegistrationRequested', 'Student Registration Requested'), ('AccountSettingsRenderStarted', 'Account Settings Render Started'), ('CourseEnrollmentStarted', 'Course Enrollment Started'), ('CourseUnenrollmentStarted', 'Course Unenrollment Started'), ('CertificateCreationRequested', 'Certificate Creation Requested'), ('CertificateRenderStarted', 'Certificate Render Started'), ('CohortChangeRequested', 'Cohort Change Requested'), ('CohortAssignmentRequested', 'Cohort Assignment Requested'), ('CourseAboutRenderStarted', 'Course About Render Started'), ('DashboardRenderStarted', 'Dashboard Render Started'), ('VerticalBlockChildRenderStarted', 'Vertical Block Child Render Started'), ('CourseEnrollmentQuerysetRequested', 'Course Enrollment Queryset Requested'), ('RenderXBlockStarted', 'Render X Block Started'), ('VerticalBlockRenderCompleted', 'Vertical Block Render Completed'), ('CourseHomeUrlCreationStarted', 'Course Home Url Creation Started'), ('CourseEnrollmentAPIRenderStarted', 'Course Enrollment API Render Started'), ('CourseRunAPIRenderStarted', 'Course Run API Render Started'), ('InstructorDashboardRenderStarted', 'Instructor Dashboard Render Started'), ('ORASubmissionViewRenderStarted', 'ORA Submission View Render Started'), ('IDVPageURLRequested', 'IDV Page URL Requested'), ('CourseAboutPageURLRequested', 'Course About Page URL Requested'), ('ScheduleQuerySetRequested', 'Schedule Query Set Requested'), ('LMSPageURLRequested', 'LMS Page URL Requested'), ('InstructorDashboardTabsRequested', 'Instructor Dashboard Tabs Requested'), ('AccountSettingsReadOnlyFieldsRequested', 'Account Settings Read Only Fields Requested'), ('GradeEventContextRequested', 'Grade Event Context Requested')], default='', help_text='Event type', max_length=50),
|
|
45
|
+
),
|
|
46
|
+
migrations.AlterField(
|
|
47
|
+
model_name='webhook',
|
|
48
|
+
name='event',
|
|
49
|
+
field=models.CharField(choices=[('ROLE_ASSIGNMENT_CREATED', 'Role assignment created'), ('ROLE_ASSIGNMENT_DELETED', 'Role assignment deleted'), ('COURSE_CATALOG_INFO_CHANGED', 'Course catalog info changed'), ('XBLOCK_CREATED', 'Xblock created'), ('XBLOCK_UPDATED', 'Xblock updated'), ('XBLOCK_PUBLISHED', 'Xblock published'), ('XBLOCK_DELETED', 'Xblock deleted'), ('XBLOCK_DUPLICATED', 'Xblock duplicated'), ('COURSE_CERTIFICATE_CONFIG_CHANGED', 'Course certificate config changed'), ('COURSE_CERTIFICATE_CONFIG_DELETED', 'Course certificate config deleted'), ('COURSE_CREATED', 'Course created'), ('CONTENT_LIBRARY_CREATED', 'Content library created'), ('CONTENT_LIBRARY_UPDATED', 'Content library updated'), ('CONTENT_LIBRARY_DELETED', 'Content library deleted'), ('LIBRARY_BLOCK_CREATED', 'Library block created'), ('LIBRARY_BLOCK_UPDATED', 'Library block updated'), ('LIBRARY_BLOCK_DELETED', 'Library block deleted'), ('LIBRARY_BLOCK_PUBLISHED', 'Library block published'), ('CONTENT_OBJECT_TAGS_CHANGED', 'Content object tags changed'), ('CONTENT_OBJECT_ASSOCIATIONS_CHANGED', 'Content object associations changed'), ('LIBRARY_COLLECTION_CREATED', 'Library collection created'), ('LIBRARY_COLLECTION_UPDATED', 'Library collection updated'), ('LIBRARY_COLLECTION_DELETED', 'Library collection deleted'), ('LIBRARY_CONTAINER_CREATED', 'Library container created'), ('LIBRARY_CONTAINER_UPDATED', 'Library container updated'), ('LIBRARY_CONTAINER_DELETED', 'Library container deleted'), ('LIBRARY_CONTAINER_PUBLISHED', 'Library container published'), ('COURSE_IMPORT_COMPLETED', 'Course import completed'), ('COURSE_RERUN_COMPLETED', 'Course rerun completed'), ('STUDENT_REGISTRATION_COMPLETED', 'Student registration completed'), ('SESSION_LOGIN_COMPLETED', 'Session login completed'), ('COURSE_ENROLLMENT_CREATED', 'Course enrollment created'), ('COURSE_ENROLLMENT_CHANGED', 'Course enrollment changed'), ('COURSE_UNENROLLMENT_COMPLETED', 'Course unenrollment completed'), ('CERTIFICATE_CREATED', 'Certificate created'), ('CERTIFICATE_CHANGED', 'Certificate changed'), ('CERTIFICATE_REVOKED', 'Certificate revoked'), ('COHORT_MEMBERSHIP_CHANGED', 'Cohort membership changed'), ('COURSE_DISCUSSIONS_CHANGED', 'Course discussions changed'), ('PROGRAM_CERTIFICATE_REVOKED', 'Program certificate revoked'), ('PROGRAM_CERTIFICATE_AWARDED', 'Program certificate awarded'), ('PERSISTENT_GRADE_SUMMARY_CHANGED', 'Persistent grade summary changed'), ('XBLOCK_SKILL_VERIFIED', 'Xblock skill verified'), ('USER_NOTIFICATION_REQUESTED', 'User notification requested'), ('EXAM_ATTEMPT_SUBMITTED', 'Exam attempt submitted'), ('EXAM_ATTEMPT_REJECTED', 'Exam attempt rejected'), ('EXAM_ATTEMPT_VERIFIED', 'Exam attempt verified'), ('EXAM_ATTEMPT_ERRORED', 'Exam attempt errored'), ('EXAM_ATTEMPT_RESET', 'Exam attempt reset'), ('COURSE_ACCESS_ROLE_ADDED', 'Course access role added'), ('COURSE_ACCESS_ROLE_REMOVED', 'Course access role removed'), ('FORUM_THREAD_CREATED', 'Forum thread created'), ('FORUM_THREAD_RESPONSE_CREATED', 'Forum thread response created'), ('FORUM_RESPONSE_COMMENT_CREATED', 'Forum response comment created'), ('COURSE_NOTIFICATION_REQUESTED', 'Course notification requested'), ('ORA_SUBMISSION_CREATED', 'Ora submission created'), ('COURSE_PASSING_STATUS_UPDATED', 'Course passing status updated'), ('CCX_COURSE_PASSING_STATUS_UPDATED', 'Ccx course passing status updated'), ('BADGE_AWARDED', 'Badge awarded'), ('BADGE_REVOKED', 'Badge revoked'), ('IDV_ATTEMPT_CREATED', 'Idv attempt created'), ('IDV_ATTEMPT_PENDING', 'Idv attempt pending'), ('IDV_ATTEMPT_APPROVED', 'Idv attempt approved'), ('IDV_ATTEMPT_DENIED', 'Idv attempt denied'), ('EXTERNAL_GRADER_SCORE_SUBMITTED', 'External grader score submitted'), ('LTI_PROVIDER_LAUNCH_SUCCESS', 'Lti provider launch success')], default='', help_text='Event type', max_length=50),
|
|
50
|
+
),
|
|
51
|
+
]
|
|
File without changes
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Models for Webhooks.
|
|
3
|
+
|
|
4
|
+
written by: Andrés González
|
|
5
|
+
https://aulasneo.com
|
|
6
|
+
|
|
7
|
+
date: May 2023
|
|
8
|
+
|
|
9
|
+
usage: Django models for Open edX signals webhooks
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
import re
|
|
13
|
+
from types import SimpleNamespace
|
|
14
|
+
|
|
15
|
+
from django.db import models
|
|
16
|
+
from django.utils.translation import gettext_lazy as _
|
|
17
|
+
from model_utils.models import TimeStampedModel
|
|
18
|
+
|
|
19
|
+
from .apps import signals
|
|
20
|
+
from .settings.common import plugin_settings
|
|
21
|
+
|
|
22
|
+
# From https://github.com/openedx/edx-platform/blob/master/docs/guides/hooks/filters.rst#index-of-filters
|
|
23
|
+
fake_settings = SimpleNamespace(OPEN_EDX_FILTERS_CONFIG={})
|
|
24
|
+
|
|
25
|
+
plugin_settings(fake_settings)
|
|
26
|
+
|
|
27
|
+
filters = fake_settings.OPEN_EDX_FILTERS_CONFIG
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class Webhook(TimeStampedModel):
|
|
31
|
+
"""
|
|
32
|
+
Configuration model to set the webhook url for each event.
|
|
33
|
+
|
|
34
|
+
.. no_pii:
|
|
35
|
+
"""
|
|
36
|
+
|
|
37
|
+
signal_list = []
|
|
38
|
+
for signal_app, signal_app_list in signals.items():
|
|
39
|
+
signal_list += signal_app_list
|
|
40
|
+
|
|
41
|
+
# Create a set of pairs like ("COURSE_ENROLLMENT_CREATED", "Course enrollment created")...
|
|
42
|
+
event_list = [
|
|
43
|
+
(signal,
|
|
44
|
+
signal.capitalize().replace("_", " ")) for signal in signal_list
|
|
45
|
+
]
|
|
46
|
+
|
|
47
|
+
event = models.CharField(
|
|
48
|
+
max_length=50,
|
|
49
|
+
blank=False,
|
|
50
|
+
primary_key=False,
|
|
51
|
+
choices=event_list,
|
|
52
|
+
default='',
|
|
53
|
+
unique=False,
|
|
54
|
+
help_text=_("Event type"),
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
webhook_url = models.URLField(
|
|
58
|
+
max_length=255,
|
|
59
|
+
blank=False,
|
|
60
|
+
help_text=_("URL to call when the event is triggered")
|
|
61
|
+
)
|
|
62
|
+
|
|
63
|
+
enabled = models.BooleanField(
|
|
64
|
+
default=True,
|
|
65
|
+
verbose_name=_("Enabled")
|
|
66
|
+
)
|
|
67
|
+
|
|
68
|
+
use_www_form_encoding = models.BooleanField(
|
|
69
|
+
default=False,
|
|
70
|
+
verbose_name=_("Use WWW form encoding"),
|
|
71
|
+
help_text=_("When enabled, data will be sent in form format, instead of JSON")
|
|
72
|
+
)
|
|
73
|
+
|
|
74
|
+
def __str__(self):
|
|
75
|
+
"""
|
|
76
|
+
Get a string representation of this model instance.
|
|
77
|
+
"""
|
|
78
|
+
return f'Webhook for {self.event} to {self.webhook_url}'
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
class Webfilter(TimeStampedModel):
|
|
82
|
+
"""
|
|
83
|
+
Configuration model to set the filter url for each event.
|
|
84
|
+
|
|
85
|
+
.. no_pii:
|
|
86
|
+
"""
|
|
87
|
+
|
|
88
|
+
class Meta:
|
|
89
|
+
"""Apply multiple configured filters in a deterministic order."""
|
|
90
|
+
|
|
91
|
+
ordering = ['pk']
|
|
92
|
+
|
|
93
|
+
# Persist the handler's exact event name, including acronyms and word order.
|
|
94
|
+
filter_list = [
|
|
95
|
+
(name, re.sub(r'(?<=[a-z])(?=[A-Z])|(?<=[A-Z])(?=[A-Z][a-z])', ' ', name))
|
|
96
|
+
for config in filters.values()
|
|
97
|
+
for name in [config['pipeline'][0].rsplit('.', 1)[1].removesuffix('WebFilter')]
|
|
98
|
+
]
|
|
99
|
+
|
|
100
|
+
description = models.TextField(
|
|
101
|
+
help_text="Description",
|
|
102
|
+
blank=True,
|
|
103
|
+
default='',
|
|
104
|
+
)
|
|
105
|
+
|
|
106
|
+
event = models.CharField(
|
|
107
|
+
max_length=50,
|
|
108
|
+
blank=False,
|
|
109
|
+
primary_key=False,
|
|
110
|
+
choices=filter_list,
|
|
111
|
+
default='',
|
|
112
|
+
unique=False,
|
|
113
|
+
help_text=_("Event type"),
|
|
114
|
+
)
|
|
115
|
+
|
|
116
|
+
webhook_url = models.URLField(
|
|
117
|
+
max_length=255,
|
|
118
|
+
blank=False,
|
|
119
|
+
help_text=_("URL to call when the event is triggered")
|
|
120
|
+
)
|
|
121
|
+
|
|
122
|
+
enabled = models.BooleanField(
|
|
123
|
+
default=True,
|
|
124
|
+
verbose_name=_("Enabled")
|
|
125
|
+
)
|
|
126
|
+
|
|
127
|
+
disable_filtering = models.BooleanField(
|
|
128
|
+
default=False,
|
|
129
|
+
verbose_name=_("Disable Filtering"),
|
|
130
|
+
help_text=_("Do not update the data with the response of the webhook call.")
|
|
131
|
+
)
|
|
132
|
+
|
|
133
|
+
disable_halt = models.BooleanField(
|
|
134
|
+
default=False,
|
|
135
|
+
verbose_name=_("Disable halting"),
|
|
136
|
+
help_text=_("Don't stop the process even if the response includes exception data.")
|
|
137
|
+
)
|
|
138
|
+
|
|
139
|
+
halt_on_4xx = models.BooleanField(
|
|
140
|
+
default=False,
|
|
141
|
+
verbose_name=_("Halt on 4xx"),
|
|
142
|
+
help_text=_("Halt the process if the server returns a status response of 4xx (client error).")
|
|
143
|
+
)
|
|
144
|
+
|
|
145
|
+
redirect_on_4xx = models.URLField(
|
|
146
|
+
max_length=255,
|
|
147
|
+
blank=True,
|
|
148
|
+
help_text=_("URL to redirect on result code 4xx (client error)")
|
|
149
|
+
)
|
|
150
|
+
|
|
151
|
+
halt_on_5xx = models.BooleanField(
|
|
152
|
+
default=False,
|
|
153
|
+
verbose_name=_("Halt on 5xx"),
|
|
154
|
+
help_text=_("Halt the process if the server returns a status response of 5xx (server error).")
|
|
155
|
+
)
|
|
156
|
+
|
|
157
|
+
redirect_on_5xx = models.URLField(
|
|
158
|
+
max_length=255,
|
|
159
|
+
blank=True,
|
|
160
|
+
help_text=_("URL to redirect on result code 5XX (server error)")
|
|
161
|
+
)
|
|
162
|
+
|
|
163
|
+
halt_on_request_exception = models.BooleanField(
|
|
164
|
+
default=False,
|
|
165
|
+
verbose_name=_("Halt on request exception"),
|
|
166
|
+
help_text=_("Halt the process if the server doesn't response or there is an exception sending the request.")
|
|
167
|
+
)
|
|
168
|
+
|
|
169
|
+
redirect_on_request_exception = models.URLField(
|
|
170
|
+
max_length=255,
|
|
171
|
+
blank=True,
|
|
172
|
+
help_text=_("URL to redirect on request exception")
|
|
173
|
+
)
|
|
174
|
+
|
|
175
|
+
use_www_form_encoding = models.BooleanField(
|
|
176
|
+
default=False,
|
|
177
|
+
verbose_name=_("Use WWW form encoding"),
|
|
178
|
+
help_text=_("When enabled, data will be sent in form format, instead of JSON")
|
|
179
|
+
)
|
|
180
|
+
|
|
181
|
+
def __str__(self):
|
|
182
|
+
"""
|
|
183
|
+
Get a string representation of this model instance.
|
|
184
|
+
"""
|
|
185
|
+
return f'Webhook filter for {self.event} to {self.webhook_url}'
|