コード例 #1
0
def _handle_changed_object(request, sender, instance, **kwargs):
    """
    Fires when an object is created or updated.
    """
    # Queue the object for processing once the request completes
    if kwargs.get("created"):
        action = ObjectChangeActionChoices.ACTION_CREATE
    elif "created" in kwargs:
        action = ObjectChangeActionChoices.ACTION_UPDATE
    elif kwargs.get("action") in ["post_add", "post_remove"] and kwargs["pk_set"]:
        # m2m_changed with objects added or removed
        action = ObjectChangeActionChoices.ACTION_UPDATE
    else:
        return

    # Record an ObjectChange if applicable
    if hasattr(instance, "to_objectchange"):
        objectchange = instance.to_objectchange(action)
        objectchange.user = _get_user_if_authenticated(request, objectchange)
        objectchange.request_id = request.id
        objectchange.save()

    # Enqueue webhooks
    enqueue_webhooks(instance, request.user, request.id, action)

    # Increment metric counters
    if action == ObjectChangeActionChoices.ACTION_CREATE:
        model_inserts.labels(instance._meta.model_name).inc()
    elif action == ObjectChangeActionChoices.ACTION_UPDATE:
        model_updates.labels(instance._meta.model_name).inc()

    # Housekeeping: 0.1% chance of clearing out expired ObjectChanges
    if settings.CHANGELOG_RETENTION and random.randint(1, 1000) == 1:
        cutoff = timezone.now() - timedelta(days=settings.CHANGELOG_RETENTION)
        ObjectChange.objects.filter(time__lt=cutoff).delete()
コード例 #2
0
ファイル: middleware.py プロジェクト: yuta2/netbox
    def __call__(self, request):

        # Initialize an empty list to cache objects being saved.
        _thread_locals.changed_objects = []

        # 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()

        # Connect our receivers to the post_save and post_delete signals.
        post_save.connect(handle_changed_object, dispatch_uid='handle_changed_object')
        pre_delete.connect(handle_deleted_object, dispatch_uid='handle_deleted_object')

        # Provide a hook for purging the change cache
        purge_changelog.connect(purge_objectchange_cache)

        # Process the request
        response = self.get_response(request)

        # If the change cache is empty, there's nothing more we need to do.
        if not _thread_locals.changed_objects:
            return response

        # Create records for any cached objects that were changed.
        for instance, action in _thread_locals.changed_objects:

            # Refresh cached custom field values
            if action in [ObjectChangeActionChoices.ACTION_CREATE, ObjectChangeActionChoices.ACTION_UPDATE]:
                if hasattr(instance, 'cache_custom_fields'):
                    instance.cache_custom_fields()

            # Record an ObjectChange if applicable
            if hasattr(instance, 'to_objectchange'):
                objectchange = instance.to_objectchange(action)
                objectchange.user = request.user
                objectchange.request_id = request.id
                objectchange.save()

            # Enqueue webhooks
            enqueue_webhooks(instance, request.user, request.id, action)

            # Increment metric counters
            if action == ObjectChangeActionChoices.ACTION_CREATE:
                model_inserts.labels(instance._meta.model_name).inc()
            elif action == ObjectChangeActionChoices.ACTION_UPDATE:
                model_updates.labels(instance._meta.model_name).inc()
            elif action == ObjectChangeActionChoices.ACTION_DELETE:
                model_deletes.labels(instance._meta.model_name).inc()

        # 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()

        return response
コード例 #3
0
def _handle_changed_object(request, webhook_queue, sender, instance, **kwargs):
    """
    Fires when an object is created or updated.
    """
    def is_same_object(instance, webhook_data):
        return (
            ContentType.objects.get_for_model(instance) == webhook_data['content_type'] and
            instance.pk == webhook_data['object_id'] and
            request.id == webhook_data['request_id']
        )

    if not hasattr(instance, 'to_objectchange'):
        return

    m2m_changed = False

    # Determine the type of change being made
    if kwargs.get('created'):
        action = ObjectChangeActionChoices.ACTION_CREATE
    elif 'created' in kwargs:
        action = ObjectChangeActionChoices.ACTION_UPDATE
    elif kwargs.get('action') in ['post_add', 'post_remove'] and kwargs['pk_set']:
        # m2m_changed with objects added or removed
        m2m_changed = True
        action = ObjectChangeActionChoices.ACTION_UPDATE
    else:
        return

    # Record an ObjectChange if applicable
    if hasattr(instance, 'to_objectchange'):
        if m2m_changed:
            ObjectChange.objects.filter(
                changed_object_type=ContentType.objects.get_for_model(instance),
                changed_object_id=instance.pk,
                request_id=request.id
            ).update(
                postchange_data=instance.to_objectchange(action).postchange_data
            )
        else:
            objectchange = instance.to_objectchange(action)
            objectchange.user = request.user
            objectchange.request_id = request.id
            objectchange.save()

    # If this is an M2M change, update the previously queued webhook (from post_save)
    if m2m_changed and webhook_queue and is_same_object(instance, webhook_queue[-1]):
        instance.refresh_from_db()  # Ensure that we're working with fresh M2M assignments
        webhook_queue[-1]['data'] = serialize_for_webhook(instance)
        webhook_queue[-1]['snapshots']['postchange'] = get_snapshots(instance, action)['postchange']
    else:
        enqueue_object(webhook_queue, instance, request.user, request.id, action)

    # Increment metric counters
    if action == ObjectChangeActionChoices.ACTION_CREATE:
        model_inserts.labels(instance._meta.model_name).inc()
    elif action == ObjectChangeActionChoices.ACTION_UPDATE:
        model_updates.labels(instance._meta.model_name).inc()
