webhooks.py 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  1. import time
  2. from importlib import import_module
  3. from django.db.models.signals import post_save, post_delete
  4. from django.conf import settings
  5. from django.core.cache import caches
  6. from django.db.models import Q
  7. from django.dispatch import Signal
  8. from django.contrib.contenttypes.models import ContentType
  9. from utilities.utils import dynamic_import
  10. from extras.models import Webhook
  11. def enqueue_webhooks(webhooks, model_class, data, event, signal_received_timestamp):
  12. """
  13. Serialize data and enqueue webhooks
  14. """
  15. serializer_context = {
  16. 'request': None,
  17. }
  18. if isinstance(data, list):
  19. serializer_property = data[0].serializer
  20. serializer_cls = dynamic_import(serializer_property)
  21. serialized_data = serializer_cls(data, context=serializer_context, many=True)
  22. else:
  23. serializer_property = data.serializer
  24. serializer_cls = dynamic_import(serializer_property)
  25. serialized_data = serializer_cls(data, context=serializer_context)
  26. from django_rq import get_queue
  27. webhook_queue = get_queue('default')
  28. for webhook in webhooks:
  29. webhook_queue.enqueue("extras.webhooks_worker.process_webhook",
  30. webhook,
  31. serialized_data.data,
  32. model_class,
  33. event,
  34. signal_received_timestamp)
  35. def post_save_receiver(sender, instance, created, **kwargs):
  36. """
  37. Receives post_save signals from registered models. If the webhook
  38. backend is enabled, queue any webhooks that apply to the event.
  39. """
  40. if settings.WEBHOOKS_ENABLED:
  41. signal_received_timestamp = time.time()
  42. # look for any webhooks that match this event
  43. updated = not created
  44. obj_type = ContentType.objects.get_for_model(sender)
  45. webhooks = Webhook.objects.filter(
  46. Q(enabled=True) &
  47. (
  48. Q(type_create=created) |
  49. Q(type_update=updated)
  50. ) &
  51. Q(obj_type=obj_type)
  52. )
  53. event = 'created' if created else 'updated'
  54. if webhooks:
  55. enqueue_webhooks(webhooks, sender, instance, event, signal_received_timestamp)
  56. def post_delete_receiver(sender, instance, **kwargs):
  57. """
  58. Receives post_delete signals from registered models. If the webhook
  59. backend is enabled, queue any webhooks that apply to the event.
  60. """
  61. if settings.WEBHOOKS_ENABLED:
  62. signal_received_timestamp = time.time()
  63. obj_type = ContentType.objects.get_for_model(sender)
  64. # look for any webhooks that match this event
  65. webhooks = Webhook.objects.filter(enabled=True, type_delete=True, obj_type=obj_type)
  66. if webhooks:
  67. enqueue_webhooks(webhooks, sender, instance, 'deleted', signal_received_timestamp)
  68. def bulk_operation_receiver(sender, **kwargs):
  69. """
  70. Receives bulk_operation_signal signals from registered models. If the webhook
  71. backend is enabled, queue any webhooks that apply to the event.
  72. """
  73. if settings.WEBHOOKS_ENABLED:
  74. signal_received_timestamp = time.time()
  75. event = kwargs['event']
  76. obj_type = ContentType.objects.get_for_model(sender)
  77. # look for any webhooks that match this event
  78. if event == 'created':
  79. webhooks = Webhook.objects.filter(enabled=True, type_create=True, obj_type=obj_type)
  80. elif event == 'updated':
  81. webhooks = Webhook.objects.filter(enabled=True, type_update=True, obj_type=obj_type)
  82. elif event == 'deleted':
  83. webhooks = Webhook.objects.filter(enabled=True, type_delete=True, obj_type=obj_type)
  84. else:
  85. webhooks = None
  86. if webhooks:
  87. enqueue_webhooks(webhooks, sender, list(kwargs['instances']), event, signal_received_timestamp)
  88. # the bulk operation signal is used to overcome signals not being sent for bulk model changes
  89. bulk_operation_signal = Signal(providing_args=["instances", "event"])
  90. bulk_operation_signal.connect(bulk_operation_receiver)
  91. def register_signals(senders):
  92. """
  93. Take a list of senders (Models) and register them to the post_save
  94. and post_delete signal receivers.
  95. """
  96. if settings.WEBHOOKS_ENABLED:
  97. # only register signals if the backend is enabled
  98. # this reduces load by not firing signals if the
  99. # webhook backend feature is disabled
  100. for sender in senders:
  101. post_save.connect(post_save_receiver, sender=sender)
  102. post_delete.connect(post_delete_receiver, sender=sender)