Skip to content

Commit 95f089a

Browse files
authored
Merge pull request #24 from netbox-community/v1.1.2
Patches
2 parents 2bc16d6 + c4bf573 commit 95f089a

File tree

16 files changed

+1854
-324
lines changed

16 files changed

+1854
-324
lines changed

.djlintrc

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"ignore": "H021,H023"
3+
}

.pre-commit-config.yaml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,3 +18,8 @@ repos:
1818
args: [ --fix ]
1919
# Run the formatter.
2020
- id: ruff-format
21+
- repo: https://github.com/djlint/djLint
22+
rev: v1.35.2
23+
hooks:
24+
- id: djlint-reformat-django
25+
- id: djlint-django

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ systemctl restart netbox
4848

4949
| netbox version | plugin version |
5050
| -------------- | ----------------------------- |
51-
| >= 4.0.0 | >= v1.1.0 |
51+
| >= 4.0.0 < 4.1.0 | >= v1.1.2 |
5252
| <= 4.0.0 | = v1.0.0 |
5353

5454
## Dependencies
@@ -57,7 +57,7 @@ Python:
5757

5858
Javascript:
5959
- Gridstack (Currently running same versions as Netbox)
60-
- Bootsrap (Currently running same versions as Netbox)
60+
- Bootstrap (Currently running same versions as Netbox)
6161

6262
### Update
6363

netbox_reorder_rack/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ class NetboxReorderRackConfig(PluginConfig):
55
name = "netbox_reorder_rack"
66
verbose_name = "NetBox Reorder Rack"
77
description = "NetBox plugin to reorder rack layouts."
8-
version = "1.1.1"
8+
version = "1.1.2"
99
base_url = "reorder"
1010

1111

netbox_reorder_rack/api/views.py

Lines changed: 102 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,24 @@
55
from django.contrib.auth.mixins import PermissionRequiredMixin
66
from django.db import transaction
77
from django.shortcuts import get_object_or_404
8+
from django.utils.translation import gettext_lazy as _
89
from rest_framework import serializers
910
from rest_framework import status
1011
from rest_framework import viewsets
12+
from rest_framework.exceptions import PermissionDenied
1113
from rest_framework.response import Response
14+
from utilities.permissions import get_permission_for_model
15+
16+
17+
def get_device_name(device):
18+
if device.virtual_chassis:
19+
name = f"{device.virtual_chassis.name}:{device.vc_position}"
20+
elif device.name:
21+
name = device.name
22+
else:
23+
name = str(device.device_type)
24+
25+
return name
1226

1327

1428
class ReorderRackSerializer(serializers.Serializer):
@@ -26,34 +40,103 @@ class SaveViewSet(PermissionRequiredMixin, viewsets.ViewSet):
2640

2741
def update(self, request, pk):
2842
rack = get_object_or_404(Rack, pk=pk)
43+
permission = get_permission_for_model(Device, "change")
44+
45+
# Validate input using serializer
46+
serializer = ReorderRackSerializer(data=request.data)
47+
serializer.is_valid(raise_exception=True)
48+
2949
try:
30-
serializer = ReorderRackSerializer(request.data)
31-
with transaction.atomic():
32-
for device in rack.devices.all():
33-
device.position = None
34-
device.clean()
35-
device.save()
50+
changes_made = False # Flag to track if any changes were made
3651

37-
for new in request.data["front"]:
38-
device = rack.devices.filter(pk=new["id"]).first()
39-
device.position = decimal.Decimal(new["y"])
40-
device.face = new["face"]
41-
device.clean()
42-
device.save()
52+
with transaction.atomic():
53+
# Update devices in different categories
54+
changes_made |= self._update_device_positions(
55+
request,
56+
rack,
57+
serializer.validated_data["front"],
58+
permission,
59+
"front",
60+
)
61+
changes_made |= self._update_device_positions(
62+
request, rack, serializer.validated_data["rear"], permission, "rear"
63+
)
64+
changes_made |= self._update_device_positions(
65+
request,
66+
rack,
67+
serializer.validated_data["other"],
68+
permission,
69+
"other",
70+
is_other=True,
71+
)
4372

44-
for new in request.data["rear"]:
45-
device = rack.devices.filter(pk=new["id"]).first()
46-
device.position = decimal.Decimal(new["y"])
47-
device.face = new["face"]
48-
device.clean()
49-
device.save()
73+
# If no changes were made, return 304 or a custom response
74+
if not changes_made:
75+
return Response(
76+
{"message": "No changes detected."},
77+
status=status.HTTP_304_NOT_MODIFIED,
78+
)
5079

5180
return Response(
52-
{"message": "POST request received", "data": serializer.data},
81+
{
82+
"message": "Devices reordered successfully",
83+
"data": serializer.data,
84+
},
5385
status=status.HTTP_201_CREATED,
5486
)
87+
except PermissionDenied as e:
88+
return Response(
89+
{"message": "Permission denied", "error": str(e)},
90+
status=status.HTTP_403_FORBIDDEN,
91+
)
5592
except Exception as e:
5693
return Response(
5794
{"message": "Error saving data", "error": str(e)},
5895
status=status.HTTP_500_INTERNAL_SERVER_ERROR,
5996
)
97+
98+
def _update_device_positions(
99+
self, request, rack, device_data_list, permission, device_type, is_other=False
100+
):
101+
"""Helper method to update device positions based on the category."""
102+
changes_made = False # Local flag to track if changes are made
103+
104+
for device_data in device_data_list:
105+
device = rack.devices.filter(pk=device_data["id"]).first()
106+
current_device = get_object_or_404(
107+
Device.objects.restrict(request.user), pk=device_data["id"]
108+
)
109+
110+
if is_other:
111+
if device.position != device_data["y"]:
112+
device.position = None
113+
device.face = ""
114+
self._check_permission(request, device, permission)
115+
116+
# Save the device and mark changes as made
117+
device.clean()
118+
device.save()
119+
changes_made = True
120+
# Update position and face for 'front' and 'rear' devices if changed
121+
elif not is_other:
122+
if current_device.face != device_data[
123+
"face"
124+
] or device.position != decimal.Decimal(device_data["y"]):
125+
device.position = decimal.Decimal(device_data["y"])
126+
device.face = device_data["face"]
127+
128+
self._check_permission(request, device, permission)
129+
130+
# Save the device and mark changes as made
131+
device.clean()
132+
device.save()
133+
changes_made = True
134+
135+
return changes_made # Return whether changes were made
136+
137+
def _check_permission(self, request, device, permission):
138+
"""Helper method to check if the user has permission for the device."""
139+
if not request.user.has_perm(permission, obj=device):
140+
raise PermissionDenied(
141+
_(f"You do not have permissions to edit {get_device_name(device)}.")
142+
)

netbox_reorder_rack/static/netbox_reorder_rack/js/rack.js

Lines changed: 10 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

netbox_reorder_rack/static/netbox_reorder_rack/js/rack.js.map

Lines changed: 3 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)