django-webhook-subscriber 0.4.0__py3-none-any.whl → 2.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.
- django_webhook_subscriber/__init__.py +7 -1
- django_webhook_subscriber/admin.py +831 -182
- django_webhook_subscriber/apps.py +3 -20
- django_webhook_subscriber/conf.py +11 -24
- django_webhook_subscriber/delivery.py +414 -159
- django_webhook_subscriber/http.py +51 -0
- django_webhook_subscriber/management/commands/webhook.py +169 -0
- django_webhook_subscriber/management/commands/webhook_cache.py +173 -0
- django_webhook_subscriber/management/commands/webhook_logs.py +226 -0
- django_webhook_subscriber/management/commands/webhook_performance_test.py +469 -0
- django_webhook_subscriber/management/commands/webhook_send.py +96 -0
- django_webhook_subscriber/management/commands/webhook_status.py +139 -0
- django_webhook_subscriber/managers.py +36 -14
- django_webhook_subscriber/migrations/0002_remove_webhookregistry_content_type_and_more.py +192 -0
- django_webhook_subscriber/models.py +291 -114
- django_webhook_subscriber/serializers.py +16 -50
- django_webhook_subscriber/tasks.py +434 -56
- django_webhook_subscriber/tests/factories.py +40 -0
- django_webhook_subscriber/tests/settings.py +27 -8
- django_webhook_subscriber/tests/test_delivery.py +453 -190
- django_webhook_subscriber/tests/test_http.py +32 -0
- django_webhook_subscriber/tests/test_managers.py +26 -37
- django_webhook_subscriber/tests/test_models.py +341 -251
- django_webhook_subscriber/tests/test_serializers.py +22 -56
- django_webhook_subscriber/tests/test_tasks.py +477 -189
- django_webhook_subscriber/tests/test_utils.py +98 -94
- django_webhook_subscriber/utils.py +87 -69
- django_webhook_subscriber/validators.py +53 -0
- django_webhook_subscriber-2.0.0.dist-info/METADATA +774 -0
- django_webhook_subscriber-2.0.0.dist-info/RECORD +38 -0
- django_webhook_subscriber/management/commands/check_webhook_tasks.py +0 -113
- django_webhook_subscriber/management/commands/clean_webhook_logs.py +0 -65
- django_webhook_subscriber/management/commands/test_webhook.py +0 -96
- django_webhook_subscriber/signals.py +0 -152
- django_webhook_subscriber/testing.py +0 -14
- django_webhook_subscriber/tests/test_signals.py +0 -268
- django_webhook_subscriber-0.4.0.dist-info/METADATA +0 -448
- django_webhook_subscriber-0.4.0.dist-info/RECORD +0 -33
- {django_webhook_subscriber-0.4.0.dist-info → django_webhook_subscriber-2.0.0.dist-info}/WHEEL +0 -0
- {django_webhook_subscriber-0.4.0.dist-info → django_webhook_subscriber-2.0.0.dist-info}/licenses/LICENSE +0 -0
- {django_webhook_subscriber-0.4.0.dist-info → django_webhook_subscriber-2.0.0.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
django_webhook_subscriber/__init__.py,sha256=t0izlsRXKHd46fRIwhDv8Cd59tb7MqAQ7DWJRLLWgtw,213
|
|
2
|
+
django_webhook_subscriber/admin.py,sha256=BGFV-1-wymm_qUsOlG0HBUY3rmAqKH59PbKaFEtAEI4,30100
|
|
3
|
+
django_webhook_subscriber/apps.py,sha256=U6GLuMB2xhtvUzn2IsK6rjaxN73LU3fvDoGGO1IZIr4,170
|
|
4
|
+
django_webhook_subscriber/conf.py,sha256=0lFW2L_s_85UIszXnUnnMCdb0iy99WnenPWeixonf-I,1759
|
|
5
|
+
django_webhook_subscriber/delivery.py,sha256=mjNtIMeVsXoVnWfEBmW8WsVDDPYfKcz8HIMkJ40PHjQ,15207
|
|
6
|
+
django_webhook_subscriber/http.py,sha256=0CoK1OMm7lCIJ3zzpNH3cdVuIgDnAB4KUqLRM_KRGQs,1191
|
|
7
|
+
django_webhook_subscriber/managers.py,sha256=w2QZCYs858XMlcI-WSZJ0H8vN_IzpTvu5_H3bmiy7zM,2322
|
|
8
|
+
django_webhook_subscriber/models.py,sha256=IdG0eBE3JPUmPLWqpR62GLtA4xVF8caIU92ourgRzVk,11528
|
|
9
|
+
django_webhook_subscriber/serializers.py,sha256=9QHzlTXvk-PibMSoztaGsDoZkVhCXJkuQMDDTPCKjak,1416
|
|
10
|
+
django_webhook_subscriber/tasks.py,sha256=jlE8Mdor387gcWfHlrMe8OGoegjt2xn8gsVVL8LkHDY,14269
|
|
11
|
+
django_webhook_subscriber/utils.py,sha256=SdogR0VmeMMl7tgl-DD5_4yP7vt3OcgI8IpghoCIVXQ,2950
|
|
12
|
+
django_webhook_subscriber/validators.py,sha256=_qlBi0rS3DaW3jKRhdpnfHzuqupqwaWtiNuZAWpIAkU,1848
|
|
13
|
+
django_webhook_subscriber/management/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
14
|
+
django_webhook_subscriber/management/commands/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
15
|
+
django_webhook_subscriber/management/commands/webhook.py,sha256=p1vHy3-Ux3cfcGRkkFpmkHIfdE17kyWrJatC5mEEDKI,5378
|
|
16
|
+
django_webhook_subscriber/management/commands/webhook_cache.py,sha256=g5bTRWzcJk6xUWCe9mYF8oQHcm1FXsTStY4RZLaFprc,5662
|
|
17
|
+
django_webhook_subscriber/management/commands/webhook_logs.py,sha256=ZBw5JmfEYsV2X6bODq4y3ZeN41-k12tcM73c-sEbLNk,7249
|
|
18
|
+
django_webhook_subscriber/management/commands/webhook_performance_test.py,sha256=8_yb1f57bZHBfmq-Ypj7-h4HYmWTXCTsiawtVZuz-Qw,16096
|
|
19
|
+
django_webhook_subscriber/management/commands/webhook_send.py,sha256=M1G_VnXwjkTw4UKoCbWVExRS18bbIYTbQY7g5Cngud0,3073
|
|
20
|
+
django_webhook_subscriber/management/commands/webhook_status.py,sha256=_s5nTA2NAxvihAXpEP5NguEcCC_uS6RjKhSYxx02ogU,4701
|
|
21
|
+
django_webhook_subscriber/migrations/0001_initial.py,sha256=HZ4CF8U0aoQNMIswHv039HR32eLIEB0rttvcjrAma-Y,4160
|
|
22
|
+
django_webhook_subscriber/migrations/0002_remove_webhookregistry_content_type_and_more.py,sha256=ut1diKCSNAIag_KxZLvUkMLjHEVoD3LW3OOOB87kwP4,9602
|
|
23
|
+
django_webhook_subscriber/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
24
|
+
django_webhook_subscriber/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
25
|
+
django_webhook_subscriber/tests/factories.py,sha256=z3fXJqt_3csAFrvM5qdKwzsVu0v_e72racLvMgejEKA,1277
|
|
26
|
+
django_webhook_subscriber/tests/settings.py,sha256=jBy9X7QhmoQ9hnaJk4WDGWXqpRydpHlrROaXU5t7KZI,825
|
|
27
|
+
django_webhook_subscriber/tests/test_delivery.py,sha256=W7JrNurpTb0TA0JDyumd6UMytaQYPJ6DohS0pDNjyJw,18380
|
|
28
|
+
django_webhook_subscriber/tests/test_http.py,sha256=-zBNRjpYxBDCC5NvWfdYc36aFdzCwN-1p8yuQsLGfz8,1262
|
|
29
|
+
django_webhook_subscriber/tests/test_managers.py,sha256=z_c49z0UjkAnldXy-KU_XoECC66dr7orE77_xFvnM4A,3062
|
|
30
|
+
django_webhook_subscriber/tests/test_models.py,sha256=RHE14IuaMtthiaRZ8g4h2EZ4VilWOrs9UrkArDbvcDg,15209
|
|
31
|
+
django_webhook_subscriber/tests/test_serializers.py,sha256=UuN-cDDmsu8ZFB-aPesffT74Ck6uIuDo9ehkq8y43Mw,1831
|
|
32
|
+
django_webhook_subscriber/tests/test_tasks.py,sha256=wcYlYqrRC9G3C4leEAKrt7x7D1uhlqx9mfwkfQYnb8c,20622
|
|
33
|
+
django_webhook_subscriber/tests/test_utils.py,sha256=zFXDjr81wB8emeJKNjlwA8ezfJTfCMSw46-S2dB_fO0,4279
|
|
34
|
+
django_webhook_subscriber-2.0.0.dist-info/licenses/LICENSE,sha256=Cqe_H97kNjzh70ZIee47TV5t0GQyath_iH2i0Yp47SU,1064
|
|
35
|
+
django_webhook_subscriber-2.0.0.dist-info/METADATA,sha256=tzvYtcH4spdVL7BVftgDOBm_udSa3A3R--NFNcgdxlE,17789
|
|
36
|
+
django_webhook_subscriber-2.0.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
37
|
+
django_webhook_subscriber-2.0.0.dist-info/top_level.txt,sha256=t2_XjlYcTMLR9OfBGdsW0xucs3OeRWrJ7ypETMXqrvw,26
|
|
38
|
+
django_webhook_subscriber-2.0.0.dist-info/RECORD,,
|
|
@@ -1,113 +0,0 @@
|
|
|
1
|
-
"""Check the status of recent webhook deliveries."""
|
|
2
|
-
|
|
3
|
-
from django.core.management.base import BaseCommand
|
|
4
|
-
from django.utils import timezone
|
|
5
|
-
from django.db.models import Q
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
class Command(BaseCommand):
|
|
9
|
-
"""Check the status of recent webhook deliveries.
|
|
10
|
-
|
|
11
|
-
This command checks the status of recent webhook deliveries and
|
|
12
|
-
provides a summary of successful and failed deliveries. It can be
|
|
13
|
-
filtered to show only failed deliveries or all deliveries within a
|
|
14
|
-
specified time period.
|
|
15
|
-
|
|
16
|
-
Usage:
|
|
17
|
-
python manage.py check_webhook_tasks --hours 24
|
|
18
|
-
python manage.py check_webhook_tasks --failed-only
|
|
19
|
-
python manage.py check_webhook_tasks --hours 48 --failed-only
|
|
20
|
-
"""
|
|
21
|
-
|
|
22
|
-
help = 'Check status of recent webhook deliveries'
|
|
23
|
-
|
|
24
|
-
def add_arguments(self, parser):
|
|
25
|
-
parser.add_argument(
|
|
26
|
-
'--hours',
|
|
27
|
-
type=int,
|
|
28
|
-
default=24,
|
|
29
|
-
help='Hours to look back for delivery logs',
|
|
30
|
-
)
|
|
31
|
-
parser.add_argument(
|
|
32
|
-
'--failed-only',
|
|
33
|
-
action='store_true',
|
|
34
|
-
help='Show only failed deliveries',
|
|
35
|
-
)
|
|
36
|
-
|
|
37
|
-
def handle(self, *args, **options):
|
|
38
|
-
hours = options['hours']
|
|
39
|
-
failed_only = options['failed_only']
|
|
40
|
-
|
|
41
|
-
cutoff = timezone.now() - timezone.timedelta(hours=hours)
|
|
42
|
-
|
|
43
|
-
from django_webhook_subscriber.models import WebhookRegistry
|
|
44
|
-
|
|
45
|
-
# Get webhooks with delivery status
|
|
46
|
-
webhooks = WebhookRegistry.objects.all()
|
|
47
|
-
|
|
48
|
-
for webhook in webhooks:
|
|
49
|
-
# Get recent delivery logs
|
|
50
|
-
logs = webhook.delivery_logs.filter(created_at__gte=cutoff)
|
|
51
|
-
|
|
52
|
-
if failed_only:
|
|
53
|
-
logs = logs.filter(
|
|
54
|
-
Q(error_message__isnull=False)
|
|
55
|
-
| Q(response_status__lt=200)
|
|
56
|
-
| Q(response_status__gte=300)
|
|
57
|
-
)
|
|
58
|
-
|
|
59
|
-
if not logs.exists():
|
|
60
|
-
if not failed_only:
|
|
61
|
-
self.stdout.write(f'Webhook: {webhook.name}')
|
|
62
|
-
self.stdout.write(
|
|
63
|
-
' No deliveries in the specified time period.'
|
|
64
|
-
)
|
|
65
|
-
continue
|
|
66
|
-
self.stdout.write(f'Webhook: {webhook.name} ({webhook.endpoint})')
|
|
67
|
-
self.stdout.write(f' Total deliveries: {logs.count()}')
|
|
68
|
-
|
|
69
|
-
# Count successes and failures
|
|
70
|
-
successes = logs.filter(
|
|
71
|
-
error_message__isnull=True,
|
|
72
|
-
response_status__gte=200,
|
|
73
|
-
response_status__lt=300,
|
|
74
|
-
).count()
|
|
75
|
-
|
|
76
|
-
failures = logs.count() - successes
|
|
77
|
-
|
|
78
|
-
if successes > 0:
|
|
79
|
-
self.stdout.write(
|
|
80
|
-
self.style.SUCCESS(f' Successful: {successes}')
|
|
81
|
-
)
|
|
82
|
-
|
|
83
|
-
if failures > 0:
|
|
84
|
-
self.stdout.write(self.style.ERROR(f' Failed: {failures}'))
|
|
85
|
-
|
|
86
|
-
# Show most recent failure
|
|
87
|
-
if failures > 0:
|
|
88
|
-
most_recent = (
|
|
89
|
-
logs.filter(
|
|
90
|
-
Q(error_message__isnull=False)
|
|
91
|
-
| Q(response_status__lt=200)
|
|
92
|
-
| Q(response_status__gte=300)
|
|
93
|
-
)
|
|
94
|
-
.order_by('-created_at')
|
|
95
|
-
.first()
|
|
96
|
-
)
|
|
97
|
-
|
|
98
|
-
self.stdout.write(
|
|
99
|
-
f' Most recent failure at: {most_recent.created_at}'
|
|
100
|
-
)
|
|
101
|
-
if most_recent.error_message:
|
|
102
|
-
self.stdout.write(
|
|
103
|
-
f' Error: {most_recent.error_message}'
|
|
104
|
-
)
|
|
105
|
-
else:
|
|
106
|
-
self.stdout.write(
|
|
107
|
-
f' Status: {most_recent.response_status}'
|
|
108
|
-
)
|
|
109
|
-
self.stdout.write(
|
|
110
|
-
f' Response: {most_recent.response_body[:100]}...'
|
|
111
|
-
)
|
|
112
|
-
|
|
113
|
-
self.stdout.write('')
|
|
@@ -1,65 +0,0 @@
|
|
|
1
|
-
"""Clean up old webhook delivery logs."""
|
|
2
|
-
|
|
3
|
-
from django.core.management.base import BaseCommand
|
|
4
|
-
from django.utils import timezone
|
|
5
|
-
from django.conf import settings
|
|
6
|
-
from datetime import timedelta
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
class Command(BaseCommand):
|
|
10
|
-
"""Clean up old webhook delivery logs.
|
|
11
|
-
|
|
12
|
-
This command deletes webhook delivery logs older than a specified
|
|
13
|
-
number of days. If no number of days is specified, it defaults to
|
|
14
|
-
the value set in the WEBHOOK_SUBSCRIBER_LOG_RETENTION_DAYS setting.
|
|
15
|
-
|
|
16
|
-
Usage:
|
|
17
|
-
python manage.py clean_webhook_logs --days 30
|
|
18
|
-
python manage.py clean_webhook_logs --dry-run
|
|
19
|
-
"""
|
|
20
|
-
|
|
21
|
-
help = 'Clean up old webhook delivery logs'
|
|
22
|
-
|
|
23
|
-
def add_arguments(self, parser):
|
|
24
|
-
parser.add_argument(
|
|
25
|
-
'--days',
|
|
26
|
-
type=int,
|
|
27
|
-
default=None,
|
|
28
|
-
help='Delete logs older than this many days',
|
|
29
|
-
)
|
|
30
|
-
parser.add_argument(
|
|
31
|
-
'--dry-run',
|
|
32
|
-
action='store_true',
|
|
33
|
-
help='Only print what would be deleted without actually deleting',
|
|
34
|
-
)
|
|
35
|
-
|
|
36
|
-
def handle(self, *args, **options):
|
|
37
|
-
# Get retention period from command line or settings
|
|
38
|
-
days = options['days']
|
|
39
|
-
if days is None:
|
|
40
|
-
days = getattr(
|
|
41
|
-
settings, 'WEBHOOK_SUBSCRIBER_LOG_RETENTION_DAYS', 30
|
|
42
|
-
)
|
|
43
|
-
|
|
44
|
-
# Calculate cutoff date
|
|
45
|
-
cutoff_date = timezone.now() - timedelta(days=days)
|
|
46
|
-
|
|
47
|
-
# Get logs to delete
|
|
48
|
-
from django_webhook_subscriber.models import WebhookDeliveryLog
|
|
49
|
-
|
|
50
|
-
logs_to_delete = WebhookDeliveryLog.objects.filter(
|
|
51
|
-
created_at__lt=cutoff_date
|
|
52
|
-
)
|
|
53
|
-
count = logs_to_delete.count()
|
|
54
|
-
|
|
55
|
-
if options['dry_run']:
|
|
56
|
-
self.stdout.write(
|
|
57
|
-
f'Would delete {count} logs older than {cutoff_date}'
|
|
58
|
-
)
|
|
59
|
-
else:
|
|
60
|
-
logs_to_delete.delete()
|
|
61
|
-
self.stdout.write(
|
|
62
|
-
self.style.SUCCESS(
|
|
63
|
-
f'Deleted {count} logs older than {cutoff_date}'
|
|
64
|
-
)
|
|
65
|
-
)
|
|
@@ -1,96 +0,0 @@
|
|
|
1
|
-
"""Test a webhook by sending a test payload to the specified endpoint."""
|
|
2
|
-
|
|
3
|
-
import json
|
|
4
|
-
|
|
5
|
-
from django.core.management.base import BaseCommand, CommandError
|
|
6
|
-
|
|
7
|
-
from django_webhook_subscriber.delivery import deliver_webhook
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
class Command(BaseCommand):
|
|
11
|
-
"""Test a webhook by sending a test payload to the specified endpoint.
|
|
12
|
-
|
|
13
|
-
This command sends a test payload to the specified webhook endpoint
|
|
14
|
-
and displays the response status and body. It can be used to verify
|
|
15
|
-
that the webhook is correctly configured and that the endpoint is
|
|
16
|
-
reachable.
|
|
17
|
-
|
|
18
|
-
Usage:
|
|
19
|
-
python manage.py test_webhook <webhook_id> --event <event_signal>
|
|
20
|
-
python manage.py test_webhook <webhook_id> --payload <custom_payload>
|
|
21
|
-
"""
|
|
22
|
-
|
|
23
|
-
help = 'Test a webhook by sending a test payload'
|
|
24
|
-
|
|
25
|
-
def add_arguments(self, parser):
|
|
26
|
-
parser.add_argument(
|
|
27
|
-
'webhook_id', type=int, help='The ID of the webhook to test'
|
|
28
|
-
)
|
|
29
|
-
parser.add_argument(
|
|
30
|
-
'--event',
|
|
31
|
-
type=str,
|
|
32
|
-
default='test',
|
|
33
|
-
help='Event type to use (test, created, updated, deleted)',
|
|
34
|
-
)
|
|
35
|
-
parser.add_argument(
|
|
36
|
-
'--payload',
|
|
37
|
-
type=str,
|
|
38
|
-
help='Custom payload to send (as JSON string)',
|
|
39
|
-
)
|
|
40
|
-
|
|
41
|
-
def handle(self, *args, **options):
|
|
42
|
-
webhook_id = options['webhook_id']
|
|
43
|
-
event_signal = options['event']
|
|
44
|
-
custom_payload = options['payload']
|
|
45
|
-
|
|
46
|
-
from django_webhook_subscriber.models import WebhookRegistry
|
|
47
|
-
|
|
48
|
-
try:
|
|
49
|
-
webhook = WebhookRegistry.objects.get(pk=webhook_id)
|
|
50
|
-
except WebhookRegistry.DoesNotExist:
|
|
51
|
-
raise CommandError(f'Webhook with ID {webhook_id} does not exist')
|
|
52
|
-
|
|
53
|
-
# Prepare payload
|
|
54
|
-
if custom_payload:
|
|
55
|
-
try:
|
|
56
|
-
# Use provided payload
|
|
57
|
-
payload = custom_payload
|
|
58
|
-
# Validate it's valid JSON
|
|
59
|
-
json.loads(payload)
|
|
60
|
-
except json.JSONDecodeError:
|
|
61
|
-
raise CommandError('The provided payload is not valid JSON')
|
|
62
|
-
else:
|
|
63
|
-
# Generate a test payload
|
|
64
|
-
model_name = webhook.content_type.model
|
|
65
|
-
app_label = webhook.content_type.app_label
|
|
66
|
-
|
|
67
|
-
payload = json.dumps(
|
|
68
|
-
{
|
|
69
|
-
'event': event_signal,
|
|
70
|
-
'model': f'{app_label}.{model_name}',
|
|
71
|
-
'test': True,
|
|
72
|
-
'message': f'Test webhook for {webhook.name}',
|
|
73
|
-
}
|
|
74
|
-
)
|
|
75
|
-
|
|
76
|
-
# Deliver the webhook
|
|
77
|
-
self.stdout.write(f'Sending test webhook to {webhook.endpoint}...')
|
|
78
|
-
log = deliver_webhook(webhook, payload, event_signal)
|
|
79
|
-
|
|
80
|
-
# Display results
|
|
81
|
-
if log.error_message:
|
|
82
|
-
self.stdout.write(self.style.ERROR(f'Error: {log.error_message}'))
|
|
83
|
-
elif log.response_status and 200 <= log.response_status < 300:
|
|
84
|
-
self.stdout.write(
|
|
85
|
-
self.style.SUCCESS(
|
|
86
|
-
f'Success! Status code: {log.response_status}'
|
|
87
|
-
)
|
|
88
|
-
)
|
|
89
|
-
self.stdout.write(f'Response: {log.response_body}')
|
|
90
|
-
else:
|
|
91
|
-
self.stdout.write(
|
|
92
|
-
self.style.WARNING(
|
|
93
|
-
f'Received status code: {log.response_status}'
|
|
94
|
-
)
|
|
95
|
-
)
|
|
96
|
-
self.stdout.write(f'Response: {log.response_body}')
|
|
@@ -1,152 +0,0 @@
|
|
|
1
|
-
"""Signal handlers for processing webhooks.
|
|
2
|
-
|
|
3
|
-
It includes functions to register models, connect signals, and process webhook
|
|
4
|
-
events.
|
|
5
|
-
"""
|
|
6
|
-
|
|
7
|
-
from django.apps import apps
|
|
8
|
-
from django.conf import settings
|
|
9
|
-
from django.utils.module_loading import import_string
|
|
10
|
-
from django.db.models.signals import post_save, post_delete
|
|
11
|
-
|
|
12
|
-
from django_webhook_subscriber.delivery import process_and_deliver_webhook
|
|
13
|
-
from django_webhook_subscriber.serializers import serialize_instance
|
|
14
|
-
from django_webhook_subscriber.utils import (
|
|
15
|
-
get_webhook_config,
|
|
16
|
-
register_model_config,
|
|
17
|
-
)
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
def process_webhook_event(instance, event_signal, **kwargs):
|
|
21
|
-
"""Process a webhook event by serializing the instance and delivering the
|
|
22
|
-
webhook.
|
|
23
|
-
|
|
24
|
-
This function checks the event type and the model class of the instance in
|
|
25
|
-
the registry. If the event type is registered, it serializes the instance
|
|
26
|
-
using the specified serializer (if any) and calls the delivery function to
|
|
27
|
-
send the webhook.
|
|
28
|
-
"""
|
|
29
|
-
|
|
30
|
-
# Skip if webhooks are disabled in settings
|
|
31
|
-
if getattr(settings, 'DISABLE_WEBHOOKS', False):
|
|
32
|
-
return
|
|
33
|
-
|
|
34
|
-
model_class = instance.__class__
|
|
35
|
-
|
|
36
|
-
# Get the webhook configuration for this model
|
|
37
|
-
config = get_webhook_config(model_class)
|
|
38
|
-
|
|
39
|
-
event_mappings = {
|
|
40
|
-
'created': 'CREATE',
|
|
41
|
-
'updated': 'UPDATE',
|
|
42
|
-
'deleted': 'DELETE',
|
|
43
|
-
}
|
|
44
|
-
if config and event_mappings[event_signal] in config.get('events', []):
|
|
45
|
-
# Get the serializer if configured, otherwise None (default will be
|
|
46
|
-
# used)
|
|
47
|
-
serializer = config.get('serializer')
|
|
48
|
-
|
|
49
|
-
# Serialize the instance using either custom or default serializer
|
|
50
|
-
payload = serialize_instance(
|
|
51
|
-
instance,
|
|
52
|
-
event_signal,
|
|
53
|
-
field_serializer=serializer,
|
|
54
|
-
)
|
|
55
|
-
|
|
56
|
-
# Deliver webhooks
|
|
57
|
-
process_and_deliver_webhook(
|
|
58
|
-
instance,
|
|
59
|
-
event_signal,
|
|
60
|
-
serialized_payload=payload,
|
|
61
|
-
)
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
def register_webhook_signals(model_class, serializer=None, events=None):
|
|
65
|
-
"""Register webhook signals for a specific model class."""
|
|
66
|
-
|
|
67
|
-
# Register the configuration
|
|
68
|
-
config = register_model_config(
|
|
69
|
-
model_class,
|
|
70
|
-
serializer=serializer,
|
|
71
|
-
events=events,
|
|
72
|
-
)
|
|
73
|
-
|
|
74
|
-
# Connect signals based on requested events with a unique identifier
|
|
75
|
-
if 'CREATE' in config['events'] or 'UPDATE' in config['events']:
|
|
76
|
-
post_save.connect(
|
|
77
|
-
webhook_post_save,
|
|
78
|
-
sender=model_class,
|
|
79
|
-
dispatch_uid=f'webhook_post_save_{model_class.__name__}',
|
|
80
|
-
)
|
|
81
|
-
|
|
82
|
-
if 'DELETE' in config['events']:
|
|
83
|
-
post_delete.connect(
|
|
84
|
-
webhook_post_delete,
|
|
85
|
-
sender=model_class,
|
|
86
|
-
dispatch_uid=f'webhook_post_delete_{model_class.__name__}',
|
|
87
|
-
)
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
def webhook_post_save(sender, instance, created, **kwargs):
|
|
91
|
-
"""Handle post_save signals for webhook processing."""
|
|
92
|
-
|
|
93
|
-
event_signal = 'created' if created else 'updated'
|
|
94
|
-
process_webhook_event(
|
|
95
|
-
instance=instance, event_signal=event_signal, **kwargs
|
|
96
|
-
)
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
def webhook_post_delete(sender, instance, **kwargs):
|
|
100
|
-
"""Handle post_delete signals for webhook processing."""
|
|
101
|
-
|
|
102
|
-
process_webhook_event(instance=instance, event_signal='deleted', **kwargs)
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
def register_webhooks_from_settings():
|
|
106
|
-
"""Register webhooks based on settings configuration.
|
|
107
|
-
|
|
108
|
-
This function is called in AppConfig.ready() to ensure that webhooks are
|
|
109
|
-
registered when the application starts.
|
|
110
|
-
"""
|
|
111
|
-
|
|
112
|
-
from django.conf import settings
|
|
113
|
-
|
|
114
|
-
# Skip registration if webhooks are disabled
|
|
115
|
-
if getattr(settings, 'DISABLE_WEBHOOKS', False):
|
|
116
|
-
return
|
|
117
|
-
|
|
118
|
-
# Check if WEBHOOK_SUBSCRIBER is defined in settings
|
|
119
|
-
if not hasattr(settings, 'WEBHOOK_SUBSCRIBER'):
|
|
120
|
-
return
|
|
121
|
-
|
|
122
|
-
# Getting WEBHOOKS_MODELS from settings
|
|
123
|
-
webhook_settings = settings.WEBHOOK_SUBSCRIBER
|
|
124
|
-
webhook_models = webhook_settings.get('WEBHOOK_MODELS', {})
|
|
125
|
-
|
|
126
|
-
for model_path, config in webhook_models.items():
|
|
127
|
-
# Split the model path into app_label and model_name
|
|
128
|
-
try:
|
|
129
|
-
app_label, model_name = model_path.split('.')
|
|
130
|
-
model_class = apps.get_model(app_label, model_name)
|
|
131
|
-
except Exception:
|
|
132
|
-
# If model path is invalid or model doesn't exist, skip it
|
|
133
|
-
continue
|
|
134
|
-
|
|
135
|
-
# Get serializer if specified
|
|
136
|
-
field_serializer = None
|
|
137
|
-
if 'serializer' in config:
|
|
138
|
-
try:
|
|
139
|
-
field_serializer = import_string(config['serializer'])
|
|
140
|
-
except ImportError:
|
|
141
|
-
# If serializer import fails, skip it
|
|
142
|
-
pass
|
|
143
|
-
|
|
144
|
-
# Get events
|
|
145
|
-
events = config.get('events', None)
|
|
146
|
-
|
|
147
|
-
# Register the webhook
|
|
148
|
-
register_webhook_signals(
|
|
149
|
-
model_class,
|
|
150
|
-
serializer=field_serializer,
|
|
151
|
-
events=events,
|
|
152
|
-
)
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
"""Testing utilities for Django Webhook Subscriber."""
|
|
2
|
-
|
|
3
|
-
from django.test.utils import override_settings
|
|
4
|
-
|
|
5
|
-
# Context manager for disabling webhooks in tests
|
|
6
|
-
disabled_webhooks = override_settings(DISABLE_WEBHOOKS=True)
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
# Function to use in setUp methods
|
|
10
|
-
def disable_webhooks_for_testing():
|
|
11
|
-
"""Disable webhooks for test purposes by unregistering all signals."""
|
|
12
|
-
from django_webhook_subscriber.utils import unregister_webhook_signals
|
|
13
|
-
|
|
14
|
-
unregister_webhook_signals()
|