Skip to content

Commit

Permalink
Merge pull request #97 from ArnesSI/test-beta
Browse files Browse the repository at this point in the history
netbox 3.5 support
  • Loading branch information
matejv authored May 3, 2023
2 parents 2398885 + 2ab4e57 commit 6d035dd
Show file tree
Hide file tree
Showing 22 changed files with 150 additions and 201 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ jobs:
strategy:
fail-fast: false
matrix:
netbox-version: ["v3.4.7"]
netbox-version: ["v3.5.0"]
services:
redis:
image: redis
Expand Down
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,13 +56,14 @@ The idea is that an external system uses some assets stored in netbox_inventory,

## Compatibility

This plugin requires netbox version 3.4.x to work. Older versions of the plugin
This plugin requires netbox version 3.5.x to work. Older versions of the plugin
support older netbox version as per table below:

| NetBox Version | Plugin Version |
|----------------|----------------|
| 3.3 | 1.1.x |
| 3.4 | 1.2.x |
| 3.5 | 1.3.x |

## Installing

Expand Down
2 changes: 1 addition & 1 deletion netbox_inventory/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ class NetBoxInventoryConfig(PluginConfig):
author = 'Matej Vadnjal'
author_email = 'matej.vadnjal@arnes.si'
base_url = 'inventory'
min_version = '3.4.0'
min_version = '3.5.0'
default_settings = {
'top_level_menu': True,
'used_status_name': 'used',
Expand Down
42 changes: 22 additions & 20 deletions netbox_inventory/forms/assign.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@

from dcim.models import Device, InventoryItem, Module, Site
from netbox.forms import NetBoxModelForm
from utilities.forms import APISelect, DynamicModelChoiceField
from tenancy.models import Contact, Tenant
from utilities.forms.fields import DynamicModelChoiceField
from utilities.forms.widgets import APISelect
from ..models import Asset

__all__ = (
Expand All @@ -18,6 +20,18 @@ class AssetAssignMixin(forms.Form):
label='Asset name',
help_text=Asset._meta.get_field('name').help_text
)
tenant = DynamicModelChoiceField(
queryset=Tenant.objects.all(),
selector=True,
required=False,
help_text=Asset._meta.get_field('tenant').help_text,
)
contact = DynamicModelChoiceField(
queryset=Contact.objects.all(),
selector=True,
required=False,
help_text=Asset._meta.get_field('contact').help_text,
)
tags = None

def _clean_hardware_type(self, kind):
Expand Down Expand Up @@ -71,7 +85,7 @@ class AssetDeviceAssignForm(AssetAssignMixin, NetBoxModelForm):
fieldsets = (
('Asset', ('device_type', 'name')),
('Device', ('site', 'device')),
('Tenancy', ('tenant', 'contact')),
('Assigned to', ('tenant', 'contact')),
)

class Meta:
Expand All @@ -87,15 +101,9 @@ def clean_device(self):


class AssetModuleAssignForm(AssetAssignMixin, NetBoxModelForm):
site = DynamicModelChoiceField(
queryset=Site.objects.all(),
required=False,
initial_params={'devices': '$device'},
)
device = DynamicModelChoiceField(
queryset=Device.objects.all(),
query_params={'site_id': '$site'},
label='Device',
selector=True,
required=False,
)
module = DynamicModelChoiceField(
Expand All @@ -114,13 +122,13 @@ class AssetModuleAssignForm(AssetAssignMixin, NetBoxModelForm):

fieldsets = (
('Asset', ('module_type', 'name')),
('Module', ('site', 'device', 'module')),
('Module', ('device', 'module',)),
('Tenancy', ('tenant', 'contact')),
)

class Meta:
model = Asset
fields = ('module_type', 'name', 'site', 'device', 'module', 'tenant', 'contact')
fields = ('module_type', 'name', 'device', 'module', 'tenant', 'contact')
widgets = {'module_type': forms.HiddenInput()}

def clean_device(self):
Expand All @@ -135,15 +143,9 @@ def clean_module(self):


class AssetInventoryItemAssignForm(AssetAssignMixin, NetBoxModelForm):
site = DynamicModelChoiceField(
queryset=Site.objects.all(),
required=False,
initial_params={'devices': '$device'},
)
device = DynamicModelChoiceField(
queryset=Device.objects.all(),
query_params={'site_id': '$site'},
label='Device',
selector=True,
required=False,
)
inventoryitem = DynamicModelChoiceField(
Expand All @@ -164,13 +166,13 @@ class AssetInventoryItemAssignForm(AssetAssignMixin, NetBoxModelForm):

fieldsets = (
('Asset', ('inventoryitem_type', 'name')),
('Inventory Item', ('site', 'device', 'inventoryitem')),
('Inventory Item', ('device', 'inventoryitem')),
('Tenancy', ('tenant', 'contact')),
)

class Meta:
model = Asset
fields = ('inventoryitem_type', 'name', 'site', 'device', 'inventoryitem', 'tenant', 'contact')
fields = ('inventoryitem_type', 'name', 'device', 'inventoryitem', 'tenant', 'contact')
widgets = {'inventoryitem_type': forms.HiddenInput()}

def clean_device(self):
Expand Down
7 changes: 4 additions & 3 deletions netbox_inventory/forms/bulk.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@

from dcim.models import DeviceType, Manufacturer, ModuleType, Location, Site
from netbox.forms import NetBoxModelBulkEditForm, NetBoxModelImportForm
from utilities.forms import (
add_blank_choice, ChoiceField, CommentField, CSVChoiceField,
CSVModelChoiceField, DynamicModelChoiceField
from utilities.forms import add_blank_choice
from utilities.forms.fields import (
ChoiceField, CommentField, CSVChoiceField, CSVModelChoiceField,
DynamicModelChoiceField
)
from tenancy.models import Contact, Tenant
from ..choices import AssetStatusChoices, HardwareKindChoices
Expand Down
76 changes: 14 additions & 62 deletions netbox_inventory/forms/create.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
from django.core.exceptions import ValidationError

from dcim.forms import DeviceForm, InventoryItemForm, ModuleForm
from dcim.models.device_components import ConsolePort, ConsoleServerPort, FrontPort, Interface, PowerOutlet, PowerPort, RearPort
from utilities.forms import DynamicModelChoiceField, StaticSelect
from dcim.models import Device
from utilities.forms.fields import DynamicModelChoiceField
from ..utils import get_plugin_setting

__all__ = (
Expand Down Expand Up @@ -37,16 +37,10 @@ def update_hardware_fields(self, kind_type):
asset = self.instance.assigned_asset
self.fields['serial'].disabled = True
self.fields['asset_tag'].disabled = True
self.fields[kind_type].disabled = True
self.initial['serial'] = asset.serial
self.initial['asset_tag'] = asset.asset_tag if asset.asset_tag else None

self.fields['manufacturer'].widget = StaticSelect(attrs={'readonly':True, 'disabled':True})
self.fields['manufacturer'].choices = [(asset.hardware_type.manufacturer.pk, asset.hardware_type.manufacturer)]
self.fields[kind_type].widget = StaticSelect(attrs={'readonly':True, 'disabled':True})
self.fields[kind_type].choices = [(asset.hardware_type.pk, asset.hardware_type)]
# disabled Select field will not be POSTed so clean() complains if field is required
# we set value later in clean_*_type() anyway
self.fields[kind_type].required = False
self.initial[kind_type] = asset.hardware_type.id

def save(self, *args):
"""
Expand Down Expand Up @@ -80,6 +74,14 @@ class AssetModuleCreateForm(AssetCreateMixin, ModuleForm):
"""
Populates and disables editing of asset and module_type fields
"""
device = DynamicModelChoiceField(
queryset=Device.objects.all(),
selector=True,
initial_params={
'modulebays': '$module_bay'
}
)

def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.update_hardware_fields('module_type')
Expand All @@ -94,55 +96,6 @@ class AssetInventoryItemCreateForm(AssetCreateMixin, InventoryItemForm):
Offers selection of device components and maps selected component
to component_type and component_id fields
"""

consoleport = DynamicModelChoiceField(
queryset=ConsolePort.objects.all(),
query_params={'device_id': '$device'},
label='Console port',
required=False,
)
consoleserverport = DynamicModelChoiceField(
queryset=ConsoleServerPort.objects.all(),
query_params={'device_id': '$device'},
label='Console server port',
required=False,
)
frontport = DynamicModelChoiceField(
queryset=FrontPort.objects.all(),
query_params={'device_id': '$device'},
label='Front port',
required=False,
)
interface = DynamicModelChoiceField(
queryset=Interface.objects.all(),
query_params={'device_id': '$device'},
label='Interface',
required=False,
)
poweroutlet = DynamicModelChoiceField(
queryset=PowerOutlet.objects.all(),
query_params={'device_id': '$device'},
label='Power outlet',
required=False,
)
powerport = DynamicModelChoiceField(
queryset=PowerPort.objects.all(),
query_params={'device_id': '$device'},
label='Power port',
required=False,
)
rearport = DynamicModelChoiceField(
queryset=RearPort.objects.all(),
query_params={'device_id': '$device'},
label='Rear port',
required=False,
)

fieldsets = (
InventoryItemForm.fieldsets[0],
('Component', ('interface', 'consoleport', 'consoleserverport', 'frontport', 'rearport', 'poweroutlet', 'powerport')),
) + InventoryItemForm.fieldsets[1:]

def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)

Expand All @@ -151,18 +104,17 @@ def __init__(self, *args, **kwargs):
self.fields['serial'].disabled = True
self.fields['asset_tag'].disabled = True
self.fields['part_id'].disabled = True
self.fields['manufacturer'].disabled = True
self.initial['serial'] = asset.serial
self.initial['asset_tag'] = asset.asset_tag if asset.asset_tag else None
self.initial['part_id'] = asset.inventoryitem_type.part_number or asset.inventoryitem_type.model
self.initial['manufacturer'] = asset.inventoryitem_type.manufacturer_id

if get_plugin_setting('prefill_asset_name_create_inventoryitem'):
self.initial['name'] = asset.name if asset.name else None
if get_plugin_setting('prefill_asset_tag_create_inventoryitem'):
self.initial['tags'] = asset.tags.all() if asset.tags else None

self.fields['manufacturer'].widget = StaticSelect(attrs={'readonly':True, 'disabled':True})
self.fields['manufacturer'].choices = [(asset.inventoryitem_type.manufacturer.pk, asset.inventoryitem_type.manufacturer)]

def clean(self):
super().clean()
component_set = None
Expand Down
10 changes: 4 additions & 6 deletions netbox_inventory/forms/filters.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
from cProfile import label
from django import forms

from dcim.models import Device, DeviceType, Manufacturer, ModuleType, Site, Location, Rack
from netbox.forms import NetBoxModelFilterSetForm
from utilities.forms import (
DatePicker, DynamicModelMultipleChoiceField, MultipleChoiceField,
StaticSelect, TagFilterField, BOOLEAN_WITH_BLANK_CHOICES
)
from utilities.forms import BOOLEAN_WITH_BLANK_CHOICES
from utilities.forms.fields import DynamicModelMultipleChoiceField, MultipleChoiceField, TagFilterField
from utilities.forms.widgets import DatePicker
from tenancy.forms import ContactModelFilterForm
from tenancy.models import Contact, Tenant
from ..choices import HardwareKindChoices, AssetStatusChoices
Expand Down Expand Up @@ -89,7 +87,7 @@ class AssetFilterForm(NetBoxModelFilterSetForm):
is_assigned = forms.NullBooleanField(
required=False,
label='Is assigned to hardware',
widget=StaticSelect(
widget=forms.Select(
choices=BOOLEAN_WITH_BLANK_CHOICES
)
)
Expand Down
3 changes: 2 additions & 1 deletion netbox_inventory/forms/models.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
from dcim.models import DeviceType, Manufacturer, ModuleType, Location, Site
from netbox.forms import NetBoxModelForm
from netbox_inventory.choices import HardwareKindChoices
from utilities.forms import CommentField, DatePicker, DynamicModelChoiceField, SlugField
from utilities.forms.fields import CommentField, DynamicModelChoiceField, SlugField
from utilities.forms.widgets import DatePicker
from tenancy.models import Contact, Tenant
from ..models import Asset, InventoryItemType, InventoryItemGroup, Purchase, Supplier
from ..utils import get_tags_and_edit_protected_asset_fields
Expand Down
5 changes: 4 additions & 1 deletion netbox_inventory/forms/reassign.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

from dcim.models import Device, InventoryItem, Module, Site, Location, Manufacturer
from netbox.forms import NetBoxModelForm
from utilities.forms import DynamicModelChoiceField, ChoiceField
from utilities.forms.fields import DynamicModelChoiceField, ChoiceField
from ..choices import AssetStatusChoices
from ..models import Asset, InventoryItemType, InventoryItemGroup
from ..utils import get_status_for
Expand Down Expand Up @@ -111,6 +111,7 @@ class AssetDeviceReassignForm(AssetReassignMixin, NetBoxModelForm):
assigned_asset = DynamicModelChoiceField(
queryset=Asset.objects.filter(device_type__isnull=False, device__isnull=True),
required=False,
selector=True,
query_params={
'kind': 'device',
'is_assigned': False,
Expand Down Expand Up @@ -140,6 +141,7 @@ class AssetModuleReassignForm(AssetReassignMixin, NetBoxModelForm):
assigned_asset = DynamicModelChoiceField(
queryset=Asset.objects.filter(module_type__isnull=False, module__isnull=True),
required=False,
selector=True,
query_params={
'kind': 'module',
'is_assigned': False,
Expand Down Expand Up @@ -190,6 +192,7 @@ class AssetInventoryItemReassignForm(AssetReassignMixin, NetBoxModelForm):
assigned_asset = DynamicModelChoiceField(
queryset=Asset.objects.filter(inventoryitem_type__isnull=False, inventoryitem__isnull=True),
required=False,
selector=True,
query_params={
'kind': 'inventoryitem',
'is_assigned': False,
Expand Down
16 changes: 13 additions & 3 deletions netbox_inventory/template_content.py
Original file line number Diff line number Diff line change
Expand Up @@ -99,10 +99,20 @@ def right_page(self):
object = self.context.get('object')
user = self.context['request'].user
context = {
'asset_assigned_count': Asset.objects.restrict(user, 'view').filter(tenant=object).count(),
'asset_owned_count': Asset.objects.restrict(user, 'view').filter(owner=object).count(),
'asset_stats': [
{
'label': 'Assigned',
'filter_field': 'tenant_id',
'count': Asset.objects.restrict(user, 'view').filter(tenant=object).count(),
},
{
'label': 'Owned',
'filter_field': 'owner_id',
'count': Asset.objects.restrict(user, 'view').filter(owner=object).count(),
},
],
}
return self.render('netbox_inventory/inc/asset_tenant.html', extra_context=context)
return self.render('netbox_inventory/inc/asset_stats_counts.html', extra_context=context)


class ContactAssetInfo(PluginTemplateExtension):
Expand Down
Loading

0 comments on commit 6d035dd

Please sign in to comment.