Skip to content

Commit

Permalink
Merge pull request #53 from cruse1977/0.5.0
Browse files Browse the repository at this point in the history
0.5.0
  • Loading branch information
cruse1977 authored Oct 9, 2024
2 parents db0fe59 + df34ff6 commit c7eafe6
Show file tree
Hide file tree
Showing 28 changed files with 550 additions and 31,232 deletions.
3 changes: 3 additions & 0 deletions .flake8
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[flake8]
max-line-length = 140
ignore = E126, E722
1 change: 1 addition & 0 deletions netbox_floorplan/__init__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from netbox.plugins import PluginConfig
from .version import __version__


class FloorplanConfig(PluginConfig):

name = "netbox_floorplan"
Expand Down
9 changes: 9 additions & 0 deletions netbox_floorplan/admin.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
from django.contrib import admin
from .models import Floorplan


@admin.register(Floorplan)
class FloorplanAdmin(admin.ModelAdmin):
list_display = (
"pk",
)
15 changes: 13 additions & 2 deletions netbox_floorplan/api/serializers.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,25 @@
from rest_framework import serializers
from netbox.api.serializers import NetBoxModelSerializer
from ..models import Floorplan
from ..models import Floorplan, FloorplanImage


class FloorplanImageSerializer(NetBoxModelSerializer):
url = serializers.HyperlinkedIdentityField(
view_name='plugins-api:netbox_floorplan-api:floorplanimage-detail')

class Meta:
model = FloorplanImage
fields = ['id', 'url', 'name', 'file', 'external_url', 'filename', 'comments', 'tags', 'custom_fields', 'created', 'last_updated']
brief_fields = ['id', 'url', 'name', 'file', 'filename', 'external_url']


class FloorplanSerializer(NetBoxModelSerializer):
url = serializers.HyperlinkedIdentityField(
view_name='plugins-api:netbox_floorplan-api:floorplan-detail')
assigned_image = FloorplanImageSerializer(nested=True, required=False, allow_null=True)

class Meta:
model = Floorplan
fields = ['id', 'url', 'site', 'location', 'background_image',
fields = ['id', 'url', 'site', 'location', 'assigned_image',
'width', 'height', 'tags', 'custom_fields', 'created',
'last_updated', 'canvas', 'measurement_unit']
2 changes: 1 addition & 1 deletion netbox_floorplan/api/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,5 @@

router = NetBoxRouter()
router.register('floorplans', views.FloorplanViewSet)

router.register('floorplanimages', views.FloorplanImageViewSet)
urlpatterns = router.urls
7 changes: 6 additions & 1 deletion netbox_floorplan/api/views.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
from netbox.api.viewsets import NetBoxModelViewSet

from .. import filtersets, models
from .serializers import FloorplanSerializer
from .serializers import FloorplanSerializer, FloorplanImageSerializer


class FloorplanViewSet(NetBoxModelViewSet):
queryset = models.Floorplan.objects.all()
serializer_class = FloorplanSerializer
filterset_class = filtersets.FloorplanFilterSet


class FloorplanImageViewSet(NetBoxModelViewSet):
queryset = models.FloorplanImage.objects.prefetch_related('tags')
serializer_class = FloorplanImageSerializer
24 changes: 22 additions & 2 deletions netbox_floorplan/forms.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,32 @@
from netbox.forms import NetBoxModelForm
from .models import Floorplan
from .models import Floorplan, FloorplanImage
from dcim.models import Rack, Device
from utilities.forms.rendering import FieldSet
from utilities.forms.fields import CommentField


class FloorplanImageForm(NetBoxModelForm):

comments = CommentField()

fieldsets = (
FieldSet(('name', 'file', 'external_url', 'comments'), name='General'),
FieldSet(('comments', 'tags'), name='')
)

class Meta:
model = FloorplanImage
fields = [
'name',
'file',
'external_url'
]


class FloorplanForm(NetBoxModelForm):
class Meta:
model = Floorplan
fields = ['site', 'location', 'background_image', 'width', 'height']
fields = ['site', 'location', 'assigned_image', 'width', 'height']


class FloorplanRackFilterForm(NetBoxModelForm):
Expand Down
30 changes: 30 additions & 0 deletions netbox_floorplan/migrations/0008_floorplanimage.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# Generated by Django 5.0.7 on 2024-07-19 23:49

import taggit.managers
import utilities.json
from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('extras', '0115_convert_dashboard_widgets'),
('netbox_floorplan', '0007_alter_floorplan_options_and_more'),
]

operations = [
migrations.CreateModel(
name='FloorplanImage',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False)),
('created', models.DateTimeField(auto_now_add=True, null=True)),
('last_updated', models.DateTimeField(auto_now=True, null=True)),
('custom_field_data', models.JSONField(blank=True, default=dict, encoder=utilities.json.CustomFieldJSONEncoder)),
('name', models.CharField(max_length=128)),
('tags', taggit.managers.TaggableManager(through='extras.TaggedItem', to='extras.Tag')),
],
options={
'ordering': ('name',),
},
),
]
19 changes: 19 additions & 0 deletions netbox_floorplan/migrations/0009_floorplanimage_file.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Generated by Django 5.0.7 on 2024-07-20 19:02