コード例 #4
0
ファイル: signals.py プロジェクト: matt852/nautobot
def _handle_changed_object(request, sender, instance, **kwargs):
    """
    Fires when an object is created or updated.
    """
    m2m_changed = False

    # Determine the type of change being made
    if kwargs.get("created"):
        action = ObjectChangeActionChoices.ACTION_CREATE
    elif "created" in kwargs:
        action = ObjectChangeActionChoices.ACTION_UPDATE
    elif kwargs.get("action") in ["post_add", "post_remove"
                                  ] and kwargs["pk_set"]:
        # m2m_changed with objects added or removed
        m2m_changed = True
        action = ObjectChangeActionChoices.ACTION_UPDATE
    else:
        return

    # Record an ObjectChange if applicable
    if hasattr(instance, "to_objectchange"):
        if m2m_changed:
            ObjectChange.objects.filter(
                changed_object_type=ContentType.objects.get_for_model(
                    instance),
                changed_object_id=instance.pk,
                request_id=request.id,
            ).update(object_data=instance.to_objectchange(action).object_data)
        else:
            objectchange = instance.to_objectchange(action)
            objectchange.user = _get_user_if_authenticated(
                request, objectchange)
            objectchange.request_id = request.id
            objectchange.save()

    # Enqueue webhooks
    enqueue_webhooks(instance, request.user, request.id, action)

    # Increment metric counters
    if action == ObjectChangeActionChoices.ACTION_CREATE:
        model_inserts.labels(instance._meta.model_name).inc()
    elif action == ObjectChangeActionChoices.ACTION_UPDATE:
        model_updates.labels(instance._meta.model_name).inc()

    # Housekeeping: 0.1% chance of clearing out expired ObjectChanges
    changelog_retention = get_settings_or_config("CHANGELOG_RETENTION")
    if changelog_retention and random.randint(1, 1000) == 1:
        cutoff = timezone.now() - timedelta(days=changelog_retention)
        ObjectChange.objects.filter(time__lt=cutoff).delete()
コード例 #5
0
def _handle_changed_object(request, sender, instance, **kwargs):
    """
    Fires when an object is created or updated.
    """
    m2m_changed = False

    # Determine the type of change being made
    if kwargs.get('created'):
        action = ObjectChangeActionChoices.ACTION_CREATE
    elif 'created' in kwargs:
        action = ObjectChangeActionChoices.ACTION_UPDATE
    elif kwargs.get('action') in ['post_add', 'post_remove'] and kwargs['pk_set']:
        # m2m_changed with objects added or removed
        m2m_changed = True
        action = ObjectChangeActionChoices.ACTION_UPDATE
    else:
        return

    # Record an ObjectChange if applicable
    if hasattr(instance, 'to_objectchange'):
        if m2m_changed:
            ObjectChange.objects.filter(
                changed_object_type=ContentType.objects.get_for_model(instance),
                changed_object_id=instance.pk,
                request_id=request.id
            ).update(
                postchange_data=instance.to_objectchange(action).postchange_data
            )
        else:
            objectchange = instance.to_objectchange(action)
            objectchange.user = request.user
            objectchange.request_id = request.id
            objectchange.save()

    # Enqueue webhooks
    enqueue_webhooks(instance, request.user, request.id, action)

    # Increment metric counters
    if action == ObjectChangeActionChoices.ACTION_CREATE:
        model_inserts.labels(instance._meta.model_name).inc()
    elif action == ObjectChangeActionChoices.ACTION_UPDATE:
        model_updates.labels(instance._meta.model_name).inc()

    # Housekeeping: 0.1% chance of clearing out expired ObjectChanges
    if settings.CHANGELOG_RETENTION and random.randint(1, 1000) == 1:
        cutoff = timezone.now() - timedelta(days=settings.CHANGELOG_RETENTION)
        ObjectChange.objects.filter(time__lt=cutoff)._raw_delete(using=DEFAULT_DB_ALIAS)
