2018-06-19 15:45:15 -04:00
|
|
|
import uuid
|
2018-06-13 17:06:33 -04:00
|
|
|
|
2020-08-14 17:03:45 -04:00
|
|
|
from django.db.models.signals import m2m_changed, pre_delete, post_save
|
2018-06-13 17:06:33 -04:00
|
|
|
|
2020-08-14 17:03:45 -04:00
|
|
|
from utilities.utils import curry
|
|
|
|
from .signals import _handle_changed_object, _handle_deleted_object
|
2019-08-26 11:59:38 -04:00
|
|
|
|
|
|
|
|
2018-07-30 14:23:49 -04:00
|
|
|
class ObjectChangeMiddleware(object):
|
|
|
|
"""
|
2019-04-25 01:09:19 -04:00
|
|
|
This middleware performs three functions in response to an object being created, updated, or deleted:
|
2018-07-30 16:33:37 -04:00
|
|
|
|
|
|
|
1. Create an ObjectChange to reflect the modification to the object in the changelog.
|
|
|
|
2. Enqueue any relevant webhooks.
|
2019-09-09 15:50:10 -04:00
|
|
|
3. Increment the metric counter for the event type.
|
2018-06-13 17:06:33 -04:00
|
|
|
|
2019-05-30 10:32:09 -04:00
|
|
|
The post_save and post_delete signals are employed to catch object modifications, however changes are recorded a bit
|
2018-07-30 16:33:37 -04:00
|
|
|
differently for each. Objects being saved are cached into thread-local storage for action *after* the response has
|
|
|
|
completed. This ensures that serialization of the object is performed only after any related objects (e.g. tags)
|
|
|
|
have been created. Conversely, deletions are acted upon immediately, so that the serialized representation of the
|
|
|
|
object is recorded before it (and any related objects) are actually deleted from the database.
|
|
|
|
"""
|
2018-06-13 17:06:33 -04:00
|
|
|
def __init__(self, get_response):
|
|
|
|
self.get_response = get_response
|
|
|
|
|
|
|
|
def __call__(self, request):
|
|
|
|
|
2018-07-10 13:33:54 -04:00
|
|
|
# Assign a random unique ID to the request. This will be used to associate multiple object changes made during
|
|
|
|
# the same request.
|
|
|
|
request.id = uuid.uuid4()
|
2018-06-13 17:06:33 -04:00
|
|
|
|
2020-08-14 17:03:45 -04:00
|
|
|
# Curry signals receivers to pass the current request
|
|
|
|
handle_changed_object = curry(_handle_changed_object, request)
|
|
|
|
handle_deleted_object = curry(_handle_deleted_object, request)
|
|
|
|
|
2019-05-30 10:32:09 -04:00
|
|
|
# Connect our receivers to the post_save and post_delete signals.
|
2019-10-22 14:36:30 -04:00
|
|
|
post_save.connect(handle_changed_object, dispatch_uid='handle_changed_object')
|
2020-08-14 17:03:45 -04:00
|
|
|
m2m_changed.connect(handle_changed_object, dispatch_uid='handle_changed_object')
|
2019-10-22 14:36:30 -04:00
|
|
|
pre_delete.connect(handle_deleted_object, dispatch_uid='handle_deleted_object')
|
2018-06-13 17:06:33 -04:00
|
|
|
|
2018-07-10 13:33:54 -04:00
|
|
|
# Process the request
|
|
|
|
response = self.get_response(request)
|
2018-06-19 15:45:15 -04:00
|
|
|
|
2020-08-14 17:03:45 -04:00
|
|
|
# Disconnect change logging signals. This is necessary to avoid recording any errant
|
|
|
|
# changes during test cleanup.
|
2020-02-24 12:42:51 -05:00
|
|
|
post_save.disconnect(handle_changed_object, dispatch_uid='handle_changed_object')
|
2020-08-14 17:03:45 -04:00
|
|
|
m2m_changed.disconnect(handle_changed_object, dispatch_uid='handle_changed_object')
|
2020-02-24 12:42:51 -05:00
|
|
|
pre_delete.disconnect(handle_deleted_object, dispatch_uid='handle_deleted_object')
|
|
|
|
|
2018-07-10 13:33:54 -04:00
|
|
|
return response
|
2020-08-14 17:03:45 -04:00
|
|
|
|
|
|
|
# TODO: Put this somewhere
|
|
|
|
# # Housekeeping: 1% chance of clearing out expired ObjectChanges. This applies only to requests which result in
|
|
|
|
# # one or more changes being logged.
|
|
|
|
# if settings.CHANGELOG_RETENTION and random.randint(1, 100) == 1:
|
|
|
|
# cutoff = timezone.now() - timedelta(days=settings.CHANGELOG_RETENTION)
|
|
|
|
# purged_count, _ = ObjectChange.objects.filter(
|
|
|
|
# time__lt=cutoff
|
|
|
|
# ).delete()
|