diff --git a/conntrackt/templates/conntrackt/entity_detail.html b/conntrackt/templates/conntrackt/entity_detail.html
--- a/conntrackt/templates/conntrackt/entity_detail.html
+++ b/conntrackt/templates/conntrackt/entity_detail.html
@@ -8,7 +8,16 @@
{% with project=entity.project location=entity.location %}
{% if entity %}
-
{{entity.name}}
+
+
{{entity.name}}
+
+
+
+
+ {% html_link "Remove" "entity_delete" entity.id class="btn btn-primary" %}
+
+
+
- Project
- {% html_link project.name 'project' project.id %}
- Location
- {{location.name}}
diff --git a/conntrackt/templates/conntrackt/location_widget.html b/conntrackt/templates/conntrackt/location_widget.html
--- a/conntrackt/templates/conntrackt/location_widget.html
+++ b/conntrackt/templates/conntrackt/location_widget.html
@@ -1,11 +1,23 @@
{% load conntrackt_tags %}
- {{location.name}} | {% html_link '' 'project_location_iptables' project.id location.id class="btn btn-link" %} |
+
+ {{location.name}} |
+ {% html_link '' 'project_location_iptables' project.id location.id class="btn btn-link" %} |
+ |
+
{% for entity in entities %}
- {% html_link entity.name 'entity' entity.id class="btn btn-link" %} | {% html_link '' 'entity_iptables' entity.id class="btn btn-link" %} |
+
+ {% html_link entity.name 'entity' entity.id class="btn btn-link" %} |
+ {% html_link '' 'entity_iptables' entity.id class="btn btn-link" %} |
+ {% html_link '' 'entity_delete' entity.id class="btn btn-link" %} |
+
{% endfor %}
{% with project_id=project.id|slugify location_id=location.id|slugify %}
- {% html_link "Add entity" "entity_create" class="btn btn-primary btn-mini" get="project="|add:project_id|add:"&location="|add:location_id %} | |
+
+ {% html_link "Add entity" "entity_create" class="btn btn-primary btn-mini" get="project="|add:project_id|add:"&location="|add:location_id %} |
+ |
+ |
+
{% endwith %}
diff --git a/conntrackt/urls.py b/conntrackt/urls.py
--- a/conntrackt/urls.py
+++ b/conntrackt/urls.py
@@ -6,7 +6,7 @@ from django.contrib.auth.views import lo
from .views import IndexView, EntityView, entity_iptables, project_iptables
from .views import ProjectView, ProjectCreateView, ProjectUpdateView, ProjectDeleteView
from .views import LocationCreateView, LocationUpdateView, LocationDeleteView
-from .views import EntityCreateView
+from .views import EntityCreateView, EntityDeleteView
urlpatterns = patterns(
@@ -37,6 +37,8 @@ urlpatterns = patterns(
name='entity'),
# View for creating a new entity.
url(r'^entity/add/$', EntityCreateView.as_view(), name="entity_create"),
+ # View for deleting an entity.
+ url(r'^entity/(?P\d+)/remove/$', EntityDeleteView.as_view(), name="entity_delete"),
# View for rendering iptables rules for a specific entity.
url(r'^entity/(?P\d+)/iptables/$', entity_iptables, name="entity_iptables"),
diff --git a/conntrackt/views.py b/conntrackt/views.py
--- a/conntrackt/views.py
+++ b/conntrackt/views.py
@@ -5,7 +5,7 @@ from zipfile import ZipFile, ZIP_DEFLATE
# Django imports.
from django.contrib.auth.decorators import permission_required
from django.contrib import messages
-from django.core.urlresolvers import reverse_lazy
+from django.core.urlresolvers import reverse, reverse_lazy
from django.http import HttpResponse
from django.shortcuts import render_to_response, get_object_or_404
from django.views.generic import TemplateView, DetailView, CreateView, UpdateView, DeleteView
@@ -86,7 +86,7 @@ class ProjectView(MultiplePermissionsReq
# Add the (location, entities) tuple for each location that has entities
# belonging to the related project.
- for location in Location.objects.filter(entity__project=self.object).distinct():
+ for location in Location.objects.filter(entity__project=self.object).distinct().order_by("name"):
entities = Entity.objects.filter(project=self.object, location=location)
location_entities.append((location, entities))
@@ -473,3 +473,42 @@ class EntityCreateView(MultiplePermissio
initial["location"] = self.request.GET.get("location", None)
return initial
+
+
+class EntityDeleteView(MultiplePermissionsRequiredMixin, DeleteView):
+ """
+ View for deleting an entity.
+ """
+
+ model = Entity
+
+ # Required permissions.
+ permissions = {
+ "all": ("conntrackt.delete_entity",),
+ }
+
+ # Raise authorisation denied exception for unmet permissions.
+ raise_exception = True
+
+ def post(self, *args, **kwargs):
+ """
+ Add a success message that will be displayed to the user to confirm the
+ entity deletion.
+ """
+
+ messages.success(self.request, "Entity %s has been removed." % self.get_object().name, extra_tags="alert alert-success")
+
+ return super(EntityDeleteView, self).post(*args, **kwargs)
+
+
+ def delete(self, *args, **kwargs):
+ """
+ Deletes the object. This method is overridden in order to obtain the
+ project ID for success URL.
+
+ @TODO: Fix this once Django 1.6 comes out with fix from ticket 19044.
+ """
+
+ self.success_url = reverse("project", args=(self.get_object().project.id,))
+
+ return super(EntityDeleteView, self).delete(*args, **kwargs)