"""passbook outpost signals""" from asgiref.sync import async_to_sync from channels.layers import get_channel_layer from django.db.models import Model from django.db.models.signals import post_save from django.dispatch import receiver from structlog import get_logger from passbook.outposts.models import Outpost, OutpostModel LOGGER = get_logger() @receiver(post_save, sender=Outpost) # pylint: disable=unused-argument def ensure_user_and_token(sender, instance, **_): """Ensure that token is created/updated on save""" _ = instance.token @receiver(post_save) # pylint: disable=unused-argument def post_save_update(sender, instance, **_): """If an OutpostModel, or a model that is somehow connected to an OutpostModel is saved, we send a message down the relevant OutpostModels WS connection to trigger an update""" if isinstance(instance, OutpostModel): LOGGER.debug("triggering outpost update from outpostmodel", instance=instance) _send_update(instance) return for field in instance._meta.get_fields(): # Each field is checked if it has a `related_model` attribute (when ForeginKeys or M2Ms) # are used, and if it has a value if not hasattr(field, "related_model"): continue if not field.related_model: continue if not issubclass(field.related_model, OutpostModel): continue field_name = f"{field.name}_set" if not hasattr(instance, field_name): continue LOGGER.debug("triggering outpost update from from field", field=field.name) # Because the Outpost Model has an M2M to Provider, # we have to iterate over the entire QS for reverse in getattr(instance, field_name).all(): _send_update(reverse) def _send_update(outpost_model: Model): """Send update trigger for each channel of an outpost model""" for outpost in outpost_model.outpost_set.all(): channel_layer = get_channel_layer() for channel in outpost.channels: LOGGER.debug("sending update", channel=channel) async_to_sync(channel_layer.send)(channel, {"type": "event.update"})