Skip to content

Commit cdf17a4

Browse files
committed
remove the legacy Webhook model
Signed-off-by: tdruez <tdruez@aboutcode.org>
1 parent 12231d5 commit cdf17a4

11 files changed

Lines changed: 109 additions & 159 deletions

File tree

dejacode/settings.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -665,7 +665,6 @@ def get_fake_redis_connection(config, use_strict_redis):
665665

666666
# https://github.com/zapier/django-rest-hooks
667667
HOOK_FINDER = "notification.models.find_and_fire_hook"
668-
HOOK_DELIVERER = "notification.tasks.deliver_hook_wrapper"
669668
HOOK_EVENTS = {
670669
# 'any.event.name': 'App.Model.Action' (created/updated/deleted)
671670
# If you want a Hook to be triggered for all users, add '+' to built-in Hooks.
@@ -676,7 +675,7 @@ def get_fake_redis_connection(config, use_strict_redis):
676675
"user.locked_out": None,
677676
"vulnerability.data_update": None,
678677
}
679-
# Provide context variables to the `Webhook` values such as `extra_headers`.
678+
# Provide context variables to WebhookSubscription extra_headers template values.
680679
HOOK_ENV = env.dict("HOOK_ENV", default={})
681680

682681
# Django-axes

dje/management/commands/flushdataset.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,8 @@
1717
from dje.models import ExternalReference
1818
from dje.models import ExternalSource
1919
from dje.models import get_unsecured_manager
20-
from notification.models import Webhook
20+
from notification.models import WebhookDelivery
21+
from notification.models import WebhookSubscription
2122
from vulnerabilities.models import Vulnerability
2223

2324

@@ -55,7 +56,8 @@ def handle(self, *args, **options):
5556
UsagePolicy,
5657
ExternalReference,
5758
ExternalSource,
58-
Webhook,
59+
WebhookDelivery,
60+
WebhookSubscription,
5961
Vulnerability,
6062
]
6163
)

dje/tests/test_access.py

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@
4141
from dje.tests import create_user
4242
from dje.tests import refresh_url_cache
4343
from license_library.models import License
44-
from notification.models import Webhook
44+
from notification.models import WebhookSubscription
4545
from product_portfolio.models import Product
4646

4747

@@ -439,14 +439,13 @@ def test_user_locked_out_on_unsuccessful_login_attempts(self):
439439
attempt = AccessAttempt.objects.get(username=credentials["username"])
440440
self.assertEqual(2, attempt.failures_since_start)
441441

