From ac2bf91a871e4474cd27438440a8166b75197e68 Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Wed, 15 Feb 2017 16:44:45 -0500 Subject: [PATCH] Added views for rack reservations --- netbox/dcim/models.py | 28 +++++++++++++++++++++++++++- netbox/dcim/urls.py | 1 + netbox/dcim/views.py | 13 +++++++++++-- netbox/templates/dcim/rack.html | 26 ++++++++++++++++++-------- 4 files changed, 57 insertions(+), 11 deletions(-) diff --git a/netbox/dcim/models.py b/netbox/dcim/models.py index 7b8647418..c95b6a823 100644 --- a/netbox/dcim/models.py +++ b/netbox/dcim/models.py @@ -488,7 +488,7 @@ class RackReservation(models.Model): created = models.DateTimeField(auto_now_add=True) user = models.ForeignKey(User, editable=False, on_delete=models.PROTECT) rack = models.ForeignKey('Rack', related_name='reservations', editable=False, on_delete=models.CASCADE) - units = ArrayField(models.PositiveSmallIntegerField(validators=[MinValueValidator(1)])) + units = ArrayField(models.PositiveSmallIntegerField()) description = models.CharField(max_length=100) class Meta: @@ -497,6 +497,32 @@ class RackReservation(models.Model): def __str__(self): return u"Reservation for rack {}".format(self.rack) + def clean(self): + + if self.units: + + # Validate that all specified units exist in the Rack. + invalid_units = [u for u in self.units if u not in self.rack.units] + if invalid_units: + raise ValidationError({ + 'units': u"Invalid unit(s) for {}U rack: {}".format( + self.rack.u_height, + ', '.join([str(u) for u in invalid_units]), + ), + }) + + # Check that none of the units has already been reserved for this Rack. + reserved_units = [] + for resv in self.rack.reservations.exclude(pk=self.pk): + reserved_units += resv.units + conflicting_units = [u for u in self.units if u in reserved_units] + if conflicting_units: + raise ValidationError({ + 'units': 'The following units have already been reserved: {}'.format( + ', '.join([str(u) for u in conflicting_units]), + ) + }) + # # Device Types diff --git a/netbox/dcim/urls.py b/netbox/dcim/urls.py index 08f14617c..1b337ad6e 100644 --- a/netbox/dcim/urls.py +++ b/netbox/dcim/urls.py @@ -31,6 +31,7 @@ urlpatterns = [ # Rack reservations url(r'^rack-reservations/(?P\d+)/edit/$', views.RackReservationEditView.as_view(), name='rackreservation_edit'), + url(r'^rack-reservations/(?P\d+)/delete/$', views.RackReservationDeleteView.as_view(), name='rackreservation_delete'), # Racks url(r'^racks/$', views.RackListView.as_view(), name='rack_list'), diff --git a/netbox/dcim/views.py b/netbox/dcim/views.py index 19a533339..4bec35be9 100644 --- a/netbox/dcim/views.py +++ b/netbox/dcim/views.py @@ -334,15 +334,24 @@ class RackReservationEditView(PermissionRequiredMixin, ObjectEditView): model = RackReservation form_class = forms.RackReservationForm - def alter_obj(self, obj, args, kwargs): - if 'rack' in kwargs: + def alter_obj(self, obj, request, args, kwargs): + if not obj.pk: obj.rack = get_object_or_404(Rack, pk=kwargs['rack']) + obj.user = request.user return obj def get_return_url(self, obj): return obj.rack.get_absolute_url() +class RackReservationDeleteView(PermissionRequiredMixin, ObjectDeleteView): + permission_required = 'dcim.delete_rackreservation' + model = RackReservation + + def get_return_url(self, obj): + return obj.rack.get_absolute_url() + + # # Manufacturers # diff --git a/netbox/templates/dcim/rack.html b/netbox/templates/dcim/rack.html index 4f25e5c54..37cddf213 100644 --- a/netbox/templates/dcim/rack.html +++ b/netbox/templates/dcim/rack.html @@ -198,22 +198,32 @@ Units Description - User - Created {% for resv in reservations %} - {{ resv.units }} - {{ resv.description }} - {{ resv.user }} - {{ resv.created }} - {% if perms.change_rackreservation %}edit{% endif %} + {{ resv.units|join:', ' }} + + {{ resv.description }}
+ {{ resv.user }} · {{ resv.created }} + + + {% if perms.change_rackreservation %} + + + + {% endif %} + {% if perms.delete_rackreservation %} + + + + {% endif %} + {% endfor %} {% else %} - None +
None
{% endif %} {% if perms.dcim.add_rackreservation %}