1
0
mirror of https://github.com/netbox-community/netbox.git synced 2024-05-10 07:54:54 +00:00

ObjectChange.action to slug (#3569)

This commit is contained in:
Jeremy Stretch
2019-12-05 16:30:15 -05:00
parent 8efde811e9
commit 2bcbcd3458
11 changed files with 83 additions and 30 deletions

View File

@ -8,6 +8,7 @@ from dcim.api.nested_serializers import (
NestedRegionSerializer, NestedSiteSerializer, NestedRegionSerializer, NestedSiteSerializer,
) )
from dcim.models import Device, DeviceRole, Platform, Rack, Region, Site from dcim.models import Device, DeviceRole, Platform, Rack, Region, Site
from extras.choices import *
from extras.constants import * from extras.constants import *
from extras.models import ( from extras.models import (
ConfigContext, ExportTemplate, Graph, ImageAttachment, ObjectChange, ReportResult, Tag, ConfigContext, ExportTemplate, Graph, ImageAttachment, ObjectChange, ReportResult, Tag,
@ -255,7 +256,7 @@ class ObjectChangeSerializer(serializers.ModelSerializer):
read_only=True read_only=True
) )
action = ChoiceField( action = ChoiceField(
choices=OBJECTCHANGE_ACTION_CHOICES, choices=ObjectChangeActionChoices,
read_only=True read_only=True
) )
changed_object_type = ContentTypeField( changed_object_type = ContentTypeField(

View File

@ -75,3 +75,26 @@ class CustomLinkButtonClassChoices(ChoiceSet):
(CLASS_DANGER, 'Danger (red)'), (CLASS_DANGER, 'Danger (red)'),
(CLASS_LINK, 'None (link)'), (CLASS_LINK, 'None (link)'),
) )
#
# ObjectChanges
#
class ObjectChangeActionChoices(ChoiceSet):
ACTION_CREATE = 'create'
ACTION_UPDATE = 'update'
ACTION_DELETE = 'delete'
CHOICES = (
(ACTION_CREATE, 'Created'),
(ACTION_UPDATE, 'Updated'),
(ACTION_DELETE, 'Deleted'),
)
LEGACY_MAP = {
ACTION_CREATE: 1,
ACTION_UPDATE: 2,
ACTION_DELETE: 3,
}

View File

@ -93,16 +93,6 @@ TEMPLATE_LANGUAGE_CHOICES = (
(TEMPLATE_LANGUAGE_JINJA2, 'Jinja2'), (TEMPLATE_LANGUAGE_JINJA2, 'Jinja2'),
) )
# Change log actions
OBJECTCHANGE_ACTION_CREATE = 1
OBJECTCHANGE_ACTION_UPDATE = 2
OBJECTCHANGE_ACTION_DELETE = 3
OBJECTCHANGE_ACTION_CHOICES = (
(OBJECTCHANGE_ACTION_CREATE, 'Created'),
(OBJECTCHANGE_ACTION_UPDATE, 'Updated'),
(OBJECTCHANGE_ACTION_DELETE, 'Deleted'),
)
# User action types # User action types
ACTION_CREATE = 1 ACTION_CREATE = 1
ACTION_IMPORT = 2 ACTION_IMPORT = 2

View File