コード例 #6
0
    def __call__(self, request):

        # Initialize an empty list to cache objects being saved.
        _thread_locals.changed_objects = []

        # 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()

        # Signals don't include the request context, so we're currying it into the post_delete function ahead of time.
        record_object_deleted = curry(_record_object_deleted, request)

        # Connect our receivers to the post_save and post_delete signals.
        post_save.connect(cache_changed_object,
                          dispatch_uid='record_object_saved')
        post_delete.connect(record_object_deleted,
                            dispatch_uid='record_object_deleted')

        # Process the request
        response = self.get_response(request)

        # Create records for any cached objects that were created/updated.
        for obj, action in _thread_locals.changed_objects:

            # Record the change
            if hasattr(obj, 'log_change'):
                obj.log_change(request.user, request.id, action)

            # Enqueue webhooks
            enqueue_webhooks(obj, request.user, request.id, action)

            # Increment metric counters
            if action == OBJECTCHANGE_ACTION_CREATE:
                model_inserts.labels(obj._meta.model_name).inc()
            elif action == OBJECTCHANGE_ACTION_UPDATE:
                model_updates.labels(obj._meta.model_name).inc()

        # Housekeeping: 1% chance of clearing out expired ObjectChanges
        if _thread_locals.changed_objects and 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()

        return response
コード例 #7
0
ファイル: signals.py プロジェクト: 2bithacker/peering-manager
def _handle_changed_object(request, sender, instance, **kwargs):
    """
    Fires when an object is created or updated.
    """
    # Ignore object without the right method
    if not hasattr(instance, "to_objectchange"):
        return

    # Queue the object for processing once the request completes
    if kwargs.get("created"):
        action = ObjectChangeAction.CREATE
    elif "created" in kwargs:
        action = ObjectChangeAction.UPDATE
    elif kwargs.get("action") in ["post_add", "post_remove"] and kwargs["pk_set"]:
        # m2m_changed with objects added or removed
        action = ObjectChangeAction.UPDATE
    else:
        return

    # Record an object change
    change = instance.to_objectchange(action)
    change.user = request.user
    change.request_id = request.id
    change.save()

    # Enqueue webhooks
    enqueue_webhooks(instance, request.user, request.id, action)

    # Increment metric counters
    if action == ObjectChangeAction.CREATE:
        model_inserts.labels(instance._meta.model_name).inc()
    elif action == ObjectChangeAction.UPDATE:
        model_updates.labels(instance._meta.model_name).inc()

    # Housekeeping: 0.1% chance of clearing out expired ObjectChanges
    if settings.CHANGELOG_RETENTION and random.randint(1, 1000) == 1:
        date_limit = timezone.now() - timedelta(days=settings.CHANGELOG_RETENTION)
        ObjectChange.objects.filter(time__lt=date_limit)._raw_delete(
            using=DEFAULT_DB_ALIAS
        )
コード例 #8
0
def handle_changed_object(sender, instance, **kwargs):
    """
    Fires when an object is created or updated.
    """
    # Ignore object without the right method
    if not hasattr(instance, "to_objectchange"):
        return

    request = get_request()
    m2m_changed = False

    def is_same_object(instance, webhook_data):
        return (
            instance.pk == webhook_data["object_id"]
            and request.id == webhook_data["request_id"]
        )

    # Queue the object for processing once the request completes
    if kwargs.get("created"):
        action = ObjectChangeAction.CREATE
    elif "created" in kwargs:
        action = ObjectChangeAction.UPDATE
    elif kwargs.get("action") in ["post_add", "post_remove"] and kwargs["pk_set"]:
        # m2m_changed with objects added or removed
        m2m_changed = True
        action = ObjectChangeAction.UPDATE
    else:
        return

    if m2m_changed:
        ObjectChange.objects.filter(
            changed_object_type=ContentType.objects.get_for_model(instance),
            changed_object_id=instance.pk,
            request_id=request.id,
        ).update(postchange_data=instance.to_objectchange(action).postchange_data)
    else:
        # Record an object change
        change = instance.to_objectchange(action)
        change.user = request.user
        change.request_id = request.id
        change.save()

    # If this is an M2M change, update the previously queued webhook (from post_save)
    webhook_queue = thread_locals.webhook_queue
    if m2m_changed and webhook_queue and is_same_object(instance, webhook_queue[-1]):
        instance.refresh_from_db()  # Ensure that we're working with fresh M2M assignments
        webhook_queue[-1]["data"] = serialize_for_webhook(instance)
        webhook_queue[-1]["snapshots"]["postchange"] = get_snapshots(instance, action)[
            "postchange"
        ]
    else:
        enqueue_object(webhook_queue, instance, request.user, request.id, action)

    # Increment metric counters
    if action == ObjectChangeAction.CREATE:
        model_inserts.labels(instance._meta.model_name).inc()
    elif action == ObjectChangeAction.UPDATE:
        model_updates.labels(instance._meta.model_name).inc()

    # Housekeeping: 0.1% chance of clearing out expired ObjectChanges
    if settings.CHANGELOG_RETENTION and random.randint(1, 1000) == 1:
        date_limit = timezone.now() - timedelta(days=settings.CHANGELOG_RETENTION)
        ObjectChange.objects.filter(time__lt=date_limit)._raw_delete(
            using=DEFAULT_DB_ALIAS
        )