Changeset - 018e7beed874
[Not reviewed]
default
0 5 3
Branko Majic (branko) - 11 years ago 2013-07-10 22:24:25
branko@majic.rs
CONNT-3: Implemented support for modifying the location information from within Conntrackt application itself. Appropriate tests were implemented as well.
8 files changed with 381 insertions and 16 deletions:
0 comments (0 inline, 0 general)
conntrackt/templates/conntrackt/index.html
Show inline comments
 
@@ -9,59 +9,62 @@
 
  <h1 class="span12">Welcome to Conntrackt</h1>
 
</div>
 

	
 
<div class="row">
 
    <div class="span12">Below you may find the list of projects that are available to you. Clicking on the project will take you to the summary page for that particular project. Clicking on an entity inside of a project will take you to the summary page of an entity.</div>
 
</div>
 

	
 
<hr>
 

	
 
<div class="row">
 
  <div class="span12">
 
    {% html_link "Add project" "project_create" class="btn btn-primary" %}
 
    {% html_link "Add location" "location_create" class="btn btn-primary" %}
 
  </div>
 
</div>
 

	
 
<hr>
 

	
 
<div class="row">
 

	
 
  <div class="span6">
 
    <h2>Projects</h2>
 
    <div class="well">
 
    {% if projects %}
 
      <table class="table table-striped">
 
        {% for project in projects %}
 
          <tr>
 
            <td style="width:99%">{% html_link project.name "project" project.id class="btn btn-link" %}</td>
 
            <td>{% html_link '<i class="icon-list"></i>' "project_iptables" project.id class="btn btn-link" %}</td>
 
            <td>{% html_link '<i class="icon-edit"></i>' "project_update" project.id class="btn btn-link" %}</td>
 
            <td>{% html_link '<i class="icon-remove"></i>' "project_delete" project.id class="btn btn-link" %}</td>
 
          </tr>
 
        {% endfor %}
 
      </table>
 
    {% else %}
 
      {% if projects %}
 
        <table class="table table-striped">
 
          {% for project in projects %}
 
            <tr>
 
              <td style="width:99%">{% html_link project.name "project" project.id class="btn btn-link" %}</td>
 
              <td>{% html_link '<i class="icon-list"></i>' "project_iptables" project.id class="btn btn-link" %}</td>
 
              <td>{% html_link '<i class="icon-edit"></i>' "project_update" project.id class="btn btn-link" %}</td>
 
              <td>{% html_link '<i class="icon-remove"></i>' "project_delete" project.id class="btn btn-link" %}</td>
 
            </tr>
 
          {% endfor %}
 
        </table>
 
      {% else %}
 
      There are no projects defined.
 
    {% endif %}
 
      {% endif %}
 
    </div>     
 
  </div>
 

	
 
  <div class="span6">
 
    <h2>Locations</h2>
 
    <div class="well">
 
      {% if locations %}
 
        <table class="table table-striped">
 
          {% for location in locations %}
 
            <tr>
 
              <td style="width:99%">{{location.name}}</td>
 
              <td>{% html_link '<i class="icon-edit"></i>' "location_update" location.id class="btn btn-link" %}</td>
 
              <td>{% html_link '<i class="icon-remove"></i>' "location_delete" location.id class="btn btn-link" %}</td>
 
            </tr>
 
          {% endfor %}
 
        </table>
 
      {% else %}
 
        There are no locations defined.
 
      {% endif %}
 
    </div>
 
  </div>
 

	
 
</div>
 

	
 
{% endblock %}
conntrackt/templates/conntrackt/location_confirm_delete.html
Show inline comments
 
new file 100644
 
{% extends "conntrackt/base.html" %}
 

	
 