@ -401,7 +401,7 @@ class ObjectChangeFilterForm(BootstrapMixin, forms.Form):
) )
) )
action = forms.ChoiceField( action = forms.ChoiceField(
choices=add_blank_choice(OBJECTCHANGE_ACTION_CHOICES), choices=add_blank_choice(ObjectChangeActionChoices),
required=False required=False
) )
user = forms.ModelChoiceField( user = forms.ModelChoiceField(

View File

@ -10,7 +10,7 @@ from django.utils import timezone
from django_prometheus.models import model_deletes, model_inserts, model_updates from django_prometheus.models import model_deletes, model_inserts, model_updates
from utilities.querysets import DummyQuerySet from utilities.querysets import DummyQuerySet
from .constants import * from .choices import ObjectChangeActionChoices
from .models import ObjectChange from .models import ObjectChange
from .signals import purge_changelog from .signals import purge_changelog
from .webhooks import enqueue_webhooks from .webhooks import enqueue_webhooks
@ -23,7 +23,7 @@ def handle_changed_object(sender, instance, **kwargs):
Fires when an object is created or updated. Fires when an object is created or updated.
""" """
# Queue the object for processing once the request completes # Queue the object for processing once the request completes
action = OBJECTCHANGE_ACTION_CREATE if kwargs['created'] else OBJECTCHANGE_ACTION_UPDATE action = ObjectChangeActionChoices.ACTION_CREATE if kwargs['created'] else ObjectChangeActionChoices.ACTION_UPDATE
_thread_locals.changed_objects.append( _thread_locals.changed_objects.append(
(instance, action) (instance, action)
) )
@ -46,7 +46,7 @@ def handle_deleted_object(sender, instance, **kwargs):
# Queue the copy of the object for processing once the request completes # Queue the copy of the object for processing once the request completes
_thread_locals.changed_objects.append( _thread_locals.changed_objects.append(
(copy, OBJECTCHANGE_ACTION_DELETE) (copy, ObjectChangeActionChoices.ACTION_DELETE)
) )
@ -101,7 +101,7 @@ class ObjectChangeMiddleware(object):
for instance, action in _thread_locals.changed_objects: for instance, action in _thread_locals.changed_objects:
# Refresh cached custom field values # Refresh cached custom field values
if action in [OBJECTCHANGE_ACTION_CREATE, OBJECTCHANGE_ACTION_UPDATE]: if action in [ObjectChangeActionChoices.ACTION_CREATE, ObjectChangeActionChoices.ACTION_UPDATE]:
if hasattr(instance, 'cache_custom_fields'): if hasattr(instance, 'cache_custom_fields'):
instance.cache_custom_fields() instance.cache_custom_fields()
@ -116,11 +116,11 @@ class ObjectChangeMiddleware(object):
enqueue_webhooks(instance, request.user, request.id, action) enqueue_webhooks(instance, request.user, request.id, action)
# Increment metric counters # Increment metric counters
if action == OBJECTCHANGE_ACTION_CREATE: if action == ObjectChangeActionChoices.ACTION_CREATE:
model_inserts.labels(instance._meta.model_name).inc() model_inserts.labels(instance._meta.model_name).inc()
elif action == OBJECTCHANGE_ACTION_UPDATE: elif action == ObjectChangeActionChoices.ACTION_UPDATE:
model_updates.labels(instance._meta.model_name).inc() model_updates.labels(instance._meta.model_name).inc()
elif action == OBJECTCHANGE_ACTION_DELETE: elif action == ObjectChangeActionChoices.ACTION_DELETE:
model_deletes.labels(instance._meta.model_name).inc() model_deletes.labels(instance._meta.model_name).inc()
# Housekeeping: 1% chance of clearing out expired ObjectChanges. This applies only to requests which result in # Housekeeping: 1% chance of clearing out expired ObjectChanges. This applies only to requests which result in

View File

@ -0,0 +1,37 @@
from django.db import migrations, models
import django.db.models.deletion
OBJECTCHANGE_ACTION_CHOICES = (
(1, 'create'),
(2, 'update'),
(3, 'delete'),
)
def objectchange_action_to_slug(apps, schema_editor):
ObjectChange = apps.get_model('extras', 'ObjectChange')
for id, slug in OBJECTCHANGE_ACTION_CHOICES:
ObjectChange.objects.filter(action=str(id)).update(action=slug)
class Migration(migrations.Migration):
atomic = False
dependencies = [
('extras', '0029_3569_customfield_fields'),
]
operations = [
# ObjectChange.action
migrations.AlterField(
model_name='objectchange',
name='action',
field=models.CharField(max_length=50),
),
migrations.RunPython(
code=objectchange_action_to_slug
),
]

View File

@ -802,8 +802,9 @@ class ObjectChange(models.Model):
request_id = models.UUIDField( request_id = models.UUIDField(
editable=False editable=False
) )
action = models.PositiveSmallIntegerField( action = models.CharField(
choices=OBJECTCHANGE_ACTION_CHOICES max_length=50,
choices=ObjectChangeActionChoices
) )
changed_object_type = models.ForeignKey( changed_object_type = models.ForeignKey(
to=ContentType, to=ContentType,

View File

@ -50,7 +50,7 @@ class ChangeLogTest(APITestCase):
changed_object_id=site.pk changed_object_id=site.pk
) )
self.assertEqual(oc.changed_object, site) self.assertEqual(oc.changed_object, site)
self.assertEqual(oc.action, OBJECTCHANGE_ACTION_CREATE) self.assertEqual(oc.action, ObjectChangeActionChoices.ACTION_CREATE)
self.assertEqual(oc.object_data['custom_fields'], data['custom_fields']) self.assertEqual(oc.object_data['custom_fields'], data['custom_fields'])
self.assertListEqual(sorted(oc.object_data['tags']), data['tags']) self.assertListEqual(sorted(oc.object_data['tags']), data['tags'])
@ -82,7 +82,7 @@ class ChangeLogTest(APITestCase):
changed_object_id=site.pk changed_object_id=site.pk
) )
self.assertEqual(oc.changed_object, site) self.assertEqual(oc.changed_object, site)
self.assertEqual(oc.action, OBJECTCHANGE_ACTION_UPDATE) self.assertEqual(oc.action, ObjectChangeActionChoices.ACTION_UPDATE)
self.assertEqual(oc.object_data['custom_fields'], data['custom_fields']) self.assertEqual(oc.object_data['custom_fields'], data['custom_fields'])
self.assertListEqual(sorted(oc.object_data['tags']), data['tags']) self.assertListEqual(sorted(oc.object_data['tags']), data['tags'])
@ -111,6 +111,6 @@ class ChangeLogTest(APITestCase):
oc = ObjectChange.objects.first() oc = ObjectChange.objects.first()
self.assertEqual(oc.changed_object, None) self.assertEqual(oc.changed_object, None)
self.assertEqual(oc.object_repr, site.name) self.assertEqual(oc.object_repr, site.name)
self.assertEqual(oc.action, OBJECTCHANGE_ACTION_DELETE) self.assertEqual(oc.action, ObjectChangeActionChoices.ACTION_DELETE)
self.assertEqual(oc.object_data['custom_fields'], {'my_field': 'ABC'}) self.assertEqual(oc.object_data['custom_fields'], {'my_field': 'ABC'})
self.assertListEqual(sorted(oc.object_data['tags']), ['bar', 'foo']) self.assertListEqual(sorted(oc.object_data['tags']), ['bar', 'foo'])

