|
6 | 6 | import pghistory |
7 | 7 | from auditlog.context import set_actor |
8 | 8 | from crum import impersonate |
9 | | -from django.test import override_settings |
| 9 | +from django.test import RequestFactory, override_settings |
10 | 10 | from django.urls import reverse |
11 | 11 | from django.utils import timezone |
12 | 12 | from rest_framework.authtoken.models import Token |
|
23 | 23 | Engagement, |
24 | 24 | Finding, |
25 | 25 | Finding_Group, |
| 26 | + Notes, |
26 | 27 | Notification_Webhooks, |
27 | 28 | Notifications, |
28 | 29 | Product, |
|
38 | 39 | WebhookNotificationManger, |
39 | 40 | async_create_notification, |
40 | 41 | create_notification, |
| 42 | + process_tag_notifications, |
41 | 43 | webhook_status_cleanup, |
42 | 44 | ) |
43 | 45 | from dojo.url.models import URL |
@@ -1301,3 +1303,76 @@ def test_ping_with_owner_assigned(self, mock): |
1301 | 1303 | }, |
1302 | 1304 | }, |
1303 | 1305 | ) |
| 1306 | + |
| 1307 | + |
| 1308 | +@versioned_fixtures |
| 1309 | +class TestProcessTagNotifications(DojoTestCase): |
| 1310 | + |
| 1311 | + """ |
| 1312 | + Regression tests for dojo.notifications.helper.process_tag_notifications. |
| 1313 | +
|
| 1314 | + @mention notifications were silently never delivered: the helper passed |
| 1315 | + Dojo_User objects as ``recipients`` where usernames are expected, so |
| 1316 | + ``_process_recipients`` (which filters ``user__username__in``) matched |
| 1317 | + nothing. Usernames containing ``.``, ``-``, ``@`` or ``+`` were also |
| 1318 | + truncated by the old word-character-only mention regex. |
| 1319 | + """ |
| 1320 | + |
| 1321 | + fixtures = ["dojo_testdata.json"] |
| 1322 | + |
| 1323 | + def _enable_mention_alerts(self, user): |
| 1324 | + # dojo_testdata.json ships only the system (user=None) Notifications row; |
| 1325 | + # the recipient lookup needs a per-user row with product=None. |
| 1326 | + notifications, _ = Notifications.objects.get_or_create(user=user, product=None) |
| 1327 | + notifications.user_mentioned = ["alert"] |
| 1328 | + notifications.save() |
| 1329 | + |
| 1330 | + def _mention(self, author, entry): |
| 1331 | + note = Notes.objects.create(entry=entry, author=author) |
| 1332 | + request = RequestFactory().get("/") |
| 1333 | + request.user = author |
| 1334 | + with impersonate(author): |
| 1335 | + process_tag_notifications( |
| 1336 | + request, |
| 1337 | + note, |
| 1338 | + parent_url="/finding/1", |
| 1339 | + parent_title="Finding: Example", |
| 1340 | + ) |
| 1341 | + |
| 1342 | + def test_mentioned_user_receives_alert(self): |
| 1343 | + author = Dojo_User.objects.get(username="admin") |
| 1344 | + mentioned = Dojo_User.objects.create(username="mentionee", is_active=True) |
| 1345 | + self._enable_mention_alerts(mentioned) |
| 1346 | + |
| 1347 | + self._mention(author, f"@{mentioned.username} please take a look") |
| 1348 | + |
| 1349 | + self.assertEqual( |
| 1350 | + Alerts.objects.filter(user_id=mentioned, source="User Mentioned").count(), |
| 1351 | + 1, |
| 1352 | + "an @mention should create exactly one in-app alert for the mentioned user", |
| 1353 | + ) |
| 1354 | + |
| 1355 | + def test_username_with_dot_is_matched(self): |
| 1356 | + author = Dojo_User.objects.get(username="admin") |
| 1357 | + mentioned = Dojo_User.objects.create(username="jane.doe", is_active=True) |
| 1358 | + self._enable_mention_alerts(mentioned) |
| 1359 | + |
| 1360 | + self._mention(author, "thanks @jane.doe") |
| 1361 | + |
| 1362 | + self.assertEqual( |
| 1363 | + Alerts.objects.filter(user_id=mentioned).count(), |
| 1364 | + 1, |
| 1365 | + "a username containing '.' must be matched in full, not truncated to 'jane'", |
| 1366 | + ) |
| 1367 | + |
| 1368 | + def test_email_address_in_prose_is_not_a_mention(self): |
| 1369 | + author = Dojo_User.objects.get(username="admin") |
| 1370 | + mentioned = Dojo_User.objects.create(username="ops", is_active=True) |
| 1371 | + self._enable_mention_alerts(mentioned) |
| 1372 | + |
| 1373 | + self._mention(author, "email me at someone@ops") |
| 1374 | + |
| 1375 | + self.assertFalse( |
| 1376 | + Alerts.objects.filter(user_id=mentioned).exists(), |
| 1377 | + "an email-like token in prose (no whitespace before '@') must not notify", |
| 1378 | + ) |
0 commit comments