Fixes #7757: Fix 404 when assigning multiple contacts/FHRP groups in succession

This commit is contained in:
jeremystretch 2021-11-09 17:08:28 -05:00
parent f93d6813a9
commit 34f24de3e4
8 changed files with 12 additions and 66 deletions

View File

@ -8,6 +8,7 @@
### Bug Fixes
* [#7756](https://github.com/netbox-community/netbox/issues/7756) - Fix AttributeError exception when editing an IP address assigned to a FHRPGroup
* [#7757](https://github.com/netbox-community/netbox/issues/7757) - Fix 404 when assigning multiple contacts/FHRP groups in succession
* [#7768](https://github.com/netbox-community/netbox/issues/7768) - Validate IP address status when creating a new FHRP group
* [#7771](https://github.com/netbox-community/netbox/issues/7771) - Group assignment should be optional when creating contacts via REST API

View File

@ -52,9 +52,7 @@ class FHRPGroup(PrimaryModel):
objects = RestrictedQuerySet.as_manager()
clone_fields = [
'protocol', 'auth_type', 'auth_key'
]
clone_fields = ('protocol', 'auth_type', 'auth_key')
class Meta:
ordering = ['protocol', 'group_id', 'pk']
@ -91,6 +89,8 @@ class FHRPGroupAssignment(ChangeLoggedModel):
objects = RestrictedQuerySet.as_manager()
clone_fields = ('interface_type', 'interface_id')
class Meta:
ordering = ('-priority', 'pk')
unique_together = ('interface_type', 'interface_id', 'group')

View File

@ -976,11 +976,7 @@ class FHRPGroupAssignmentEditView(generic.ObjectEditView):
def alter_obj(self, instance, request, args, kwargs):
if not instance.pk:
# Assign the interface based on URL kwargs
try:
app_label, model = request.GET.get('interface_type').split('.')
except (AttributeError, ValueError):
raise Http404("Content type not specified")
content_type = get_object_or_404(ContentType, app_label=app_label, model=model)
content_type = get_object_or_404(ContentType, pk=request.GET.get('interface_type'))
instance.interface = get_object_or_404(content_type.model_class(), pk=request.GET.get('interface_id'))
return instance

View File

@ -41,7 +41,7 @@
</div>
{% if perms.tenancy.add_contactassignment %}
<div class="card-footer text-end noprint">
<a href="{% url 'tenancy:contactassignment_add' %}?content_type={{ object|meta:"app_label" }}.{{ object|meta:"model_name" }}&object_id={{ object.pk }}&return_url={{ object.get_absolute_url }}" class="btn btn-primary btn-sm">
<a href="{% url 'tenancy:contactassignment_add' %}?content_type={{ object|content_type_id }}&object_id={{ object.pk }}&return_url={{ object.get_absolute_url }}" class="btn btn-primary btn-sm">
<i class="mdi mdi-plus-thick" aria-hidden="true"></i> Add a contact
</a>
</div>

View File

@ -1,49 +0,0 @@
{% load helpers %}
<div class="card">
<h5 class="card-header">Contacts</h5>
<div class="card-body">
{% with fhrp_groups=object.fhrp_group_assignments.all %}
{% if contacts.exists %}
<table class="table table-hover">
<tr>
<th>Protocol</th>
<th>Group ID</th>
<th>Priority</th>
<th></th>
</tr>
{% for contact in contacts %}
<tr>
<td>
<a href="{{ contact.contact.get_absolute_url }}">{{ contact.contact }}</a>
</td>
<td>{{ contact.role|placeholder }}</td>
<td>{{ contact.get_priority_display|placeholder }}</td>
<td class="text-end noprint">
{% if perms.tenancy.change_contactassignment %}
<a href="{% url 'tenancy:contactassignment_edit' pk=contact.pk %}" class="btn btn-warning btn-sm lh-1" title="Edit">
<i class="mdi mdi-pencil" aria-hidden="true"></i>
</a>
{% endif %}
{% if perms.tenancy.delete_contactassignment %}
<a href="{% url 'extras:imageattachment_delete' pk=contact.pk %}" class="btn btn-danger btn-sm lh-1" title="Delete">
<i class="mdi mdi-trash-can-outline" aria-hidden="true"></i>
</a>
{% endif %}
</td>
</tr>
{% endfor %}
</table>
{% else %}
<div class="text-muted">None</div>
{% endif %}
{% endwith %}
</div>
{% if perms.tenancy.add_contactassignment %}
<div class="card-footer text-end noprint">
<a href="{% url 'tenancy:contactassignment_add' %}?content_type={{ object|meta:"app_label" }}.{{ object|meta:"model_name" }}&object_id={{ object.pk }}" class="btn btn-primary btn-sm">
<i class="mdi mdi-plus-thick" aria-hidden="true"></i> Add a contact
</a>
</div>
{% endif %}
</div>

View File

@ -46,7 +46,7 @@
</tr>
{% empty %}
<tr>
<td colspan="3" class="text-muted">None</td>
<td colspan="5" class="text-muted">None</td>
</tr>
{% endfor %}
</tbody>
@ -54,12 +54,12 @@
</div>
<div class="card-footer text-end noprint">
{% if perms.ipam.add_fhrpgroup %}
<a href="{% url 'ipam:fhrpgroup_add' %}?return_url={% url 'ipam:fhrpgroupassignment_add' %}%3Finterface_type={{ object|meta:"app_label" }}.{{ object|meta:"model_name" }}%26interface_id={{ object.pk }}" class="btn btn-sm btn-primary">
<a href="{% url 'ipam:fhrpgroup_add' %}?return_url={% url 'ipam:fhrpgroupassignment_add' %}%3Finterface_type={{ object|content_type_id }}%26interface_id={{ object.pk }}" class="btn btn-sm btn-primary">
<span class="mdi mdi-plus-thick" aria-hidden="true"></span> Create Group
</a>
{% endif %}
{% if perms.ipam.add_fhrpgroupassignment %}
<a href="{% url 'ipam:fhrpgroupassignment_add' %}?interface_type={{ object|meta:"app_label" }}.{{ object|meta:"model_name" }}&interface_id={{ object.pk }}&return_url={{ object.get_absolute_url }}" class="btn btn-sm btn-primary">
<a href="{% url 'ipam:fhrpgroupassignment_add' %}?interface_type={{ object|content_type_id }}&interface_id={{ object.pk }}&return_url={{ object.get_absolute_url }}" class="btn btn-sm btn-primary">
<span class="mdi mdi-plus-thick" aria-hidden="true"></span> Assign Group
</a>
{% endif %}

View File

@ -163,6 +163,8 @@ class ContactAssignment(ChangeLoggedModel):
objects = RestrictedQuerySet.as_manager()
clone_fields = ('content_type', 'object_id')
class Meta:
ordering = ('priority', 'contact')
unique_together = ('content_type', 'object_id', 'contact', 'role', 'priority')

View File

@ -343,11 +343,7 @@ class ContactAssignmentEditView(generic.ObjectEditView):
def alter_obj(self, instance, request, args, kwargs):
if not instance.pk:
# Assign the object based on URL kwargs
try:
app_label, model = request.GET.get('content_type').split('.')
except (AttributeError, ValueError):
raise Http404("Content type not specified")
content_type = get_object_or_404(ContentType, app_label=app_label, model=model)
content_type = get_object_or_404(ContentType, pk=request.GET.get('content_type'))
instance.object = get_object_or_404(content_type.model_class(), pk=request.GET.get('object_id'))
return instance