Browse Source

Added views for editing/deleting VCMemberships

Jeremy Stretch 7 years ago
parent
commit
da2bff691b

+ 5 - 1
netbox/dcim/forms.py

@@ -2219,8 +2219,12 @@ class VirtualChassisCreateForm(BootstrapMixin, forms.ModelForm):
         self.fields['master'].queryset = Device.objects.filter(pk__in=candidate_pks)
 
 
+#
+# VC memberships
+#
+
 class VCMembershipForm(BootstrapMixin, forms.ModelForm):
 
     class Meta:
         model = VCMembership
-        fields = ['device', 'position', 'priority']
+        fields = ['position', 'priority']

+ 14 - 6
netbox/dcim/models.py

@@ -1507,7 +1507,7 @@ class VirtualChassis(models.Model):
         return self.master.name
 
     def get_absolute_url(self):
-        return "{}?virtual_chassis={}".format(reverse('dcim:device_list'), self.pk)
+        return self.master.get_absolute_url()
 
     @property
     def master(self):
@@ -1547,13 +1547,21 @@ class VCMembership(models.Model):
         unique_together = ['virtual_chassis', 'position']
         verbose_name = 'VC membership'
 
+    def __str__(self):
+        return self.device.name
+
     def clean(self):
 
+        # We have to call this here because it won't be called by VCMembershipForm
+        self.validate_unique()
+
         # Check for master conflicts
         if getattr(self, 'virtual_chassis', None) and self.is_master:
-            master_conflict = VCMembership.objects.filter(virtual_chassis=self.virtual_chassis).first()
+            master_conflict = VCMembership.objects.filter(
+                virtual_chassis=self.virtual_chassis, is_master=True
+            ).exclude(pk=self.pk).first()
             if master_conflict:
-                raise ValidationError({
-                    'virtual_chassis': "{} has already been designated as the master for this virtual chassis. It must "
-                                       "be demoted before a new master can be assigned.".format(master_conflict.device)
-                })
+                raise ValidationError(
+                    "{} has already been designated as the master for this virtual chassis. It must be demoted before "
+                    "a new master can be assigned.".format(master_conflict.device)
+                )

+ 4 - 0
netbox/dcim/urls.py

@@ -213,4 +213,8 @@ urlpatterns = [
     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'),
 
+    # VC memberships
+    url(r'^vc-memberships/(?P<pk>\d+)/edit/$', views.VCMembershipEditView.as_view(), name='vcmembership_edit'),
+    url(r'^vc-memberships/(?P<pk>\d+)/delete/$', views.VCMembershipDeleteView.as_view(), name='vcmembership_delete'),
+
 ]

+ 19 - 0
netbox/dcim/views.py

@@ -1859,6 +1859,10 @@ class VirtualChassisCreateView(PermissionRequiredMixin, View):
         class _VCMembershipForm(forms.VCMembershipForm):
             device = ModelChoiceField(queryset=Device.objects.filter(pk__in=device_list))
 
+            class Meta:
+                model = VCMembership
+                fields = ['device', 'position', 'priority']
+
         VCMembershipFormSet = modelformset_factory(model=VCMembership, form=_VCMembershipForm, extra=len(device_list))
 
         if '_create' in request.POST:
@@ -1902,3 +1906,18 @@ class VirtualChassisDeleteView(PermissionRequiredMixin, ObjectDeleteView):
     permission_required = 'dcim.delete_virtualchassis'
     model = VirtualChassis
     default_return_url = 'dcim:device_list'
+
+
+#
+# VC memberships
+#
+
+class VCMembershipEditView(PermissionRequiredMixin, ObjectEditView):
+    permission_required = 'dcim.change_vcmembership'
+    model = VCMembership
+    model_form = forms.VCMembershipForm
+
+
+class VCMembershipDeleteView(PermissionRequiredMixin, ObjectDeleteView):
+    permission_required = 'dcim.delete_vcmembership'
+    model = VCMembership

+ 38 - 5
netbox/templates/dcim/virtualchassis_edit.html

@@ -1,11 +1,44 @@
 {% extends 'utilities/obj_edit.html' %}
 {% load form_helpers %}
 
-{% block form %}
-    <div class="panel panel-default">
-        <div class="panel-heading"><strong>{{ obj_type|capfirst }}</strong></div>
-        <div class="panel-body">
-            {% render_form form %}
+{% block content %}
+    {{ block.super }}
+    <div class="row">
+        <div class="col-md-6 col-md-offset-3">
+            <h3>Memberships</h3>
+            <div class="panel panel-default">
+                <table class="table panel-body">
+                    <tr class="table-headings">
+                        <th>Device</th>
+                        <th>Position</th>
+                        <th>Master</th>
+                        <th>Priority</th>
+                        <th></th>
+                    </tr>
+                    {% for vcm in form.instance.memberships.all %}
+                        <tr>
+                            <td>
+                                <a href="{{ vcm.device.get_absolute_url }}">{{ vcm.device }}</a>
+                            </td>
+                            <td>{{ vcm.position }}</td>
+                            <td>{% if vcm.is_master %}<i class="fa fa-check"></i>{% endif %}</td>
+                            <td>{{ vcm.priority|default:"" }}</td>
+                            <td class="text-right">
+                                 {% if perms.dcim.change_vcmembership %}
+                                    <a href="{% url 'dcim:vcmembership_edit' pk=vcm.pk %}?return_url={% url 'dcim:virtualchassis_edit' pk=vcm.virtual_chassis.pk %}" class="btn btn-warning btn-xs">
+                                        <span class="glyphicon glyphicon-pencil" aria-hidden="true"></span> Edit
+                                    </a>
+                                {% endif %}
+                                 {% if perms.dcim.delete_vcmembership %}
+                                    <a href="{% url 'dcim:vcmembership_delete' pk=vcm.pk %}?return_url={% url 'dcim:virtualchassis_edit' pk=vcm.virtual_chassis.pk %}" class="btn btn-danger btn-xs">
+                                        <span class="glyphicon glyphicon-trash" aria-hidden="true"></span> Delete
+                                    </a>
+                                {% endif %}
+                            </td>
+                        </tr>
+                    {% endfor %}
+                </table>
+            </div>
         </div>
     </div>
 {% endblock %}