{# For html_link #}
 
{% load conntrackt_tags %}
 
{# For Bootstrapped forms #}
 
{% load crispy_forms_tags %}
 

	
 
{% block content %}
 
<div class="row">
 
  <h1 class="span12">Remove location {{location.name}}</h1>
 
</div>
 
<div class="row">
 
  <div class="span12">
 
    <form action="" method="post">
 
      <div class="controls controls-row">
 
        {% csrf_token %}
 
        {{ form }}
 
        Are you sure you want to remove this location?
 
      </div>
 
      <hr>
 
      <div class="controls">
 
        <button type="submit" class="btn btn-primary">Remove</button>
 
      </div>
 
    </form>
 
  </div>
 
</div>
 
{% endblock content %}
conntrackt/templates/conntrackt/location_create_form.html
Show inline comments
 
new file 100644
 
{% extends "conntrackt/base.html" %}
 

	
 
{# For html_link #}
 
{% load conntrackt_tags %}
 
{# For Bootstrapped forms #}
 
{% load crispy_forms_tags %}
 

	
 
{% block content %}
 
<div class="row">
 
  <h1 class="span12">Add new location</h1>
 
</div>
 
<div class="row">
 
  <div class="span6">
 
    <form action="" method="post">
 
      <div class="controls controls-row">
 
      {% csrf_token %}
 
      {{ form | crispy }}
 
      </div>
 
      <div class="controls">
 
        <button type="submit" class="btn btn-primary">Add</button>
 
      </div>
 
    </form>
 
  </div>
 
</div>
 
{% endblock content %}
conntrackt/templates/conntrackt/location_update_form.html
Show inline comments
 
new file 100644
 
{% extends "conntrackt/base.html" %}
 

	
 
{# For html_link #}
 
{% load conntrackt_tags %}
 
{# For Bootstrapped forms #}
 
{% load crispy_forms_tags %}
 

	
 
{% block content %}
 
<div class="row">
 
  <h1 class="span12">Edit location {{location.name}}</h1>
 
</div>
 
<div class="row">
 
  <div class="span6">
 
    <form action="" method="post">
 
      <div class="controls controls-row">
 
      {% csrf_token %}
 
      {{ form | crispy }}
 
      </div>
 
      <div class="controls">
 
        <button type="submit" class="btn btn-primary">Update</button>
 
      </div>
 
    </form>
 
  </div>
 
</div>
 
{% endblock content %}
conntrackt/tests/test_views.py
Show inline comments
 
@@ -85,25 +85,25 @@ class IndexViewTest(ViewTest):
 
        """
 

	
 
        self.client.login(username="fullperms", password="fullperms")
 

	
 
        response = self.client.get(reverse("index"))
 

	
 
        self.assertQuerysetEqual(response.context["projects"], ["<Project: Test Project 1>", "<Project: Test Project 2>"])
 
        self.assertContains(response, "Test Project 1")
 
        self.assertContains(response, "Test Project 2")
 

	
 
    def test_locations_available(self):
 
        """
 
        Tests if locations are show or not.
 
        Tests if locations are shown or not.
 
        """
 

	
 
        self.client.login(username="fullperms", password="fullperms")
 

	
 
        response = self.client.get(reverse("index"))
 

	
 
        self.assertQuerysetEqual(response.context["locations"], ["<Location: Test Location 1>", "<Location: Test Location 2>"])
 
        self.assertContains(response, "Test Location 1")
 
        self.assertContains(response, "Test Location 2")
 

	
 

	
 
class ProjectViewTest(ViewTest):
 
@@ -559,12 +559,190 @@ class ProjectDeleteViewTest(TestCase):
 
        Tests if the message gets added when the project is deleted.
 
        """
 

	
 
        self.client.login(username="fullperms", password="fullperms")
 

	
 
        response = self.client.get(reverse("project_delete", args=(1,)))
 

	
 
        response = self.client.post(reverse("project_delete", args=(1,)),
 
                                    {'csrfmiddlewaretoken': response.context['request'].META['CSRF_COOKIE']},
 
                                    follow=True)
 

	
 
        self.assertContains(response, "Project Test Project 1 has been removed.")
 

	
 

	
 
class LocationCreateViewTest(TestCase):
 

	
 
    def setUp(self):
 
        # Set-up web client.
 
        self.client = Client()
 

	
 
        # Set-up users with different view permissions.
 
        self.user = {}
 
        self.user["fullperms"] = User.objects.create_user("fullperms", "fullperms@example.com", "fullperms")
 
        self.user["fullperms"].user_permissions.add(Permission.objects.get(codename="add_location"))
 
        self.user["noperms"] = User.objects.create_user("noperms", "noperms@example.com", "noperms")
 

	
 
    def test_permission_denied(self):
 
        """
 
        Tests if permission will be denied for client without sufficient privileges.
 
        """
 

	
 
        self.client.login(username="noperms", password="noperms")
 

	
 
        response = self.client.get(reverse("location_create"))
 

	
 
        self.assertContains(response, "You have insufficient privileges to access this resource. Please contact your local system administrator if you believe you should have been granted access.", status_code=403)
 

	
 
    def test_permission_granted(self):
 
        """
 
        Tests if permission will be granted for user with correct privileges.
 
        """
 

	
 
        self.client.login(username="fullperms", password="fullperms")
 

	
 
        response = self.client.get(reverse("location_create"))
 

	
 
        self.assertEqual(response.status_code, 200)
 

	
 
    def test_form_styling(self):
 
        """
 
        Tests if proper form styling is being applied.
 
        """
 

	
 
        self.client.login(username="fullperms", password="fullperms")
 

	
 
        response = self.client.get(reverse("location_create"))
 

	
 
        self.assertContains(response, 'class="span6 textinput')
 
        self.assertContains(response, 'class="span6 textarea')
 
        self.assertContains(response, 'placeholder="New Location"')
 
        self.assertContains(response, 'placeholder="Description for new location."')
 

	
 

	
 
class LocationUpdateViewTest(TestCase):
 

	
 
    fixtures = ['test-data.json']
 

	
 
    def setUp(self):
 
        # Set-up web client.
 
        self.client = Client()
 

	
 
        # Set-up users with different view permissions.
 
        self.user = {}
 
        self.user["fullperms"] = User.objects.create_user("fullperms", "fullperms@example.com", "fullperms")
 
        self.user["fullperms"].user_permissions.add(Permission.objects.get(codename="change_location"))
 
        self.user["noperms"] = User.objects.create_user("noperms", "noperms@example.com", "noperms")
 

	
 
    def test_permission_denied(self):
 
        """
 
        Tests if permission will be denied for client without sufficient privileges.
 
        """
 

	
 
        self.client.login(username="noperms", password="noperms")
 

	
 
        response = self.client.get(reverse("location_update", args=(1,)))
 

	
 
        self.assertContains(response, "You have insufficient privileges to access this resource. Please contact your local system administrator if you believe you should have been granted access.", status_code=403)
 

	
 
    def test_permission_granted(self):
 
        """
 
        Tests if permission will be granted for user with correct privileges.
 
        """
 

	
 
        self.client.login(username="fullperms", password="fullperms")
 

	
 
        response = self.client.get(reverse("location_update", args=(1,)))
 

	
 
        self.assertEqual(response.status_code, 200)
 

	
 
    def test_form_styling(self):
 
        """
 
        Tests if proper form styling is being applied.
 
        """
 

	
 
        self.client.login(username="fullperms", password="fullperms")
 

	
 
        response = self.client.get(reverse("location_update", args=(1,)))
 

	
 
        self.assertContains(response, 'class="span6 textinput')
 
        self.assertContains(response, 'class="span6 textarea')
 
        self.assertContains(response, 'placeholder="Location name"')
 
        self.assertContains(response, 'placeholder="Description for location."')
 

	
 
    def test_content(self):
 
        """
 
        Tests if the form comes pre-populated with proper content.
 
        """
 

	
 
        self.client.login(username="fullperms", password="fullperms")
 

	
 
        response = self.client.get(reverse("location_update", args=(1,)))
 

	
 
        self.assertContains(response, ">Edit location Test Location 1<")
 
        self.assertContains(response, 'value="Test Location 1"')
 
        self.assertContains(response, "This is a test location 1.")
 

	
 

	
 
class LocationDeleteViewTest(TestCase):
 

	
 
    fixtures = ['test-data.json']
 

	
 
    def setUp(self):
 
        # Set-up web client.
 
        self.client = Client()
 

	
 
        # Set-up users with different view permissions.
 
        self.user = {}
 
        self.user["fullperms"] = User.objects.create_user("fullperms", "fullperms@example.com", "fullperms")
 
        self.user["fullperms"].user_permissions.add(Permission.objects.get(codename="delete_location"))
 
        self.user["fullperms"].user_permissions.add(Permission.objects.get(codename="view"))
 
        self.user["noperms"] = User.objects.create_user("noperms", "noperms@example.com", "noperms")
 

	
 
    def test_permission_denied(self):
 
        """
 
        Tests if permission will be denied for client without sufficient privileges.
 
        """
 

	
 
        self.client.login(username="noperms", password="noperms")
 

	
 
        response = self.client.get(reverse("location_delete", args=(1,)))
 

	
 
        self.assertContains(response, "You have insufficient privileges to access this resource. Please contact your local system administrator if you believe you should have been granted access.", status_code=403)
 

	
 
    def test_permission_granted(self):
 
        """
 
        Tests if permission will be granted for user with correct privileges.
 
        """
 

	
 
        self.client.login(username="fullperms", password="fullperms")
 

	
 
        response = self.client.get(reverse("location_delete", args=(1,)))
 

	
 
        self.assertEqual(response.status_code, 200)
 

	
 
    def test_content(self):
 
        """
 
        Tests if the form comes pre-populated with proper content.
 
        """
 

	
 
        self.client.login(username="fullperms", password="fullperms")
 

	
 
        response = self.client.get(reverse("location_delete", args=(1,)))
 

	
 
        self.assertContains(response, ">Remove location Test Location 1<")
 
        self.assertContains(response, "Are you sure you want to remove this location?")
 

	
 
    def test_message(self):
 
        """
 
        Tests if the message gets added when the location is deleted.
 
        """
 

	
 
        self.client.login(username="fullperms", password="fullperms")
 

	
 
        response = self.client.get(reverse("location_delete", args=(1,)))
 

	
 
        response = self.client.post(reverse("location_delete", args=(1,)),
 
                                    {'csrfmiddlewaretoken': response.context['request'].META['CSRF_COOKIE']},
 
                                    follow=True)
 

	
 
        self.assertContains(response, "Location Test Location 1 has been removed.")
conntrackt/urls.py
Show inline comments
 
# Django imports.
 
from django.conf.urls import patterns, url
 
from django.contrib.auth.views import login, logout
 

	
 
# Application imports.
 
from .views import IndexView, ProjectView, ProjectCreateView, ProjectUpdateView, ProjectDeleteView, EntityView, entity_iptables, project_iptables
 
from .views import IndexView, EntityView, entity_iptables, project_iptables
 
from .views import ProjectView, ProjectCreateView, ProjectUpdateView, ProjectDeleteView
 
from .views import LocationCreateView, LocationUpdateView, LocationDeleteView
 

	
 

	
 
urlpatterns = patterns(
 
    'conntrackt.views',
 
    # Homepage/index view.
 
    url(r'^$', IndexView.as_view(), name="index"),
 

	
 
    # View for showing information about a project.
 
    url(r'^project/(?P<pk>\d+)/$', ProjectView.as_view(),
 
        name='project'),
 
    # View for creating a new project.
 
    url(r'^project/add/$', ProjectCreateView.as_view(), name="project_create"),
 
    # View for updating an existing project.
 
    url(r'^project/(?P<pk>\d+)/edit/$', ProjectUpdateView.as_view(), name="project_update"),
 
    # View for deleting a project.
 
    url(r'^project/(?P<pk>\d+)/remove/$', ProjectDeleteView.as_view(), name="project_delete"),
 

	
 
    # View for creating a new location.
 
    url(r'^location/add/$', LocationCreateView.as_view(), name="location_create"),
 
    # View for updating an existing location.
 
    url(r'^location/(?P<pk>\d+)/edit/$', LocationUpdateView.as_view(), name="location_update"),
 
    # View for deleting a location.
 
    url(r'^location/(?P<pk>\d+)/remove/$', LocationDeleteView.as_view(), name="location_delete"),
 

	
 

	
 
    # View for showing information about an entity.
 
    url(r'^entity/(?P<pk>\d+)/$', EntityView.as_view(),
 
        name='entity'),
 
    # View for rendering iptables rules for a specific entity.
 
    url(r'^entity/(?P<pk>\d+)/iptables/$', entity_iptables, name="entity_iptables"),
 
    # View for rendering zip file with iptables rules for all entities in a project.
 
    url(r'^project/(?P<project_id>\d+)/iptables/$', project_iptables, name="project_iptables"),
 
    # View for rendering zip file with iptables rules for all entities in a project for a specific location.
 
    url(r'^project/(?P<project_id>\d+)/location/(?P<location_id>\d+)/iptables/$', project_iptables, name="project_location_iptables"),
 
    # Views for logging-in/out the users.
 
    url(r'^login/$', login, {'template_name': 'conntrackt/login.html'}, name="login"),
 
    url(r'^logout/$', logout, name="logout"),
conntrackt/views.py
Show inline comments
 
@@ -314,12 +314,106 @@ class ProjectDeleteView(MultiplePermissi
 

	
 
    success_url = reverse_lazy("index")
 

	
 
    def post(self, *args, **kwargs):
 
        """
 
        Add a success message that will be displayed to the user to confirm the
 
        project deletion.
 
        """
 

	
 
        messages.success(self.request, "Project %s has been removed." % self.get_object().name, extra_tags="alert alert-success")
 

	
 
        return super(ProjectDeleteView, self).post(*args, **kwargs)
 

	
 

	
 
class LocationCreateView(MultiplePermissionsRequiredMixin, CreateView):
 
    """
 
    View for creating a new location.
 
    """
 

	
 
    model = Location
 
    template_name_suffix = "_create_form"
 

	
 
    # Required permissions.
 
    permissions = {
 
        "all": ("conntrackt.add_location",),
 
        }
 

	
 
    # Raise authorisation denied exception for unmet permissions.
 
    raise_exception = True
 

	
 
    success_url = reverse_lazy("index")
 

	
 
    def get_form(self, form_class):
 
        """
 
        Implements an override for the default form constructed for the create
 
        view that includes some better styling of input widgets.
 
        """
 

	
 
        form = super(LocationCreateView, self).get_form(form_class)
 
        form.fields["name"].widget.attrs["class"] = "span6"
 
        form.fields["name"].widget.attrs["placeholder"] = "New Location"
 
        form.fields["description"].widget.attrs["class"] = "span6"
 
        form.fields["description"].widget.attrs["placeholder"] = "Description for new location."
 

	
 
        return form
 

	
 

	
 
class LocationUpdateView(MultiplePermissionsRequiredMixin, UpdateView):
 
    """
 
    View for modifying an existing location.
 
    """
 

	
 
    model = Location
 
    template_name_suffix = "_update_form"
 

	
 
    # Required permissions.
 
    permissions = {
 
        "all": ("conntrackt.change_location",),
 
        }
 

	
 
    # Raise authorisation denied exception for unmet permissions.
 
    raise_exception = True
 

	
 
    success_url = reverse_lazy("index")
 

	
 
    def get_form(self, form_class):
 
        """
 
        Implements an override for the default form constructed for the create
 
        view that includes some better styling of input widgets.
 
        """
 

	
 
        form = super(LocationUpdateView, self).get_form(form_class)
 
        form.fields["name"].widget.attrs["class"] = "span6"
 
        form.fields["name"].widget.attrs["placeholder"] = "Location name"
 
        form.fields["description"].widget.attrs["class"] = "span6"
 
        form.fields["description"].widget.attrs["placeholder"] = "Description for location."
 

	
 
        return form
 

	
 

	
 
class LocationDeleteView(MultiplePermissionsRequiredMixin, DeleteView):
 
    """
 
    View for deleting a location.
 
    """
 

	
 
    model = Location
 

	
 
    # Required permissions.
 
    permissions = {
 
        "all": ("conntrackt.delete_location",),
 
        }
 

	
 
    # Raise authorisation denied exception for unmet permissions.
 
    raise_exception = True
 

	
 
    success_url = reverse_lazy("index")
 

	
 
    def post(self, *args, **kwargs):
 
        """
 
        Add a success message that will be displayed to the user to confirm the
 
        location deletion.
 
        """
 

	
 
        messages.success(self.request, "Location %s has been removed." % self.get_object().name, extra_tags="alert alert-success")
 

	
 
        return super(LocationDeleteView, self).post(*args, **kwargs)
docs/conf.py
Show inline comments
 
@@ -2,25 +2,26 @@
 
#
 
# Django Conntrackt documentation build configuration file, created by
 
# sphinx-quickstart on Sun Apr 14 21:47:09 2013.
 
#
 
# This file is execfile()d with the current directory set to its containing dir.
 
#
 
# Note that not all possible configuration values are present in this
 
# autogenerated file.
 
#
 
# All configuration values have a default; values that are commented out
 
# serve to show the default.
 

	
 
import sys, os
 
import sys
 
import os
 

	
 
# If extensions (or modules to document with autodoc) are in another directory,
 
# add these directories to sys.path here. If the directory is relative to the
 
# documentation root, use os.path.abspath to make it absolute, like shown here.
 
#sys.path.insert(0, os.path.abspath('.'))
 

	
 
# -- General configuration -----------------------------------------------------
 

	
 
# If your documentation needs a minimal Sphinx version, state it here.
 
#needs_sphinx = '1.0'
 

	
 
# Add any Sphinx extension module names here, as strings. They can be extensions
0 comments (0 inline, 0 general)