mirror of
https://github.com/netbox-community/netbox.git
synced 2025-07-23 04:22:01 -06:00
Implemented changelog views
This commit is contained in:
parent
a8b11e45c1
commit
ddd878683d
@ -2,7 +2,7 @@ from __future__ import unicode_literals
|
||||
|
||||
from django.conf.urls import url
|
||||
|
||||
from extras.views import ChangeLogView
|
||||
from extras.views import ObjectChangeLogView
|
||||
from . import views
|
||||
from .models import Circuit, CircuitType, Provider
|
||||
|
||||
@ -18,7 +18,7 @@ urlpatterns = [
|
||||
url(r'^providers/(?P<slug>[\w-]+)/$', views.ProviderView.as_view(), name='provider'),
|
||||
url(r'^providers/(?P<slug>[\w-]+)/edit/$', views.ProviderEditView.as_view(), name='provider_edit'),
|
||||
url(r'^providers/(?P<slug>[\w-]+)/delete/$', views.ProviderDeleteView.as_view(), name='provider_delete'),
|
||||
url(r'^providers/(?P<slug>[\w-]+)/changelog/$', ChangeLogView.as_view(), name='provider_changelog', kwargs={'model': Provider}),
|
||||
url(r'^providers/(?P<slug>[\w-]+)/changelog/$', ObjectChangeLogView.as_view(), name='provider_changelog', kwargs={'model': Provider}),
|
||||
|
||||
# Circuit types
|
||||
url(r'^circuit-types/$', views.CircuitTypeListView.as_view(), name='circuittype_list'),
|
||||
@ -26,7 +26,7 @@ urlpatterns = [
|
||||
url(r'^circuit-types/import/$', views.CircuitTypeBulkImportView.as_view(), name='circuittype_import'),
|
||||
url(r'^circuit-types/delete/$', views.CircuitTypeBulkDeleteView.as_view(), name='circuittype_bulk_delete'),
|
||||
url(r'^circuit-types/(?P<slug>[\w-]+)/edit/$', views.CircuitTypeEditView.as_view(), name='circuittype_edit'),
|
||||
url(r'^circuit-types/(?P<slug>[\w-]+)/changelog/$', ChangeLogView.as_view(), name='circuittype_changelog', kwargs={'model': CircuitType}),
|
||||
url(r'^circuit-types/(?P<slug>[\w-]+)/changelog/$', ObjectChangeLogView.as_view(), name='circuittype_changelog', kwargs={'model': CircuitType}),
|
||||
|
||||
# Circuits
|
||||
url(r'^circuits/$', views.CircuitListView.as_view(), name='circuit_list'),
|
||||
@ -37,7 +37,7 @@ urlpatterns = [
|
||||
url(r'^circuits/(?P<pk>\d+)/$', views.CircuitView.as_view(), name='circuit'),
|
||||
url(r'^circuits/(?P<pk>\d+)/edit/$', views.CircuitEditView.as_view(), name='circuit_edit'),
|
||||
url(r'^circuits/(?P<pk>\d+)/delete/$', views.CircuitDeleteView.as_view(), name='circuit_delete'),
|
||||
url(r'^circuits/(?P<pk>\d+)/changelog/$', ChangeLogView.as_view(), name='circuit_changelog', kwargs={'model': Circuit}),
|
||||
url(r'^circuits/(?P<pk>\d+)/changelog/$', ObjectChangeLogView.as_view(), name='circuit_changelog', kwargs={'model': Circuit}),
|
||||
url(r'^circuits/(?P<pk>\d+)/terminations/swap/$', views.circuit_terminations_swap, name='circuit_terminations_swap'),
|
||||
|
||||
# Circuit terminations
|
||||
|
@ -2,7 +2,7 @@ from __future__ import unicode_literals
|
||||
|
||||
from django.conf.urls import url
|
||||
|
||||
from extras.views import ChangeLogView, ImageAttachmentEditView
|
||||
from extras.views import ObjectChangeLogView, ImageAttachmentEditView
|
||||
from ipam.views import ServiceCreateView
|
||||
from secrets.views import secret_add
|
||||
from . import views
|
||||
@ -20,7 +20,7 @@ urlpatterns = [
|
||||
url(r'^regions/import/$', views.RegionBulkImportView.as_view(), name='region_import'),
|
||||
url(r'^regions/delete/$', views.RegionBulkDeleteView.as_view(), name='region_bulk_delete'),
|
||||
url(r'^regions/(?P<pk>\d+)/edit/$', views.RegionEditView.as_view(), name='region_edit'),
|
||||
url(r'^regions/(?P<pk>\d+)/changelog/$', ChangeLogView.as_view(), name='region_changelog', kwargs={'model': Region}),
|
||||
url(r'^regions/(?P<pk>\d+)/changelog/$', ObjectChangeLogView.as_view(), name='region_changelog', kwargs={'model': Region}),
|
||||
|
||||
# Sites
|
||||
url(r'^sites/$', views.SiteListView.as_view(), name='site_list'),
|
||||
@ -30,7 +30,7 @@ urlpatterns = [
|
||||
url(r'^sites/(?P<slug>[\w-]+)/$', views.SiteView.as_view(), name='site'),
|
||||
url(r'^sites/(?P<slug>[\w-]+)/edit/$', views.SiteEditView.as_view(), name='site_edit'),
|
||||
url(r'^sites/(?P<slug>[\w-]+)/delete/$', views.SiteDeleteView.as_view(), name='site_delete'),
|
||||
url(r'^sites/(?P<slug>[\w-]+)/changelog/$', ChangeLogView.as_view(), name='site_changelog', kwargs={'model': Site}),
|
||||
url(r'^sites/(?P<slug>[\w-]+)/changelog/$', ObjectChangeLogView.as_view(), name='site_changelog', kwargs={'model': Site}),
|
||||
url(r'^sites/(?P<object_id>\d+)/images/add/$', ImageAttachmentEditView.as_view(), name='site_add_image', kwargs={'model': Site}),
|
||||
|
||||
# Rack groups
|
||||
@ -39,7 +39,7 @@ urlpatterns = [
|
||||
url(r'^rack-groups/import/$', views.RackGroupBulkImportView.as_view(), name='rackgroup_import'),
|
||||
url(r'^rack-groups/delete/$', views.RackGroupBulkDeleteView.as_view(), name='rackgroup_bulk_delete'),
|
||||
url(r'^rack-groups/(?P<pk>\d+)/edit/$', views.RackGroupEditView.as_view(), name='rackgroup_edit'),
|
||||
url(r'^rack-groups/(?P<pk>\d+)/changelog/$', ChangeLogView.as_view(), name='rackgroup_changelog', kwargs={'model': RackGroup}),
|
||||
url(r'^rack-groups/(?P<pk>\d+)/changelog/$', ObjectChangeLogView.as_view(), name='rackgroup_changelog', kwargs={'model': RackGroup}),
|
||||
|
||||
# Rack roles
|
||||
url(r'^rack-roles/$', views.RackRoleListView.as_view(), name='rackrole_list'),
|
||||
@ -47,7 +47,7 @@ urlpatterns = [
|
||||
url(r'^rack-roles/import/$', views.RackRoleBulkImportView.as_view(), name='rackrole_import'),
|
||||
url(r'^rack-roles/delete/$', views.RackRoleBulkDeleteView.as_view(), name='rackrole_bulk_delete'),
|
||||
url(r'^rack-roles/(?P<pk>\d+)/edit/$', views.RackRoleEditView.as_view(), name='rackrole_edit'),
|
||||
url(r'^rack-roles/(?P<pk>\d+)/changelog/$', ChangeLogView.as_view(), name='rackrole_changelog', kwargs={'model': RackRole}),
|
||||
url(r'^rack-roles/(?P<pk>\d+)/changelog/$', ObjectChangeLogView.as_view(), name='rackrole_changelog', kwargs={'model': RackRole}),
|
||||
|
||||
# Rack reservations
|
||||
url(r'^rack-reservations/$', views.RackReservationListView.as_view(), name='rackreservation_list'),
|
||||
@ -55,7 +55,7 @@ urlpatterns = [
|
||||
url(r'^rack-reservations/delete/$', views.RackReservationBulkDeleteView.as_view(), name='rackreservation_bulk_delete'),
|
||||
url(r'^rack-reservations/(?P<pk>\d+)/edit/$', views.RackReservationEditView.as_view(), name='rackreservation_edit'),
|
||||
url(r'^rack-reservations/(?P<pk>\d+)/delete/$', views.RackReservationDeleteView.as_view(), name='rackreservation_delete'),
|
||||
url(r'^rack-reservations/(?P<pk>\d+)/changelog/$', ChangeLogView.as_view(), name='rackreservation_changelog', kwargs={'model': RackReservation}),
|
||||
url(r'^rack-reservations/(?P<pk>\d+)/changelog/$', ObjectChangeLogView.as_view(), name='rackreservation_changelog', kwargs={'model': RackReservation}),
|
||||
|
||||
# Racks
|
||||
url(r'^racks/$', views.RackListView.as_view(), name='rack_list'),
|
||||
@ -67,7 +67,7 @@ urlpatterns = [
|
||||
url(r'^racks/(?P<pk>\d+)/$', views.RackView.as_view(), name='rack'),
|
||||
url(r'^racks/(?P<pk>\d+)/edit/$', views.RackEditView.as_view(), name='rack_edit'),
|
||||
url(r'^racks/(?P<pk>\d+)/delete/$', views.RackDeleteView.as_view(), name='rack_delete'),
|
||||
url(r'^racks/(?P<pk>\d+)/changelog/$', ChangeLogView.as_view(), name='rack_changelog', kwargs={'model': Rack}),
|
||||
url(r'^racks/(?P<pk>\d+)/changelog/$', ObjectChangeLogView.as_view(), name='rack_changelog', kwargs={'model': Rack}),
|
||||
url(r'^racks/(?P<rack>\d+)/reservations/add/$', views.RackReservationCreateView.as_view(), name='rack_add_reservation'),
|
||||
url(r'^racks/(?P<object_id>\d+)/images/add/$', ImageAttachmentEditView.as_view(), name='rack_add_image', kwargs={'model': Rack}),
|
||||
|
||||
@ -77,7 +77,7 @@ urlpatterns = [
|
||||
url(r'^manufacturers/import/$', views.ManufacturerBulkImportView.as_view(), name='manufacturer_import'),
|
||||
url(r'^manufacturers/delete/$', views.ManufacturerBulkDeleteView.as_view(), name='manufacturer_bulk_delete'),
|
||||
url(r'^manufacturers/(?P<slug>[\w-]+)/edit/$', views.ManufacturerEditView.as_view(), name='manufacturer_edit'),
|
||||
url(r'^manufacturers/(?P<slug>[\w-]+)/changelog/$', ChangeLogView.as_view(), name='manufacturer_changelog', kwargs={'model': Manufacturer}),
|
||||
url(r'^manufacturers/(?P<slug>[\w-]+)/changelog/$', ObjectChangeLogView.as_view(), name='manufacturer_changelog', kwargs={'model': Manufacturer}),
|
||||
|
||||
# Device types
|
||||
url(r'^device-types/$', views.DeviceTypeListView.as_view(), name='devicetype_list'),
|
||||
@ -88,7 +88,7 @@ urlpatterns = [
|
||||
url(r'^device-types/(?P<pk>\d+)/$', views.DeviceTypeView.as_view(), name='devicetype'),
|
||||
url(r'^device-types/(?P<pk>\d+)/edit/$', views.DeviceTypeEditView.as_view(), name='devicetype_edit'),
|
||||
url(r'^device-types/(?P<pk>\d+)/delete/$', views.DeviceTypeDeleteView.as_view(), name='devicetype_delete'),
|
||||
url(r'^device-types/(?P<pk>\d+)/changelog/$', ChangeLogView.as_view(), name='devicetype_changelog', kwargs={'model': DeviceType}),
|
||||
url(r'^device-types/(?P<pk>\d+)/changelog/$', ObjectChangeLogView.as_view(), name='devicetype_changelog', kwargs={'model': DeviceType}),
|
||||
|
||||
# Console port templates
|
||||
url(r'^device-types/(?P<pk>\d+)/console-ports/add/$', views.ConsolePortTemplateCreateView.as_view(), name='devicetype_add_consoleport'),
|
||||
@ -121,7 +121,7 @@ urlpatterns = [
|
||||
url(r'^device-roles/import/$', views.DeviceRoleBulkImportView.as_view(), name='devicerole_import'),
|
||||
url(r'^device-roles/delete/$', views.DeviceRoleBulkDeleteView.as_view(), name='devicerole_bulk_delete'),
|
||||
url(r'^device-roles/(?P<slug>[\w-]+)/edit/$', views.DeviceRoleEditView.as_view(), name='devicerole_edit'),
|
||||
url(r'^device-roles/(?P<slug>[\w-]+)/changelog/$', ChangeLogView.as_view(), name='devicerole_changelog', kwargs={'model': DeviceRole}),
|
||||
url(r'^device-roles/(?P<slug>[\w-]+)/changelog/$', ObjectChangeLogView.as_view(), name='devicerole_changelog', kwargs={'model': DeviceRole}),
|
||||
|
||||
# Platforms
|
||||
url(r'^platforms/$', views.PlatformListView.as_view(), name='platform_list'),
|
||||
@ -129,7 +129,7 @@ urlpatterns = [
|
||||
url(r'^platforms/import/$', views.PlatformBulkImportView.as_view(), name='platform_import'),
|
||||
url(r'^platforms/delete/$', views.PlatformBulkDeleteView.as_view(), name='platform_bulk_delete'),
|
||||
url(r'^platforms/(?P<slug>[\w-]+)/edit/$', views.PlatformEditView.as_view(), name='platform_edit'),
|
||||
url(r'^platforms/(?P<slug>[\w-]+)/changelog/$', ChangeLogView.as_view(), name='platform_changelog', kwargs={'model': Platform}),
|
||||
url(r'^platforms/(?P<slug>[\w-]+)/changelog/$', ObjectChangeLogView.as_view(), name='platform_changelog', kwargs={'model': Platform}),
|
||||
|
||||
# Devices
|
||||
url(r'^devices/$', views.DeviceListView.as_view(), name='device_list'),
|
||||
@ -141,7 +141,7 @@ urlpatterns = [
|
||||
url(r'^devices/(?P<pk>\d+)/$', views.DeviceView.as_view(), name='device'),
|
||||
url(r'^devices/(?P<pk>\d+)/edit/$', views.DeviceEditView.as_view(), name='device_edit'),
|
||||
url(r'^devices/(?P<pk>\d+)/delete/$', views.DeviceDeleteView.as_view(), name='device_delete'),
|
||||
url(r'^devices/(?P<pk>\d+)/changelog/$', ChangeLogView.as_view(), name='device_changelog', kwargs={'model': Device}),
|
||||
url(r'^devices/(?P<pk>\d+)/changelog/$', ObjectChangeLogView.as_view(), name='device_changelog', kwargs={'model': Device}),
|
||||
url(r'^devices/(?P<pk>\d+)/inventory/$', views.DeviceInventoryView.as_view(), name='device_inventory'),
|
||||
url(r'^devices/(?P<pk>\d+)/status/$', views.DeviceStatusView.as_view(), name='device_status'),
|
||||
url(r'^devices/(?P<pk>\d+)/lldp-neighbors/$', views.DeviceLLDPNeighborsView.as_view(), name='device_lldp_neighbors'),
|
||||
@ -235,7 +235,7 @@ urlpatterns = [
|
||||
url(r'^virtual-chassis/add/$', views.VirtualChassisCreateView.as_view(), name='virtualchassis_add'),
|
||||
url(r'^virtual-chassis/(?P<pk>\d+)/edit/$', views.VirtualChassisEditView.as_view(), name='virtualchassis_edit'),
|
||||
url(r'^virtual-chassis/(?P<pk>\d+)/delete/$', views.VirtualChassisDeleteView.as_view(), name='virtualchassis_delete'),
|
||||
url(r'^virtual-chassis/(?P<pk>\d+)/changelog/$', ChangeLogView.as_view(), name='virtualchassis_changelog', kwargs={'model': VirtualChassis}),
|
||||
url(r'^virtual-chassis/(?P<pk>\d+)/changelog/$', ObjectChangeLogView.as_view(), name='virtualchassis_changelog', kwargs={'model': VirtualChassis}),
|
||||
url(r'^virtual-chassis/(?P<pk>\d+)/add-member/$', views.VirtualChassisAddMemberView.as_view(), name='virtualchassis_add_member'),
|
||||
url(r'^virtual-chassis-members/(?P<pk>\d+)/delete/$', views.VirtualChassisRemoveMemberView.as_view(), name='virtualchassis_remove_member'),
|
||||
|
||||
|
@ -129,6 +129,7 @@ class ObjectChangeFilter(django_filters.FilterSet):
|
||||
method='search',
|
||||
label='Search',
|
||||
)
|
||||
time = django_filters.DateTimeFromToRangeFilter()
|
||||
|
||||
class Meta:
|
||||
model = ObjectChange
|
||||
|
@ -3,12 +3,16 @@ from __future__ import unicode_literals
|
||||
from collections import OrderedDict
|
||||
|
||||
from django import forms
|
||||
from django.contrib.auth.models import User
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
from taggit.models import Tag
|
||||
|
||||
from utilities.forms import BootstrapMixin, BulkEditForm, LaxURLField, SlugField
|
||||
from .constants import CF_FILTER_DISABLED, CF_TYPE_BOOLEAN, CF_TYPE_DATE, CF_TYPE_INTEGER, CF_TYPE_SELECT, CF_TYPE_URL
|
||||
from .models import CustomField, CustomFieldValue, ImageAttachment
|
||||
from utilities.forms import add_blank_choice, BootstrapMixin, BulkEditForm, LaxURLField, SlugField
|
||||
from .constants import (
|
||||
CF_FILTER_DISABLED, CF_TYPE_BOOLEAN, CF_TYPE_DATE, CF_TYPE_INTEGER, CF_TYPE_SELECT, CF_TYPE_URL,
|
||||
OBJECTCHANGE_ACTION_CHOICES,
|
||||
)
|
||||
from .models import CustomField, CustomFieldValue, ImageAttachment, ObjectChange
|
||||
|
||||
|
||||
#
|
||||
@ -189,3 +193,38 @@ class ImageAttachmentForm(BootstrapMixin, forms.ModelForm):
|
||||
class Meta:
|
||||
model = ImageAttachment
|
||||
fields = ['name', 'image']
|
||||
|
||||
|
||||
#
|
||||
# Change logging
|
||||
#
|
||||
|
||||
class ObjectChangeFilterForm(BootstrapMixin, CustomFieldFilterForm):
|
||||
model = ObjectChange
|
||||
q = forms.CharField(
|
||||
required=False,
|
||||
label='Search'
|
||||
)
|
||||
# TODO: Change time_0 and time_1 to time_after and time_before for django-filter==2.0
|
||||
time_0 = forms.DateTimeField(
|
||||
label='After',
|
||||
required=False,
|
||||
widget=forms.TextInput(
|
||||
attrs={'placeholder': 'YYYY-MM-DD hh:mm:ss'}
|
||||
)
|
||||
)
|
||||
time_1 = forms.DateTimeField(
|
||||
label='Before',
|
||||
required=False,
|
||||
widget=forms.TextInput(
|
||||
attrs={'placeholder': 'YYYY-MM-DD hh:mm:ss'}
|
||||
)
|
||||
)
|
||||
action = forms.ChoiceField(
|
||||
choices=add_blank_choice(OBJECTCHANGE_ACTION_CHOICES),
|
||||
required=False
|
||||
)
|
||||
user = forms.ModelChoiceField(
|
||||
queryset=User.objects.order_by('username'),
|
||||
required=False
|
||||
)
|
||||
|
@ -9,6 +9,7 @@ from django.contrib.auth.models import User
|
||||
from django.contrib.contenttypes.fields import GenericForeignKey
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
from django.contrib.postgres.fields import JSONField
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.core.validators import ValidationError
|
||||
from django.db import models
|
||||
from django.db.models import Q
|
||||
@ -704,15 +705,18 @@ class ObjectChange(models.Model):
|
||||
editable=False
|
||||
)
|
||||
|
||||
serializer = 'extras.api.serializers.ObjectChangeSerializer'
|
||||
csv_headers = ['time', 'user', 'request_id', 'action', 'content_type', 'object_id', 'object_repr', 'object_data']
|
||||
|
||||
class Meta:
|
||||
ordering = ['-time']
|
||||
|
||||
def __str__(self):
|
||||
attribution = 'by {}'.format(self.user_name) if self.user_name else '(no attribution)'
|
||||
return '{} {} {}'.format(
|
||||
return '{} {} {} by {}'.format(
|
||||
self.content_type,
|
||||
self.object_repr,
|
||||
self.get_action_display().lower(),
|
||||
attribution
|
||||
self.user_name
|
||||
)
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
@ -724,6 +728,21 @@ class ObjectChange(models.Model):
|
||||
|
||||
return super(ObjectChange, self).save(*args, **kwargs)
|
||||
|
||||
def get_absolute_url(self):
|
||||
return reverse('extras:objectchange', args=[self.pk])
|
||||
|
||||
def to_csv(self):
|
||||
return (
|
||||
self.time,
|
||||
self.user or self.user_name,
|
||||
self.request_id,
|
||||
self.get_action_display(),
|
||||
self.content_type,
|
||||
self.object_id,
|
||||
self.object_repr,
|
||||
self.object_data,
|
||||
)
|
||||
|
||||
@property
|
||||
def object_data_pretty(self):
|
||||
return json.dumps(self.object_data, indent=4, sort_keys=True)
|
||||
|
@ -4,6 +4,7 @@ import django_tables2 as tables
|
||||
from taggit.models import Tag
|
||||
|
||||
from utilities.tables import BaseTable, ToggleColumn
|
||||
from .models import ObjectChange
|
||||
|
||||
TAG_ACTIONS = """
|
||||
{% if perms.taggit.change_tag %}
|
||||
@ -14,6 +15,24 @@ TAG_ACTIONS = """
|
||||
{% endif %}
|
||||
"""
|
||||
|
||||
OBJECTCHANGE_ACTION = """
|
||||
{% if record.action == 1 %}
|
||||
<span class="label label-success">Created</span>
|
||||
{% elif record.action == 2 %}
|
||||
<span class="label label-primary">Updated</span>
|
||||
{% elif record.action == 3 %}
|
||||
<span class="label label-danger">Deleted</span>
|
||||
{% endif %}
|
||||
"""
|
||||
|
||||
OBJECTCHANGE_OBJECT = """
|
||||
{% if record.action != 3 and record.changed_object.get_absolute_url %}
|
||||
<a href="{{ record.changed_object.get_absolute_url }}">{{ record.object_repr }}</a>
|
||||
{% else %}
|
||||
{{ record.object_repr }}
|
||||
{% endif %}
|
||||
"""
|
||||
|
||||
|
||||
class TagTable(BaseTable):
|
||||
pk = ToggleColumn()
|
||||
@ -26,3 +45,21 @@ class TagTable(BaseTable):
|
||||
class Meta(BaseTable.Meta):
|
||||
model = Tag
|
||||
fields = ('pk', 'name', 'items')
|
||||
|
||||
|
||||
class ObjectChangeTable(BaseTable):
|
||||
time = tables.LinkColumn()
|
||||
action = tables.TemplateColumn(
|
||||
template_code=OBJECTCHANGE_ACTION
|
||||
)
|
||||
object_repr = tables.TemplateColumn(
|
||||
template_code=OBJECTCHANGE_OBJECT,
|
||||
verbose_name='Object'
|
||||
)
|
||||
request_id = tables.Column(
|
||||
verbose_name='Request ID'
|
||||
)
|
||||
|
||||
class Meta(BaseTable.Meta):
|
||||
model = ObjectChange
|
||||
fields = ('time', 'user_name', 'action', 'content_type', 'object_repr', 'request_id')
|
||||
|
@ -22,4 +22,8 @@ urlpatterns = [
|
||||
url(r'^reports/(?P<name>[^/]+\.[^/]+)/$', views.ReportView.as_view(), name='report'),
|
||||
url(r'^reports/(?P<name>[^/]+\.[^/]+)/run/$', views.ReportRunView.as_view(), name='report_run'),
|
||||
|
||||
# Change logging
|
||||
url(r'^changelog/$', views.ObjectChangeListView.as_view(), name='objectchange_list'),
|
||||
url(r'^changelog/(?P<pk>\d+)/$', views.ObjectChangeView.as_view(), name='objectchange'),
|
||||
|
||||
]
|
||||
|
@ -13,10 +13,11 @@ from taggit.models import Tag
|
||||
|
||||
from utilities.forms import ConfirmationForm
|
||||
from utilities.views import BulkDeleteView, ObjectDeleteView, ObjectEditView, ObjectListView
|
||||
from .forms import ImageAttachmentForm, TagForm
|
||||
from . import filters
|
||||
from .forms import ObjectChangeFilterForm, ImageAttachmentForm, TagForm
|
||||
from .models import ImageAttachment, ObjectChange, ReportResult, UserAction
|
||||
from .reports import get_report, get_reports
|
||||
from .tables import TagTable
|
||||
from .tables import ObjectChangeTable, TagTable
|
||||
|
||||
|
||||
#
|
||||
@ -56,9 +57,36 @@ class TagBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
|
||||
# Change logging
|
||||
#
|
||||
|
||||
class ChangeLogView(View):
|
||||
class ObjectChangeListView(ObjectListView):
|
||||
queryset = ObjectChange.objects.select_related('user', 'content_type')
|
||||
filter = filters.ObjectChangeFilter
|
||||
filter_form = ObjectChangeFilterForm
|
||||
table = ObjectChangeTable
|
||||
template_name = 'extras/objectchange_list.html'
|
||||
|
||||
|
||||
class ObjectChangeView(View):
|
||||
|
||||
def get(self, request, pk):
|
||||
|
||||
objectchange = get_object_or_404(ObjectChange, pk=pk)
|
||||
|
||||
related_changes = ObjectChange.objects.filter(request_id=objectchange.request_id).exclude(pk=objectchange.pk)
|
||||
related_changes_table = ObjectChangeTable(
|
||||
data=related_changes[:50],
|
||||
orderable=False
|
||||
)
|
||||
|
||||
return render(request, 'extras/objectchange.html', {
|
||||
'objectchange': objectchange,
|
||||
'related_changes_table': related_changes_table,
|
||||
'related_changes_count': related_changes.count()
|
||||
})
|
||||
|
||||
|
||||
class ObjectChangeLogView(View):
|
||||
"""
|
||||
Present a history of changes made to an object.
|
||||
Present a history of changes made to a particular object.
|
||||
"""
|
||||
|
||||
def get(self, request, model, **kwargs):
|
||||
@ -68,7 +96,16 @@ class ChangeLogView(View):
|
||||
|
||||
# Gather all changes for this object
|
||||
content_type = ContentType.objects.get_for_model(model)
|
||||
changes = ObjectChange.objects.filter(content_type=content_type, object_id=obj.pk)
|
||||
objectchanges = ObjectChange.objects.select_related(
|
||||
'user', 'content_type'
|
||||
).filter(
|
||||
content_type=content_type,
|
||||
object_id=obj.pk
|
||||
)
|
||||
objectchanges_table = ObjectChangeTable(
|
||||
data=objectchanges,
|
||||
orderable=False
|
||||
)
|
||||
|
||||
# Check whether a header template exists for this model
|
||||
base_template = '{}/{}.html'.format(model._meta.app_label, model._meta.model_name)
|
||||
@ -79,9 +116,9 @@ class ChangeLogView(View):
|
||||
base_template = '_base.html'
|
||||
object_var = 'obj'
|
||||
|
||||
return render(request, 'extras/changelog.html', {
|
||||
return render(request, 'extras/object_changelog.html', {
|
||||
object_var: obj,
|
||||
'changes': changes,
|
||||
'objectchanges_table': objectchanges_table,
|
||||
'base_template': base_template,
|
||||
'active_tab': 'changelog',
|
||||
})
|
||||
|
@ -2,7 +2,7 @@ from __future__ import unicode_literals
|
||||
|
||||
from django.conf.urls import url
|
||||
|
||||
from extras.views import ChangeLogView
|
||||
from extras.views import ObjectChangeLogView
|
||||
from . import views
|
||||
from .models import Aggregate, IPAddress, Prefix, RIR, Role, Service, VLAN, VLANGroup, VRF
|
||||
|
||||
@ -19,7 +19,7 @@ urlpatterns = [
|
||||
url(r'^vrfs/(?P<pk>\d+)/$', views.VRFView.as_view(), name='vrf'),
|
||||
url(r'^vrfs/(?P<pk>\d+)/edit/$', views.VRFEditView.as_view(), name='vrf_edit'),
|
||||
url(r'^vrfs/(?P<pk>\d+)/delete/$', views.VRFDeleteView.as_view(), name='vrf_delete'),
|
||||
url(r'^vrfs/(?P<pk>\d+)/changelog/$', ChangeLogView.as_view(), name='vrf_changelog', kwargs={'model': VRF}),
|
||||
url(r'^vrfs/(?P<pk>\d+)/changelog/$', ObjectChangeLogView.as_view(), name='vrf_changelog', kwargs={'model': VRF}),
|
||||
|
||||
# RIRs
|
||||
url(r'^rirs/$', views.RIRListView.as_view(), name='rir_list'),
|
||||
@ -27,7 +27,7 @@ urlpatterns = [
|
||||
url(r'^rirs/import/$', views.RIRBulkImportView.as_view(), name='rir_import'),
|
||||
url(r'^rirs/delete/$', views.RIRBulkDeleteView.as_view(), name='rir_bulk_delete'),
|
||||
url(r'^rirs/(?P<slug>[\w-]+)/edit/$', views.RIREditView.as_view(), name='rir_edit'),
|
||||
url(r'^vrfs/(?P<slug>[\w-]+)/changelog/$', ChangeLogView.as_view(), name='rir_changelog', kwargs={'model': RIR}),
|
||||
url(r'^vrfs/(?P<slug>[\w-]+)/changelog/$', ObjectChangeLogView.as_view(), name='rir_changelog', kwargs={'model': RIR}),
|
||||
|
||||
# Aggregates
|
||||
url(r'^aggregates/$', views.AggregateListView.as_view(), name='aggregate_list'),
|
||||
@ -38,7 +38,7 @@ urlpatterns = [
|
||||
url(r'^aggregates/(?P<pk>\d+)/$', views.AggregateView.as_view(), name='aggregate'),
|
||||
url(r'^aggregates/(?P<pk>\d+)/edit/$', views.AggregateEditView.as_view(), name='aggregate_edit'),
|
||||
url(r'^aggregates/(?P<pk>\d+)/delete/$', views.AggregateDeleteView.as_view(), name='aggregate_delete'),
|
||||
url(r'^aggregates/(?P<pk>\d+)/changelog/$', ChangeLogView.as_view(), name='aggregate_changelog', kwargs={'model': Aggregate}),
|
||||
url(r'^aggregates/(?P<pk>\d+)/changelog/$', ObjectChangeLogView.as_view(), name='aggregate_changelog', kwargs={'model': Aggregate}),
|
||||
|
||||
# Roles
|
||||
url(r'^roles/$', views.RoleListView.as_view(), name='role_list'),
|
||||
@ -46,7 +46,7 @@ urlpatterns = [
|
||||
url(r'^roles/import/$', views.RoleBulkImportView.as_view(), name='role_import'),
|
||||
url(r'^roles/delete/$', views.RoleBulkDeleteView.as_view(), name='role_bulk_delete'),
|
||||
url(r'^roles/(?P<slug>[\w-]+)/edit/$', views.RoleEditView.as_view(), name='role_edit'),
|
||||
url(r'^roles/(?P<slug>[\w-]+)/changelog/$', ChangeLogView.as_view(), name='role_changelog', kwargs={'model': Role}),
|
||||
url(r'^roles/(?P<slug>[\w-]+)/changelog/$', ObjectChangeLogView.as_view(), name='role_changelog', kwargs={'model': Role}),
|
||||
|
||||
# Prefixes
|
||||
url(r'^prefixes/$', views.PrefixListView.as_view(), name='prefix_list'),
|
||||
@ -57,7 +57,7 @@ urlpatterns = [
|
||||
url(r'^prefixes/(?P<pk>\d+)/$', views.PrefixView.as_view(), name='prefix'),
|
||||
url(r'^prefixes/(?P<pk>\d+)/edit/$', views.PrefixEditView.as_view(), name='prefix_edit'),
|
||||
url(r'^prefixes/(?P<pk>\d+)/delete/$', views.PrefixDeleteView.as_view(), name='prefix_delete'),
|
||||
url(r'^prefixes/(?P<pk>\d+)/changelog/$', ChangeLogView.as_view(), name='prefix_changelog', kwargs={'model': Prefix}),
|
||||
url(r'^prefixes/(?P<pk>\d+)/changelog/$', ObjectChangeLogView.as_view(), name='prefix_changelog', kwargs={'model': Prefix}),
|
||||
url(r'^prefixes/(?P<pk>\d+)/prefixes/$', views.PrefixPrefixesView.as_view(), name='prefix_prefixes'),
|
||||
url(r'^prefixes/(?P<pk>\d+)/ip-addresses/$', views.PrefixIPAddressesView.as_view(), name='prefix_ipaddresses'),
|
||||
|
||||
@ -68,7 +68,7 @@ urlpatterns = [
|
||||
url(r'^ip-addresses/import/$', views.IPAddressBulkImportView.as_view(), name='ipaddress_import'),
|
||||
url(r'^ip-addresses/edit/$', views.IPAddressBulkEditView.as_view(), name='ipaddress_bulk_edit'),
|
||||
url(r'^ip-addresses/delete/$', views.IPAddressBulkDeleteView.as_view(), name='ipaddress_bulk_delete'),
|
||||
url(r'^ip-addresses/(?P<pk>\d+)/changelog/$', ChangeLogView.as_view(), name='ipaddress_changelog', kwargs={'model': IPAddress}),
|
||||
url(r'^ip-addresses/(?P<pk>\d+)/changelog/$', ObjectChangeLogView.as_view(), name='ipaddress_changelog', kwargs={'model': IPAddress}),
|
||||
url(r'^ip-addresses/assign/$', views.IPAddressAssignView.as_view(), name='ipaddress_assign'),
|
||||
url(r'^ip-addresses/(?P<pk>\d+)/$', views.IPAddressView.as_view(), name='ipaddress'),
|
||||
url(r'^ip-addresses/(?P<pk>\d+)/edit/$', views.IPAddressEditView.as_view(), name='ipaddress_edit'),
|
||||
@ -80,7 +80,7 @@ urlpatterns = [
|
||||
url(r'^vlan-groups/import/$', views.VLANGroupBulkImportView.as_view(), name='vlangroup_import'),
|
||||
url(r'^vlan-groups/delete/$', views.VLANGroupBulkDeleteView.as_view(), name='vlangroup_bulk_delete'),
|
||||
url(r'^vlan-groups/(?P<pk>\d+)/edit/$', views.VLANGroupEditView.as_view(), name='vlangroup_edit'),
|
||||
url(r'^vlan-groups/(?P<pk>\d+)/changelog/$', ChangeLogView.as_view(), name='vlangroup_changelog', kwargs={'model': VLANGroup}),
|
||||
url(r'^vlan-groups/(?P<pk>\d+)/changelog/$', ObjectChangeLogView.as_view(), name='vlangroup_changelog', kwargs={'model': VLANGroup}),
|
||||
|
||||
# VLANs
|
||||
url(r'^vlans/$', views.VLANListView.as_view(), name='vlan_list'),
|
||||
@ -92,11 +92,11 @@ urlpatterns = [
|
||||
url(r'^vlans/(?P<pk>\d+)/members/$', views.VLANMembersView.as_view(), name='vlan_members'),
|
||||
url(r'^vlans/(?P<pk>\d+)/edit/$', views.VLANEditView.as_view(), name='vlan_edit'),
|
||||
url(r'^vlans/(?P<pk>\d+)/delete/$', views.VLANDeleteView.as_view(), name='vlan_delete'),
|
||||
url(r'^vlans/(?P<pk>\d+)/changelog/$', ChangeLogView.as_view(), name='vlan_changelog', kwargs={'model': VLAN}),
|
||||
url(r'^vlans/(?P<pk>\d+)/changelog/$', ObjectChangeLogView.as_view(), name='vlan_changelog', kwargs={'model': VLAN}),
|
||||
|
||||
# Services
|
||||
url(r'^services/(?P<pk>\d+)/edit/$', views.ServiceEditView.as_view(), name='service_edit'),
|
||||
url(r'^services/(?P<pk>\d+)/delete/$', views.ServiceDeleteView.as_view(), name='service_delete'),
|
||||
url(r'^services/(?P<pk>\d+)/changelog/$', ChangeLogView.as_view(), name='service_changelog', kwargs={'model': Service}),
|
||||
url(r'^services/(?P<pk>\d+)/changelog/$', ObjectChangeLogView.as_view(), name='service_changelog', kwargs={'model': Service}),
|
||||
|
||||
]
|
||||
|
@ -2,7 +2,7 @@ from __future__ import unicode_literals
|
||||
|
||||
from django.conf.urls import url
|
||||
|
||||
from extras.views import ChangeLogView
|
||||
from extras.views import ObjectChangeLogView
|
||||
from . import views
|
||||
from .models import Secret, SecretRole
|
||||
|
||||
@ -15,7 +15,7 @@ urlpatterns = [
|
||||
url(r'^secret-roles/import/$', views.SecretRoleBulkImportView.as_view(), name='secretrole_import'),
|
||||
url(r'^secret-roles/delete/$', views.SecretRoleBulkDeleteView.as_view(), name='secretrole_bulk_delete'),
|
||||
url(r'^secret-roles/(?P<slug>[\w-]+)/edit/$', views.SecretRoleEditView.as_view(), name='secretrole_edit'),
|
||||
url(r'^secret-roles/(?P<slug>[\w-]+)/changelog/$', ChangeLogView.as_view(), name='secretrole_changelog', kwargs={'model': SecretRole}),
|
||||
url(r'^secret-roles/(?P<slug>[\w-]+)/changelog/$', ObjectChangeLogView.as_view(), name='secretrole_changelog', kwargs={'model': SecretRole}),
|
||||
|
||||
# Secrets
|
||||
url(r'^secrets/$', views.SecretListView.as_view(), name='secret_list'),
|
||||
@ -25,6 +25,6 @@ urlpatterns = [
|
||||
url(r'^secrets/(?P<pk>\d+)/$', views.SecretView.as_view(), name='secret'),
|
||||
url(r'^secrets/(?P<pk>\d+)/edit/$', views.secret_edit, name='secret_edit'),
|
||||
url(r'^secrets/(?P<pk>\d+)/delete/$', views.SecretDeleteView.as_view(), name='secret_delete'),
|
||||
url(r'^secrets/(?P<pk>\d+)/changelog/$', ChangeLogView.as_view(), name='secret_changelog', kwargs={'model': Secret}),
|
||||
url(r'^secrets/(?P<pk>\d+)/changelog/$', ObjectChangeLogView.as_view(), name='secret_changelog', kwargs={'model': Secret}),
|
||||
|
||||
]
|
||||
|
@ -1,36 +0,0 @@
|
||||
{% extends base_template %}
|
||||
|
||||
{% block title %}{% if obj %}{{ obj }}{% else %}{{ block.super }}{% endif %} - Changelog{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
{% if obj %}<h1>{{ obj }}</h1>{% endif %}
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Time</th>
|
||||
<th>User</th>
|
||||
<th>Action</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for change in changes %}
|
||||
<tr>
|
||||
<td>{{ change.time }}</td>
|
||||
<td>{{ change.user }}</td>
|
||||
<td>{{ change.get_action_display }}</td>
|
||||
<td>
|
||||
<button class="btn btn-xs btn-primary" type="button" data-toggle="collapse" data-target="#change{{ change.pk }}" aria-expanded="false" aria-controls="collapseExample">
|
||||
<i class="fa fa-search"></i>
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="collapse" id="change{{ change.pk }}">
|
||||
<td colspan="4">
|
||||
<pre class="well">{{ change.object_data_pretty }}</pre>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
{% endblock %}
|
8
netbox/templates/extras/object_changelog.html
Normal file
8
netbox/templates/extras/object_changelog.html
Normal file
@ -0,0 +1,8 @@
|
||||
{% extends base_template %}
|
||||
|
||||
{% block title %}{% if obj %}{{ obj }}{% else %}{{ block.super }}{% endif %} - Changelog{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
{% if obj %}<h1>{{ obj }}</h1>{% endif %}
|
||||
{% include 'panel_table.html' with table=objectchanges_table %}
|
||||
{% endblock %}
|
101
netbox/templates/extras/objectchange.html
Normal file
101
netbox/templates/extras/objectchange.html
Normal file
@ -0,0 +1,101 @@
|
||||
{% extends '_base.html' %}
|
||||
{% load helpers %}
|
||||
|
||||
{% block title %}{{ objectchange }}{% endblock %}
|
||||
|
||||
{% block header %}
|
||||
<div class="row">
|
||||
<div class="col-sm-8 col-md-9">
|
||||
<ol class="breadcrumb">
|
||||
<li><a href="{% url 'extras:objectchange_list' %}">Changelog</a></li>
|
||||
<li>{{ objectchange }}</li>
|
||||
</ol>
|
||||
</div>
|
||||
<div class="col-sm-4 col-md-3">
|
||||
<form action="{% url 'extras:objectchange_list' %}" method="get">
|
||||
<div class="input-group">
|
||||
<input type="text" name="q" class="form-control" />
|
||||
<span class="input-group-btn">
|
||||
<button type="submit" class="btn btn-primary">
|
||||
<span class="fa fa-search" aria-hidden="true"></span>
|
||||
</button>
|
||||
</span>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="row">
|
||||
<div class="col-md-5">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<strong>Change</strong>
|
||||
</div>
|
||||
<table class="table table-hover panel-body attr-table">
|
||||
<tr>
|
||||
<td>Time</td>
|
||||
<td>
|
||||
{{ objectchange.time }}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>User</td>
|
||||
<td>
|
||||
{{ objectchange.user|default:objectchange.user_name }}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Action</td>
|
||||
<td>
|
||||
{{ objectchange.get_action_display }}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Content Type</td>
|
||||
<td>
|
||||
{{ objectchange.content_type }}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Object</td>
|
||||
<td>
|
||||
{% if objectchange.changed_object.get_absolute_url %}
|
||||
<a href="{{ objectchange.changed_object.get_aboslute_url }}">{{ objectchange.changed_object }}</a>
|
||||
{% else %}
|
||||
{{ objectchange.object_repr }}
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Request ID</td>
|
||||
<td>
|
||||
{{ objectchange.request_id }}
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-7">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<strong>Object Data</strong>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<pre>{{ objectchange.object_data_pretty }}</pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
{% include 'panel_table.html' with table=related_changes_table heading='Related Changes' %}
|
||||
{% if related_changes_count > related_changes_table.rows|length %}
|
||||
<div class="pull-right">
|
||||
<a href="{% url 'extras:objectchange_list' %}?request_id={{ objectchange.request_id }}" class="btn btn-primary">See all {{ related_changes_count|add:"1" }} changes</a>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
17
netbox/templates/extras/objectchange_list.html
Normal file
17
netbox/templates/extras/objectchange_list.html
Normal file
@ -0,0 +1,17 @@
|
||||
{% extends '_base.html' %}
|
||||
{% load buttons %}
|
||||
|
||||
{% block content %}
|
||||
<div class="pull-right">
|
||||
{% export_button content_type %}
|
||||
</div>
|
||||
<h1>{% block title %}Changelog{% endblock %}</h1>
|
||||
<div class="row">
|
||||
<div class="col-md-9">
|
||||
{% include 'utilities/obj_table.html' %}
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
{% include 'inc/search_panel.html' %}
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
@ -66,6 +66,9 @@
|
||||
<li>
|
||||
<a href="{% url 'extras:report_list' %}">Reports</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="{% url 'extras:objectchange_list' %}">Changelog</a>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="dropdown{% if request.path|contains:'/dcim/rack' %} active{% endif %}">
|
||||
|
@ -2,7 +2,7 @@ from __future__ import unicode_literals
|
||||
|
||||
from django.conf.urls import url
|
||||
|
||||
from extras.views import ChangeLogView
|
||||
from extras.views import ObjectChangeLogView
|
||||
from . import views
|
||||
from .models import Tenant, TenantGroup
|
||||
|
||||
@ -15,7 +15,7 @@ urlpatterns = [
|
||||
url(r'^tenant-groups/import/$', views.TenantGroupBulkImportView.as_view(), name='tenantgroup_import'),
|
||||
url(r'^tenant-groups/delete/$', views.TenantGroupBulkDeleteView.as_view(), name='tenantgroup_bulk_delete'),
|
||||
url(r'^tenant-groups/(?P<slug>[\w-]+)/edit/$', views.TenantGroupEditView.as_view(), name='tenantgroup_edit'),
|
||||
url(r'^tenant-groups/(?P<slug>[\w-]+)/changelog/$', ChangeLogView.as_view(), name='tenantgroup_changelog', kwargs={'model': TenantGroup}),
|
||||
url(r'^tenant-groups/(?P<slug>[\w-]+)/changelog/$', ObjectChangeLogView.as_view(), name='tenantgroup_changelog', kwargs={'model': TenantGroup}),
|
||||
|
||||
# Tenants
|
||||
url(r'^tenants/$', views.TenantListView.as_view(), name='tenant_list'),
|
||||
@ -26,6 +26,6 @@ urlpatterns = [
|
||||
url(r'^tenants/(?P<slug>[\w-]+)/$', views.TenantView.as_view(), name='tenant'),
|
||||
url(r'^tenants/(?P<slug>[\w-]+)/edit/$', views.TenantEditView.as_view(), name='tenant_edit'),
|
||||
url(r'^tenants/(?P<slug>[\w-]+)/delete/$', views.TenantDeleteView.as_view(), name='tenant_delete'),
|
||||
url(r'^tenants/(?P<slug>[\w-]+)/changelog/$', ChangeLogView.as_view(), name='tenant_changelog', kwargs={'model': Tenant}),
|
||||
url(r'^tenants/(?P<slug>[\w-]+)/changelog/$', ObjectChangeLogView.as_view(), name='tenant_changelog', kwargs={'model': Tenant}),
|
||||
|
||||
]
|
||||
|
@ -2,7 +2,7 @@ from __future__ import unicode_literals
|
||||
|
||||
from django.conf.urls import url
|
||||
|
||||
from extras.views import ChangeLogView
|
||||
from extras.views import ObjectChangeLogView
|
||||
from ipam.views import ServiceCreateView
|
||||
from . import views
|
||||
from .models import Cluster, ClusterGroup, ClusterType, VirtualMachine
|
||||
@ -16,7 +16,7 @@ urlpatterns = [
|
||||
url(r'^cluster-types/import/$', views.ClusterTypeBulkImportView.as_view(), name='clustertype_import'),
|
||||
url(r'^cluster-types/delete/$', views.ClusterTypeBulkDeleteView.as_view(), name='clustertype_bulk_delete'),
|
||||
url(r'^cluster-types/(?P<slug>[\w-]+)/edit/$', views.ClusterTypeEditView.as_view(), name='clustertype_edit'),
|
||||
url(r'^cluster-types/(?P<slug>[\w-]+)/changelog/$', ChangeLogView.as_view(), name='clustertype_changelog', kwargs={'model': ClusterType}),
|
||||
url(r'^cluster-types/(?P<slug>[\w-]+)/changelog/$', ObjectChangeLogView.as_view(), name='clustertype_changelog', kwargs={'model': ClusterType}),
|
||||
|
||||
# Cluster groups
|
||||
url(r'^cluster-groups/$', views.ClusterGroupListView.as_view(), name='clustergroup_list'),
|
||||
@ -24,7 +24,7 @@ urlpatterns = [
|
||||
url(r'^cluster-groups/import/$', views.ClusterGroupBulkImportView.as_view(), name='clustergroup_import'),
|
||||
url(r'^cluster-groups/delete/$', views.ClusterGroupBulkDeleteView.as_view(), name='clustergroup_bulk_delete'),
|
||||
url(r'^cluster-groups/(?P<slug>[\w-]+)/edit/$', views.ClusterGroupEditView.as_view(), name='clustergroup_edit'),
|
||||
url(r'^cluster-groups/(?P<slug>[\w-]+)/changelog/$', ChangeLogView.as_view(), name='clustergroup_changelog', kwargs={'model': ClusterGroup}),
|
||||
url(r'^cluster-groups/(?P<slug>[\w-]+)/changelog/$', ObjectChangeLogView.as_view(), name='clustergroup_changelog', kwargs={'model': ClusterGroup}),
|
||||
|
||||
# Clusters
|
||||
url(r'^clusters/$', views.ClusterListView.as_view(), name='cluster_list'),
|
||||
@ -35,7 +35,7 @@ urlpatterns = [
|
||||
url(r'^clusters/(?P<pk>\d+)/$', views.ClusterView.as_view(), name='cluster'),
|
||||
url(r'^clusters/(?P<pk>\d+)/edit/$', views.ClusterEditView.as_view(), name='cluster_edit'),
|
||||
url(r'^clusters/(?P<pk>\d+)/delete/$', views.ClusterDeleteView.as_view(), name='cluster_delete'),
|
||||
url(r'^clusters/(?P<pk>\d+)/changelog/$', ChangeLogView.as_view(), name='cluster_changelog', kwargs={'model': Cluster}),
|
||||
url(r'^clusters/(?P<pk>\d+)/changelog/$', ObjectChangeLogView.as_view(), name='cluster_changelog', kwargs={'model': Cluster}),
|
||||
url(r'^clusters/(?P<pk>\d+)/devices/add/$', views.ClusterAddDevicesView.as_view(), name='cluster_add_devices'),
|
||||
url(r'^clusters/(?P<pk>\d+)/devices/remove/$', views.ClusterRemoveDevicesView.as_view(), name='cluster_remove_devices'),
|
||||
|
||||
@ -48,7 +48,7 @@ urlpatterns = [
|
||||
url(r'^virtual-machines/(?P<pk>\d+)/$', views.VirtualMachineView.as_view(), name='virtualmachine'),
|
||||
url(r'^virtual-machines/(?P<pk>\d+)/edit/$', views.VirtualMachineEditView.as_view(), name='virtualmachine_edit'),
|
||||
url(r'^virtual-machines/(?P<pk>\d+)/delete/$', views.VirtualMachineDeleteView.as_view(), name='virtualmachine_delete'),
|
||||
url(r'^virtual-machines/(?P<pk>\d+)/changelog/$', ChangeLogView.as_view(), name='virtualmachine_changelog', kwargs={'model': VirtualMachine}),
|
||||
url(r'^virtual-machines/(?P<pk>\d+)/changelog/$', ObjectChangeLogView.as_view(), name='virtualmachine_changelog', kwargs={'model': VirtualMachine}),
|
||||
url(r'^virtual-machines/(?P<virtualmachine>\d+)/services/assign/$', ServiceCreateView.as_view(), name='virtualmachine_service_assign'),
|
||||
|
||||
# VM interfaces
|
||||
|
Loading…
Reference in New Issue
Block a user