442-
@mock.patch("requests.Session.post", autospec=True)
442+
@mock.patch("requests.post")
443443
def test_notification_on_unsuccessful_login_attempts(self, method_mock):
444444
user = create_user(username="real_user", dataspace=self.dataspace)
445445
extra_payload = {"username": "DejaCode Webhook"}
446-
Webhook.objects.create(
446+
WebhookSubscription.objects.create(
447447
dataspace=self.dataspace,
448-
target="http://127.0.0.1:8000/",
449-
user=user,
448+
target_url="http://127.0.0.1:8000/",
450449
event="user.locked_out",
451450
extra_payload=extra_payload,
452451
)

etc/scripts/build_deb_docker.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ def build_deb_with_docker():
6161
filtered_dependencies = [
6262
dep
6363
for dep in dependencies
64-
if "django-rest-hooks" not in dep and "django_notifications_patched" not in dep
64+
if "django_notifications_patched" not in dep
6565
]
6666

6767
docker_cmd = [
@@ -98,7 +98,6 @@ def build_deb_with_docker():
9898
rm -rf build/
9999
100100
# Install non-PyPI dependencies
101-
pip install https://github.com/aboutcode-org/django-rest-hooks/releases/download/1.6.1/django_rest_hooks-1.6.1-py2.py3-none-any.whl
102101
pip install https://github.com/dejacode/django-notifications-patched/archive/refs/tags/2.0.0.tar.gz
103102
104103
# Install dependencies directly

etc/scripts/build_nix_docker.py

Lines changed: 3 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -242,21 +242,9 @@ def create_defualt_nix(dependencies_list, meta_dict):
242242
print("Processing {}/{}: {}".format(idx + 1, deps_size, dep["name"]))
243243
name = dep["name"]
244244
version = dep["version"]
245-
# Handle 'django_notifications_patched' and 'django-rest-hooks' seperately
246-
if name == "django-rest-hooks" or name == "django_notifications_patched":
247-
if name == "django-rest-hooks" and version == "1.6.1":
248-
nix_content += " " + name + " = python.pkgs.buildPythonPackage {\n"
249-
nix_content += ' pname = "django-rest-hooks";\n'
250-
nix_content += ' version = "1.6.1";\n'
251-
nix_content += ' format = "wheel";\n'
252-
nix_content += " src = pkgs.fetchurl {\n"
253-
nix_content += ' url = "https://github.com/aboutcode-org/django-rest-hooks/releases/download/1.6.1/django_rest_hooks-1.6.1-py2.py3-none-any.whl";\n'
254-
nix_content += (
255-
' sha256 = "1byakq3ghpqhm0mjjkh8v5y6g3wlnri2vvfifyi9ky36l12vqx74";\n'
256-
)
257-
nix_content += " };\n"
258-
nix_content += " };\n"
259-
elif name == "django_notifications_patched" and version == "2.0.0":
245+
# Handle 'django_notifications_patched' seperately
246+
if name == "django_notifications_patched":
247+
if name == "django_notifications_patched" and version == "2.0.0":
260248
nix_content += " " + name + " = self.buildPythonPackage rec {\n"
261249
nix_content += ' pname = "django_notifications_patched";\n'
262250
nix_content += ' version = "2.0.0";\n'

etc/scripts/build_rpm_docker.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ def build_rpm_with_docker():
6161
filtered_dependencies = [
6262
dep
6363
for dep in dependencies
64-
if "django-rest-hooks" not in dep and "django-notifications-patched" not in dep
64+
if "django-notifications-patched" not in dep
6565
]
6666

6767
# Create a requirements.txt content for installation
@@ -189,8 +189,6 @@ def build_rpm_with_docker():
189189
dnf install -y postgresql-devel
190190
191191
# Install non-PyPI dependencies
192-
/tmp/venv_build/bin/python -m pip install \\
193-
https://github.com/aboutcode-org/django-rest-hooks/releases/download/1.6.1/django_rest_hooks-1.6.1-py2.py3-none-any.whl
194192
/tmp/venv_build/bin/python -m pip install \\
195193
https://github.com/dejacode/django-notifications-patched/archive/refs/tags/2.0.0.tar.gz
196194

notification/admin.py

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -15,20 +15,20 @@
1515
from dje.admin import ProhibitDataspaceLookupMixin
1616
from dje.admin import dejacode_site
1717
from dje.forms import DataspacedAdminForm
18-
from notification.models import Webhook
18+
from notification.models import WebhookSubscription
1919

2020
HOOK_EVENTS = settings.HOOK_EVENTS
2121
if HOOK_EVENTS is None:
2222
raise ImproperlyConfigured("settings.HOOK_EVENTS is not defined")
2323

2424

25-
class WebookForm(DataspacedAdminForm):
25+
class WebhookSubscriptionForm(DataspacedAdminForm):
2626
EVENTS = [(event, event) for event in HOOK_EVENTS.keys()]
2727

2828
class Meta:
29-
model = Webhook
29+
model = WebhookSubscription
3030
fields = [
31-
"target",
31+
"target_url",
3232
"event",
3333
"is_active",
3434
"extra_payload",
@@ -39,15 +39,11 @@ def __init__(self, *args, **kwargs):
3939
super().__init__(*args, **kwargs)
4040
self.fields["event"] = forms.ChoiceField(choices=self.EVENTS)
4141

42-
add = not kwargs.get("instance")
43-
if add:
44-
self.instance.user = self.request.user
4542

46-
47-
@admin.register(Webhook, site=dejacode_site)
48-
class WebookAdmin(ProhibitDataspaceLookupMixin, DataspacedAdmin):
49-
list_display = ("__str__", "event", "target", "is_active", "dataspace")
50-
form = WebookForm
43+
@admin.register(WebhookSubscription, site=dejacode_site)
44+
class WebhookSubscriptionAdmin(ProhibitDataspaceLookupMixin, DataspacedAdmin):
45+
list_display = ("__str__", "event", "target_url", "is_active", "dataspace")
46+
form = WebhookSubscriptionForm
5147
list_filter = ("is_active", "event")
5248
activity_log = False
5349
actions = []
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
# Generated by Django 6.0.6 on 2026-07-03 13:50
2+
3+
from django.db import migrations
4+
5+
6+
class Migration(migrations.Migration):
7+
8+
dependencies = [
9+
('notification', '0003_migrate_webhook_to_webhooksubscription'),
10+
]
11+
12+
operations = [
13+
migrations.DeleteModel(
14+
name='Webhook',
15+
),
16+
]

notification/models.py

Lines changed: 6 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,6 @@
1313
from django.db import models
1414
from django.utils.translation import gettext_lazy as _
1515

16-
from rest_hooks.models import AbstractHook
17-
1816
from aboutcode.notifications import AbstractWebhookDelivery
1917
from aboutcode.notifications import AbstractWebhookSubscription
2018
from dje.models import DataspacedModel
@@ -83,6 +81,12 @@ def get_headers(self):
8381
headers.update(self.get_extra_headers())
8482
return headers
8583

84+
def deliver(self, context, timeout=10, payload_override=None):
85+
if payload_override and self.extra_payload:
86+
payload_override = {**payload_override}
87+
payload_override.update(self.extra_payload)
88+
return super().deliver(context, timeout=timeout, payload_override=payload_override)
89+
8690
def get_payload(self, instance):
8791
payload = instance.serialize_hook(hook=self)
8892
if self.extra_payload:
@@ -121,46 +125,6 @@ class Meta(AbstractWebhookDelivery.Meta):
121125
unique_together = [("dataspace", "uuid")]
122126

123127

124-
# DataspacedModel is first as we want to apply it last for proper overrides
125-
class Webhook(DataspacedModel, AbstractHook):
126-
is_active = models.BooleanField(default=True)
127-
extra_payload = models.JSONField(
128-
blank=True,
129-
default=dict,
130-
help_text=_("Extra data as JSON to be included in the payload"),
131-
)
132-
extra_headers = models.JSONField(
133-
blank=True,
134-
default=dict,
135-
help_text=_("Extra headers as JSON to be included in the request"),
136-
)
137-
138-
class Meta:
139-
unique_together = ("dataspace", "uuid")
140-
141-
def __str__(self):
142-
return f"{self.event} => {self.target}"
143-
144-
def dict(self):
145-
return {"uuid": str(self.uuid), "event": self.event, "target": self.target}
146-
147-
def get_extra_headers(self):
148-
"""Inject `hook_env` context in headers template values."""
149-
if hook_env := settings.HOOK_ENV:
150-
hook_env_context = template.Context(hook_env)
151-
return {
152-
key: self.render_template(value, hook_env_context)
153-
for key, value in self.extra_headers.items()
154-
}
155-
156-
return self.extra_headers
157-
158-
@staticmethod
159-
def render_template(value, hook_env_context):
160-
if "{{" in value and "}}" in value:
161-
return template.Template(value).render(hook_env_context)
162-
return value
163-
164128

165129
def find_and_fire_hook(
166130
event_name,

notification/tests/test_models.py

Lines changed: 16 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -11,39 +11,38 @@
1111

1212
from dje.models import Dataspace
1313
from dje.tests import create_superuser
14-
from notification.models import Webhook
14+
from notification.models import WebhookSubscription
1515

1616

17-
class NotificationModelsTestCase(TestCase):
17+
class WebhookSubscriptionModelTestCase(TestCase):
1818
def setUp(self):
1919
self.nexb_dataspace = Dataspace.objects.create(name="nexB")
2020
self.nexb_user = create_superuser("nexb_user", self.nexb_dataspace)
2121

22-
self.webhook1 = Webhook.objects.create(
22+
self.webhook = WebhookSubscription.objects.create(
2323
dataspace=self.nexb_dataspace,
24-
target="http://1.2.3.4/",
25-
user=self.nexb_user,
24+
target_url="http://1.2.3.4/",
2625
event="request.added",
2726
)
2827

29-
def test_notification_webhook_model_str(self):
30-
self.assertEqual("request.added => http://1.2.3.4/", str(self.webhook1))
28+
def test_webhook_subscription_str(self):
29+
self.assertEqual("request.added => http://1.2.3.4/", str(self.webhook))
3130

32-
def test_notification_webhook_model_dict(self):
31+
def test_webhook_subscription_dict(self):
3332
expected = {
34-
"uuid": str(self.webhook1.uuid),
35-
"event": self.webhook1.event,
36-
"target": self.webhook1.target,
33+
"uuid": str(self.webhook.uuid),
34+
"event": self.webhook.event,
35+
"target": self.webhook.target_url,
3736
}
38-
self.assertEqual(expected, self.webhook1.dict())
37+
self.assertEqual(expected, self.webhook.dict())
3938

40-
def test_notification_webhook_model_get_extra_headers(self):
41-
self.webhook1.extra_headers = {"Header": "{{ENV_VALUE}}"}
42-
self.webhook1.save()
39+
def test_webhook_subscription_get_extra_headers(self):
40+
self.webhook.extra_headers = {"Header": "{{ENV_VALUE}}"}
41+
self.webhook.save()
4342

4443
expected = {"Header": "{{ENV_VALUE}}"}
45-
self.assertEqual(expected, self.webhook1.get_extra_headers())
44+
self.assertEqual(expected, self.webhook.get_extra_headers())
4645

4746
expected = {"Header": "some_value"}
4847
with override_settings(HOOK_ENV={"ENV_VALUE": "some_value"}):
49-
self.assertEqual(expected, self.webhook1.get_extra_headers())
48+
self.assertEqual(expected, self.webhook.get_extra_headers())

0 commit comments

Comments
 (0)