import netbox_floorplan.utils
from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('netbox_floorplan', '0008_floorplanimage'),
]

operations = [
migrations.AddField(
model_name='floorplanimage',
name='file',
field=models.FileField(blank=True, upload_to=netbox_floorplan.utils.file_upload),
),
]
18 changes: 18 additions & 0 deletions netbox_floorplan/migrations/0010_floorplanimage_external_url.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Generated by Django 5.0.7 on 2024-07-20 19:57

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('netbox_floorplan', '0009_floorplanimage_file'),
]

operations = [
migrations.AddField(
model_name='floorplanimage',
name='external_url',
field=models.URLField(blank=True, max_length=255),
),
]
18 changes: 18 additions & 0 deletions netbox_floorplan/migrations/0011_floorplanimage_comments.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Generated by Django 5.0.7 on 2024-07-20 20:34

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('netbox_floorplan', '0010_floorplanimage_external_url'),
]

operations = [
migrations.AddField(
model_name='floorplanimage',
name='comments',
field=models.TextField(blank=True),
),
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# Generated by Django 5.0.7 on 2024-07-20 20:53

import django.db.models.deletion
from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('netbox_floorplan', '0011_floorplanimage_comments'),
]

operations = [
migrations.AlterModelOptions(
name='floorplan',
options={'ordering': ('site', 'location', 'assigned_image', 'width', 'height', 'measurement_unit')},
),
migrations.RemoveField(
model_name='floorplan',
name='background_image',
),
migrations.AddField(
model_name='floorplan',
name='assigned_image',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='netbox_floorplan.floorplanimage'),
),
]
101 changes: 95 additions & 6 deletions netbox_floorplan/models.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,98 @@
from django.core.exceptions import ValidationError
from django.db import models
from django.urls import reverse

from netbox.models import NetBoxModel
from dcim.models import Rack, Device
from .utils import file_upload

from dcim.models import Rack, Device

class FloorplanImage(NetBoxModel):
"""
A Floorplan Image is effectively a background image
"""
name = models.CharField(
help_text='Can be used to quickly identify a particular image',
max_length=128,
blank=False,
null=False
)

file = models.FileField(
upload_to=file_upload,
blank=True
)

external_url = models.URLField(
blank=True,
max_length=255
)

comments = models.TextField(
blank=True
)

def get_absolute_url(self):
return reverse('plugins:netbox_floorplan:floorplanimage', args=[self.pk])

def __str__(self):
return f'{self.name}'

class Meta:
ordering = ('name',)

@property
def size(self):
"""
Wrapper around `document.size` to suppress an OSError in case the file is inaccessible. Also opportunistically
catch other exceptions that we know other storage back-ends to throw.
"""
expected_exceptions = [OSError]

try:
from botocore.exceptions import ClientError
expected_exceptions.append(ClientError)
except ImportError:
pass

try:
return self.file.size
except:
return None

@property
def filename(self):
filename = self.file.name.rsplit('/', 1)[-1]
return filename

def clean(self):
super().clean()

# Must have an uploaded document or an external URL. cannot have both
if not self.file and self.external_url == '':
raise ValidationError("A document must contain an uploaded file or an external URL.")
if self.file and self.external_url:
raise ValidationError("A document cannot contain both an uploaded file and an external URL.")

def delete(self, *args, **kwargs):

# Check if its a document or a URL
if self.external_url == '':

_name = self.file.name

# Delete file from disk
super().delete(*args, **kwargs)
self.file.delete(save=False)

# Restore the name of the document as it's re-used in the notifications later
self.file.name = _name
else:
# Straight delete of external URL
super().delete(*args, **kwargs)


class Floorplan(NetBoxModel):

site = models.ForeignKey(
to='dcim.Site',
blank=True,
Expand All @@ -20,17 +105,21 @@ class Floorplan(NetBoxModel):
null=True,
on_delete=models.PROTECT
)
background_image = models.ImageField(
upload_to=file_upload,

assigned_image = models.ForeignKey(
to='FloorplanImage',
blank=True,
null=True
null=True,
on_delete=models.SET_NULL
)

width = models.DecimalField(
max_digits=10,
decimal_places=2,
blank=True,
null=True
)

height = models.DecimalField(
max_digits=10,
decimal_places=2,
Expand All @@ -50,7 +139,7 @@ class Floorplan(NetBoxModel):
canvas = models.JSONField(default=dict)

class Meta:
ordering = ('site', 'location', 'background_image',
ordering = ('site', 'location', 'assigned_image',
'width', 'height', 'measurement_unit')

def __str__(self):
Expand Down
5 changes: 3 additions & 2 deletions netbox_floorplan/navigation.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,10 @@
#
menu_buttons = (
PluginMenuItem(
link="plugins:netbox_floorplan:floorplan_list",
link_text="Floorplans",
link="plugins:netbox_floorplan:floorplanimage_list",
link_text="Floorplan Images",
),

)


Expand Down
Loading

0 comments on commit c7eafe6

Please sign in to comment.