Skip to content

Commit 4cceb9b

Browse files
committed
remove rest hook
Signed-off-by: tdruez <tdruez@aboutcode.org>
1 parent cdf17a4 commit 4cceb9b

15 files changed

Lines changed: 79 additions & 113 deletions

dejacode/settings.py

Lines changed: 8 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -327,7 +327,6 @@ def gettext_noop(s):
327327
"crispy_bootstrap5",
328328
"guardian",
329329
"django_filters",
330-
"rest_hooks",
331330
"notifications",
332331
"axes",
333332
"django_otp",
@@ -663,18 +662,14 @@ def get_fake_redis_connection(config, use_strict_redis):
663662
# django-altcha
664663
ALTCHA_HMAC_KEY = env.str("DEJACODE_ALTCHA_HMAC_KEY", default="")
665664

666-
# https://github.com/zapier/django-rest-hooks
667-
HOOK_FINDER = "notification.models.find_and_fire_hook"
668-
HOOK_EVENTS = {
669-
# 'any.event.name': 'App.Model.Action' (created/updated/deleted)
670-
# If you want a Hook to be triggered for all users, add '+' to built-in Hooks.
671-
"request.added": "workflow.Request.created+",
672-
"request.updated": "workflow.Request.updated+",
673-
"request_comment.added": "workflow.RequestComment.created+",
674-
"user.added_or_updated": None,
675-
"user.locked_out": None,
676-
"vulnerability.data_update": None,
677-
}
665+
WEBHOOK_EVENTS = [
666+
"request.added",
667+
"request.updated",
668+
"request_comment.added",
669+
"user.added_or_updated",
670+
"user.locked_out",
671+
"vulnerability.data_update",
672+
]
678673
# Provide context variables to WebhookSubscription extra_headers template values.
679674
HOOK_ENV = env.dict("HOOK_ENV", default={})
680675

dje/notification.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
from dje.models import History
2222
from dje.tasks import send_mail_task
2323
from dje.tasks import send_mail_to_admins_task
24-
from notification.models import find_and_fire_hook
24+
from notification.models import fire_webhooks
2525

2626
ADDITION = History.ADDITION
2727
CHANGE = History.CHANGE
@@ -228,7 +228,7 @@ def notify_on_user_locked_out(request, username, **kwargs):
228228
if not reference_dataspace:
229229
return
230230