View File

@ -6,7 +6,7 @@ from django.test import Client, TestCase
from django.urls import reverse from django.urls import reverse
from dcim.models import Site from dcim.models import Site
from extras.constants import OBJECTCHANGE_ACTION_UPDATE from extras.choices import ObjectChangeActionChoices
from extras.models import ConfigContext, ObjectChange, Tag from extras.models import ConfigContext, ObjectChange, Tag
from utilities.testing import create_test_user from utilities.testing import create_test_user
@ -83,7 +83,7 @@ class ObjectChangeTestCase(TestCase):
# Create three ObjectChanges # Create three ObjectChanges
for i in range(1, 4): for i in range(1, 4):
oc = site.to_objectchange(action=OBJECTCHANGE_ACTION_UPDATE) oc = site.to_objectchange(action=ObjectChangeActionChoices.ACTION_UPDATE)
oc.user = user oc.user = user
oc.request_id = uuid.uuid4() oc.request_id = uuid.uuid4()
oc.save() oc.save()

View File

@ -5,6 +5,7 @@ from django.contrib.contenttypes.models import ContentType
from extras.models import Webhook from extras.models import Webhook
from utilities.api import get_serializer_for_model from utilities.api import get_serializer_for_model
from .choices import *
from .constants import * from .constants import *
@ -18,9 +19,9 @@ def enqueue_webhooks(instance, user, request_id, action):
# Retrieve any applicable Webhooks # Retrieve any applicable Webhooks
action_flag = { action_flag = {
OBJECTCHANGE_ACTION_CREATE: 'type_create', ObjectChangeActionChoices.ACTION_CREATE: 'type_create',
OBJECTCHANGE_ACTION_UPDATE: 'type_update', ObjectChangeActionChoices.ACTION_UPDATE: 'type_update',
OBJECTCHANGE_ACTION_DELETE: 'type_delete', ObjectChangeActionChoices.ACTION_DELETE: 'type_delete',
}[action] }[action]
obj_type = ContentType.objects.get_for_model(instance.__class__) obj_type = ContentType.objects.get_for_model(instance.__class__)
webhooks = Webhook.objects.filter(obj_type=obj_type, enabled=True, **{action_flag: True}) webhooks = Webhook.objects.filter(obj_type=obj_type, enabled=True, **{action_flag: True})

View File

@ -15,7 +15,7 @@ def process_webhook(webhook, data, model_name, event, timestamp, username, reque
Make a POST request to the defined Webhook Make a POST request to the defined Webhook
""" """
payload = { payload = {
'event': dict(OBJECTCHANGE_ACTION_CHOICES)[event].lower(), 'event': event,
'timestamp': timestamp, 'timestamp': timestamp,
'model': model_name, 'model': model_name,
'username': username, 'username': username,