Skip to content

Commit b769410

Browse files
authored
Async Delete: Correct instances of multiple audit log entries for delete (#12650)
* Async Delete: Correct instances of multiple audit log entries for delete * Update utils.py * Fixing ruff for good * Make notification signals a bit more resilient * Ruff again
1 parent bc177ab commit b769410

File tree

7 files changed

+35
-30
lines changed

7 files changed

+35
-30
lines changed

dojo/endpoint/signals.py

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,16 +13,15 @@
1313
@receiver(post_delete, sender=Endpoint)
1414
def endpoint_post_delete(sender, instance, using, origin, **kwargs):
1515
if instance == origin:
16+
description = _('The endpoint "%(name)s" was deleted') % {"name": str(instance)}
1617
if settings.ENABLE_AUDITLOG:
17-
le = LogEntry.objects.get(
18+
if le := LogEntry.objects.filter(
1819
action=LogEntry.Action.DELETE,
1920
content_type=ContentType.objects.get(app_label="dojo", model="endpoint"),
2021
object_id=instance.id,
21-
)
22-
description = _('The endpoint "%(name)s" was deleted by %(user)s') % {
22+
).order_by("-id").first():
23+
description = _('The endpoint "%(name)s" was deleted by %(user)s') % {
2324
"name": str(instance), "user": le.actor}
24-
else:
25-
description = _('The endpoint "%(name)s" was deleted') % {"name": str(instance)}
2625
create_notification(event="endpoint_deleted", # template does not exists, it will default to "other" but this event name needs to stay because of unit testing
2726
title=_("Deletion of %(name)s") % {"name": str(instance)},
2827
description=description,

dojo/engagement/signals.py

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -39,16 +39,15 @@ def engagement_pre_save(sender, instance, **kwargs):
3939
@receiver(post_delete, sender=Engagement)
4040
def engagement_post_delete(sender, instance, using, origin, **kwargs):
4141
if instance == origin:
42+
description = _('The engagement "%(name)s" was deleted') % {"name": instance.name}
4243
if settings.ENABLE_AUDITLOG:
43-
le = LogEntry.objects.get(
44+
if le := LogEntry.objects.filter(
4445
action=LogEntry.Action.DELETE,
4546
content_type=ContentType.objects.get(app_label="dojo", model="engagement"),
4647
object_id=instance.id,
47-
)
48-
description = _('The engagement "%(name)s" was deleted by %(user)s') % {
48+
).order_by("-id").first():
49+
description = _('The engagement "%(name)s" was deleted by %(user)s') % {
4950
"name": instance.name, "user": le.actor}
50-
else:
51-
description = _('The engagement "%(name)s" was deleted') % {"name": instance.name}
5251
create_notification(event="engagement_deleted", # template does not exists, it will default to "other" but this event name needs to stay because of unit testing
5352
title=_("Deletion of %(name)s") % {"name": instance.name},
5453
description=description,

dojo/finding_group/signals.py

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,16 +13,15 @@
1313
@receiver(post_delete, sender=Finding_Group)
1414
def finding_group_post_delete(sender, instance, using, origin, **kwargs):
1515
if instance == origin:
16+
description = _('The finding group "%(name)s" was deleted') % {"name": instance.name}
1617
if settings.ENABLE_AUDITLOG:
17-
le = LogEntry.objects.get(
18+
if le := LogEntry.objects.filter(
1819
action=LogEntry.Action.DELETE,
1920
content_type=ContentType.objects.get(app_label="dojo", model="finding_group"),
2021
object_id=instance.id,
21-
)
22-
description = _('The finding group "%(name)s" was deleted by %(user)s') % {
22+
).order_by("-id").first():
23+
description = _('The finding group "%(name)s" was deleted by %(user)s') % {
2324
"name": instance.name, "user": le.actor}
24-
else:
25-
description = _('The finding group "%(name)s" was deleted') % {"name": instance.name}
2625
create_notification(event="finding_group_deleted", # template does not exists, it will default to "other" but this event name needs to stay because of unit testing
2726
title=_("Deletion of %(name)s") % {"name": instance.name},
2827
description=description,

dojo/product/signals.py

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,16 +23,15 @@ def product_post_save(sender, instance, created, **kwargs):
2323

2424
@receiver(post_delete, sender=Product)
2525
def product_post_delete(sender, instance, **kwargs):
26+
description = _('The product "%(name)s" was deleted') % {"name": instance.name}
2627
if settings.ENABLE_AUDITLOG:
27-
le = LogEntry.objects.get(
28+
if le := LogEntry.objects.filter(
2829
action=LogEntry.Action.DELETE,
2930
content_type=ContentType.objects.get(app_label="dojo", model="product"),
3031
object_id=instance.id,
31-
)
32-
description = _('The product "%(name)s" was deleted by %(user)s') % {
32+
).order_by("-id").first():
33+
description = _('The product "%(name)s" was deleted by %(user)s') % {
3334
"name": instance.name, "user": le.actor}
34-
else:
35-
description = _('The product "%(name)s" was deleted') % {"name": instance.name}
3635
create_notification(event="product_deleted", # template does not exists, it will default to "other" but this event name needs to stay because of unit testing
3736
title=_("Deletion of %(name)s") % {"name": instance.name},
3837
description=description,

dojo/product_type/signals.py

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,16 +23,15 @@ def product_type_post_save(sender, instance, created, **kwargs):
2323

2424
@receiver(post_delete, sender=Product_Type)
2525
def product_type_post_delete(sender, instance, **kwargs):
26+
description = _('The product type "%(name)s" was deleted') % {"name": instance.name}
2627
if settings.ENABLE_AUDITLOG:
27-
le = LogEntry.objects.get(
28+
if le := LogEntry.objects.filter(
2829
action=LogEntry.Action.DELETE,
2930
content_type=ContentType.objects.get(app_label="dojo", model="product_type"),
3031
object_id=instance.id,
31-
)
32-
description = _('The product type "%(name)s" was deleted by %(user)s') % {
32+
).order_by("-id").first():
33+
description = _('The product type "%(name)s" was deleted by %(user)s') % {
3334
"name": instance.name, "user": le.actor}
34-
else:
35-
description = _('The product type "%(name)s" was deleted') % {"name": instance.name}
3635
create_notification(event="product_type_deleted", # template does not exists, it will default to "other" but this event name needs to stay because of unit testing
3736
title=_("Deletion of %(name)s") % {"name": instance.name},
3837
description=description,

dojo/test/signals.py

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,16 +16,15 @@
1616
@receiver(post_delete, sender=Test)
1717
def test_post_delete(sender, instance, using, origin, **kwargs):
1818
if instance == origin:
19+
description = _('The test "%(name)s" was deleted') % {"name": str(instance)}
1920
if settings.ENABLE_AUDITLOG:
20-
le = LogEntry.objects.get(
21+
if le := LogEntry.objects.filter(
2122
action=LogEntry.Action.DELETE,
2223
content_type=ContentType.objects.get(app_label="dojo", model="test"),
2324
object_id=instance.id,
24-
)
25-
description = _('The test "%(name)s" was deleted by %(user)s') % {
25+
).order_by("-id").first():
26+
description = _('The test "%(name)s" was deleted by %(user)s') % {
2627
"name": str(instance), "user": le.actor}
27-
else:
28-
description = _('The test "%(name)s" was deleted') % {"name": str(instance)}
2928
create_notification(event="test_deleted", # template does not exists, it will default to "other" but this event name needs to stay because of unit testing
3029
title=_("Deletion of %(name)s") % {"name": str(instance)},
3130
description=description,

dojo/utils.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,15 @@
1818
import hyperlink
1919
import vobject
2020
from asteval import Interpreter
21+
from auditlog.models import LogEntry
2122
from cryptography.hazmat.backends import default_backend
2223
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
2324
from dateutil.parser import parse
2425
from dateutil.relativedelta import MO, SU, relativedelta
2526
from django.conf import settings
2627
from django.contrib import messages
2728
from django.contrib.auth.signals import user_logged_in, user_logged_out, user_login_failed
29+
from django.contrib.contenttypes.models import ContentType
2830
from django.core.exceptions import ValidationError
2931
from django.core.paginator import Paginator
3032
from django.db.models import Case, Count, IntegerField, Q, Sum, Value, When
@@ -2333,6 +2335,15 @@ def delete_chunk(self, objects, **kwargs):
23332335
logger.debug("ASYNC_DELETE: object has already been deleted elsewhere. Skipping")
23342336
# The id must be None
23352337
# The object has already been deleted elsewhere
2338+
except LogEntry.MultipleObjectsReturned:
2339+
# Delete the log entrys first, then delete
2340+
LogEntry.objects.filter(
2341+
content_type=ContentType.objects.get_for_model(obj.__class__),
2342+
object_pk=str(obj.pk),
2343+
action=LogEntry.Action.DELETE,
2344+
).delete()
2345+
# Now delete the object again
2346+
obj.delete()
23362347

23372348
@dojo_async_task
23382349
@app.task

0 commit comments

Comments
 (0)