231-
find_and_fire_hook(
231+
fire_webhooks(
232232
"user.locked_out",
233233
instance=None,
234234
dataspace=reference_dataspace,
@@ -248,7 +248,7 @@ def notify_on_user_added_or_updated(instance, **kwargs):
248248
if not reference_dataspace:
249249
return
250250

251-
find_and_fire_hook(
251+
fire_webhooks(
252252
"user.added_or_updated",
253253
instance=instance,
254254
dataspace=reference_dataspace,

dje/tests/test_access.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -441,6 +441,7 @@ def test_user_locked_out_on_unsuccessful_login_attempts(self):
441441

442442
@mock.patch("requests.post")
443443
def test_notification_on_unsuccessful_login_attempts(self, method_mock):
444+
method_mock.return_value = None
444445
user = create_user(username="real_user", dataspace=self.dataspace)
445446
extra_payload = {"username": "DejaCode Webhook"}
446447
WebhookSubscription.objects.create(

etc/scripts/build_deb_docker.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -59,9 +59,7 @@ def build_deb_with_docker():
5959
dependencies = project.get("dependencies", [])
6060

6161
filtered_dependencies = [
62-
dep
63-
for dep in dependencies
64-
if "django_notifications_patched" not in dep
62+
dep for dep in dependencies if "django_notifications_patched" not in dep
6563
]
6664

6765
docker_cmd = [

etc/scripts/build_rpm_docker.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -59,9 +59,7 @@ def build_rpm_with_docker():
5959
dependencies = project["dependencies"]
6060

6161
filtered_dependencies = [
62-
dep
63-
for dep in dependencies
64-
if "django-notifications-patched" not in dep
62+
dep for dep in dependencies if "django-notifications-patched" not in dep
6563
]
6664

6765
# Create a requirements.txt content for installation

notification/admin.py

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,21 +9,16 @@
99
from django import forms
1010
from django.conf import settings
1111
from django.contrib import admin
12-
from django.core.exceptions import ImproperlyConfigured
1312

1413
from dje.admin import DataspacedAdmin
1514
from dje.admin import ProhibitDataspaceLookupMixin
1615
from dje.admin import dejacode_site
1716
from dje.forms import DataspacedAdminForm
1817
from notification.models import WebhookSubscription
1918

20-
HOOK_EVENTS = settings.HOOK_EVENTS
21-
if HOOK_EVENTS is None:
22-
raise ImproperlyConfigured("settings.HOOK_EVENTS is not defined")
23-
2419

2520
class WebhookSubscriptionForm(DataspacedAdminForm):
26-
EVENTS = [(event, event) for event in HOOK_EVENTS.keys()]
21+
EVENTS = [(event, event) for event in settings.WEBHOOK_EVENTS]
2722

2823
class Meta:
2924
model = WebhookSubscription

notification/apps.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,3 +13,21 @@
1313
class NotificationConfig(AppConfig):
1414
name = "notification"
1515
verbose_name = _("Notification")
16+
17+
def ready(self):
18+
from django.db.models.signals import post_save
19+
20+
from notification.models import fire_webhooks
21+
from workflow.models import Request
22+
from workflow.models import RequestComment
23+
24+
def fire_request_webhook(sender, instance, created, **kwargs):
25+
event = "request.added" if created else "request.updated"
26+
fire_webhooks(event, instance)
27+
28+
def fire_request_comment_webhook(sender, instance, created, **kwargs):
29+
if created:
30+
fire_webhooks("request_comment.added", instance)
31+
32+
post_save.connect(fire_request_webhook, sender=Request, weak=False)
33+
post_save.connect(fire_request_comment_webhook, sender=RequestComment, weak=False)

notification/models.py

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ def deliver(self, context, timeout=10, payload_override=None):
9090
def get_payload(self, instance):
9191
payload = instance.serialize_hook(hook=self)
9292
if self.extra_payload:
93-
payload.update(self.extra_payload)
93+
payload["data"].update(self.extra_payload)
9494
return payload
9595

9696
def create_delivery(self, payload, instance):
@@ -125,18 +125,18 @@ class Meta(AbstractWebhookDelivery.Meta):
125125
unique_together = [("dataspace", "uuid")]
126126

127127

128-
129-
def find_and_fire_hook(
128+
def fire_webhooks(
130129
event_name,
131130
instance,
132-
user_override=None,
133131
dataspace=None,
134132
payload_override=None,
135133
):
136134
"""
137-
Fire active Webhook instances found in the `dataspace` for the `event_name`.
135+
Enqueue async delivery for each active WebhookSubscription in `dataspace` matching `event_name`.
138136
If `dataspace` is not provided, uses the Dataspace of the `instance`.
139137
"""
138+
from notification.tasks import deliver_webhook_task
139+
140140
if not dataspace and instance:
141141
dataspace = instance.dataspace
142142
if not dataspace:
@@ -150,4 +150,11 @@ def find_and_fire_hook(
150150
webhooks = WebhookSubscription.objects.scope(dataspace).filter(**filters)
151151

152152
for webhook in webhooks:
153-
webhook.deliver(instance, payload_override=payload_override)
153+
task_kwargs = {"webhook_subscription_pk": webhook.pk}
154+
if payload_override is not None:
155+
task_kwargs["payload_override"] = payload_override
156+
if instance is not None:
157+
task_kwargs["instance_app_label"] = instance._meta.app_label
158+
task_kwargs["instance_model_name"] = instance._meta.model_name
159+
task_kwargs["instance_pk"] = instance.pk
160+
deliver_webhook_task.delay(**task_kwargs)

notification/tasks.py

Lines changed: 28 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -6,55 +6,41 @@
66
# See https://aboutcode.org for more information about AboutCode FOSS projects.
77
#
88

9-
import json
9+
import logging
1010

11-
from django.template.defaultfilters import truncatechars
12-
13-
import requests
1411
from django_rq import job
15-
from rest_framework.utils import encoders
1612

17-
from dje.tasks import logger
13+
logger = logging.getLogger("dje")
1814

1915

2016
@job
21-
def deliver_hook_task(
22-
target, payload, instance_id=None, hook_id=None, extra_headers=None, **kwargs
17+
def deliver_webhook_task(
18+
webhook_subscription_pk,
19+
payload_override=None,
20+
instance_app_label=None,
21+
instance_model_name=None,
22+
instance_pk=None,
2323
):
24-
"""
25-
target: the url to receive the payload.
26-
payload: a python primitive data structure
27-
instance_id: a possibly None "trigger" instance ID
28-
hook_id: the ID of defining Hook object
29-
extra_headers: Additional headers such as Authentication ones
30-
"""
31-
session = requests.Session()
32-
33-
session.headers.update({"Content-Type": "application/json"})
34-
if extra_headers:
35-
session.headers.update(extra_headers)
36-
37-
logger.info(f"Delivering Webhook hook_id={hook_id} to target={truncatechars(target, 25)}")
38-
try:
39-
session.post(url=target, data=payload)
40-
except requests.ConnectionError:
41-
return
42-
24+
"""Deliver a webhook payload to the target URL of the given WebhookSubscription."""
25+
from django.apps import apps
4326

44-
def deliver_hook_wrapper(target, payload, instance, hook):
45-
if hook.extra_payload:
46-
payload.update(hook.extra_payload)
27+
from notification.models import WebhookSubscription
4728

48-
# Using ID's instead of objects for proper serialization
49-
kwargs = {
50-
"target": target,
51-
"payload": json.dumps(payload, cls=encoders.JSONEncoder),
52-
"hook_id": hook.id,
53-
}
54-
55-
if instance:
56-
kwargs["instance_id"] = instance.id
57-
if hook.extra_headers:
58-
kwargs["extra_headers"] = hook.get_extra_headers()
29+
try:
30+
webhook_subscription = WebhookSubscription.objects.get(pk=webhook_subscription_pk)
31+
except WebhookSubscription.DoesNotExist:
32+
logger.error(f"WebhookSubscription pk={webhook_subscription_pk} not found.")
33+
return
5934

60-
deliver_hook_task.delay(**kwargs)
35+
instance = None
36+
if instance_app_label and instance_model_name and instance_pk:
37+
try:
38+
model_class = apps.get_model(instance_app_label, instance_model_name)
39+
instance = model_class.objects.get(pk=instance_pk)
40+
except Exception:
41+
logger.error(
42+
f"Instance {instance_app_label}.{instance_model_name} pk={instance_pk} not found."
43+
)
44+
return
45+
46+
webhook_subscription.deliver(instance, payload_override=payload_override)

pyproject.toml

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -115,8 +115,6 @@ dependencies = [
115115
# license expressions
116116
"boolean.py==5.0",
117117
"license-expression==30.4.4",
118-
# Webhooks
119-
"django-rest-hooks==1.6.1",
120118
# django-notifications
121119
"django_notifications_patched==2.0.0",
122120
"jsonfield==3.2.0",

0 commit comments

Comments
 (0)