2020-09-21 19:16:14 +01:00
|
|
|
"""Audit middleware"""
|
|
|
|
from functools import partial
|
|
|
|
from typing import Callable
|
|
|
|
|
|
|
|
from django.contrib.auth.models import User
|
|
|
|
from django.db.models import Model
|
|
|
|
from django.db.models.signals import post_save, pre_delete
|
|
|
|
from django.http import HttpRequest, HttpResponse
|
|
|
|
|
|
|
|
from passbook.audit.models import Event, EventAction, model_to_dict
|
|
|
|
from passbook.audit.signals import EventNewThread
|
|
|
|
from passbook.core.middleware import LOCAL
|
|
|
|
|
|
|
|
|
|
|
|
class AuditMiddleware:
|
|
|
|
"""Register handlers for duration of request-response that log creation/update/deletion
|
|
|
|
of models"""
|
|
|
|
|
|
|
|
get_response: Callable[[HttpRequest], HttpResponse]
|
|
|
|
|
|
|
|
def __init__(self, get_response: Callable[[HttpRequest], HttpResponse]):
|
|
|
|
self.get_response = get_response
|
|
|
|
|
|
|
|
def __call__(self, request: HttpRequest) -> HttpResponse:
|
|
|
|
# Connect signal for automatic logging
|
|
|
|
if hasattr(request, "user") and getattr(
|
|
|
|
request.user, "is_authenticated", False
|
|
|
|
):
|
|
|
|
post_save_handler = partial(
|
|
|
|
self.post_save_handler, user=request.user, request=request
|
|
|
|
)
|
|
|
|
pre_delete_handler = partial(
|
|
|
|
self.pre_delete_handler, user=request.user, request=request
|
|
|
|
)
|
|
|
|
post_save.connect(
|
|
|
|
post_save_handler,
|
|
|
|
dispatch_uid=LOCAL.passbook["request_id"],
|
|
|
|
weak=False,
|
|
|
|
)
|
|
|
|
pre_delete.connect(
|
|
|
|
pre_delete_handler,
|
|
|
|
dispatch_uid=LOCAL.passbook["request_id"],
|
|
|
|
weak=False,
|
|
|
|
)
|
|
|
|
|
|
|
|
response = self.get_response(request)
|
|
|
|
|
|
|
|
post_save.disconnect(dispatch_uid=LOCAL.passbook["request_id"])
|
|
|
|
pre_delete.disconnect(dispatch_uid=LOCAL.passbook["request_id"])
|
|
|
|
|
|
|
|
return response
|
|
|
|
|
|
|
|
# pylint: disable=unused-argument
|
|
|
|
def process_exception(self, request: HttpRequest, exception: Exception):
|
|
|
|
"""Unregister handlers in case of exception"""
|
|
|
|
post_save.disconnect(dispatch_uid=LOCAL.passbook["request_id"])
|
|
|
|
pre_delete.disconnect(dispatch_uid=LOCAL.passbook["request_id"])
|
|
|
|
|
|
|
|
@staticmethod
|
|
|
|
# pylint: disable=unused-argument
|
|
|
|
def post_save_handler(
|
|
|
|
user: User, request: HttpRequest, sender, instance: Model, created: bool, **_
|
|
|
|
):
|
|
|
|
"""Signal handler for all object's post_save"""
|
|
|
|
if isinstance(instance, Event):
|
|
|
|
return
|
|
|
|
|
|
|
|
action = EventAction.MODEL_CREATED if created else EventAction.MODEL_UPDATED
|
2020-09-21 21:34:03 +01:00
|
|
|
EventNewThread(action, request, user=user, model=model_to_dict(instance)).run()
|
2020-09-21 19:16:14 +01:00
|
|
|
|
|
|
|
@staticmethod
|
|
|
|
# pylint: disable=unused-argument
|
|
|
|
def pre_delete_handler(
|
|
|
|
user: User, request: HttpRequest, sender, instance: Model, **_
|
|
|
|
):
|
|
|
|
"""Signal handler for all object's pre_delete"""
|
|
|
|
if isinstance(instance, Event):
|
|
|
|
return
|
|
|
|
|
|
|
|
EventNewThread(
|
|
|
|
EventAction.MODEL_DELETED,
|
|
|
|
request,
|
|
|
|
user=user,
|
2020-09-21 21:34:03 +01:00
|
|
|
model=model_to_dict(instance),
|
2020-09-21 19:16:14 +01:00
|
|
|
).run()
|