Changeset - 2755f34f36d7
[Not reviewed]
default
0 2 1
Branko Majic (branko) - 11 years ago 2013-06-22 22:26:57
branko@majic.rs
Added the 'view' permission for project, location, and entity. Added query optimisations. Integrated permissions into views.
3 files changed with 72 insertions and 6 deletions:
0 comments (0 inline, 0 general)
conntrackt/models.py
Show inline comments
 
# Django imports.
 
from django.core.exceptions import ValidationError
 
from django.db import models
 

	
 

	
 
class ViewPermissionModelMetaClass(models.base.ModelBase):
 
    """
 
    Implements a meta class that can be used for automatically adding the view
 
    permission for a model.
 

	
 
    Limitation is that syncdb must be called with --all if using South.
 

	
 
    Original source found at:
 

	
 
    http://stackoverflow.com/questions/725913/dynamic-meta-attributes-for-django-models
 
    """
 

	
 
    def __new__(cls, name, bases, attrs):
 
        cl = super(ViewPermissionModelMetaClass, cls).__new__(cls, name, bases, attrs)
 
        cl._meta.permissions.append(('view_' + cl._meta.module_name, u'Can view %s' % cl._meta.verbose_name))
 

	
 
        return cl
 

	
 

	
 
class Project(models.Model):
 
    """
 
    Implements a model with information about a project. A project has some
 
    basic settings, and mainly serves the purpose of grouping entities for
 
    easier handling and administration.
 

	
 
@@ -15,12 +34,14 @@ class Project(models.Model):
 
      description - Free-form description of the project.
 
    """
 

	
 
    name = models.CharField(max_length=100)
 
    description = models.TextField(blank=True)
 

	
 
    __metaclass__ = ViewPermissionModelMetaClass
 

	
 
    def __unicode__(self):
 
        """
 
        Returns:
 
          String representation of a project.
 
        """
 

	
 
@@ -51,12 +72,14 @@ class Location(models.Model):
 
      description - Free-form description of a location.
 
    """
 

	
 
    name = models.CharField(max_length=100)
 
    description = models.TextField(blank=True)
 

	
 
    __metaclass__ = ViewPermissionModelMetaClass
 

	
 
    def __unicode__(self):
 
        """
 
        Returns:
 
          String representation of a location.
 
        """
 

	
 
@@ -85,12 +108,14 @@ class Entity(models.Model):
 

	
 
    name = models.CharField(max_length=100)
 
    description = models.TextField(blank=True)
 
    project = models.ForeignKey(Project)
 
    location = models.ForeignKey(Location)
 

	
 
    __metaclass__ = ViewPermissionModelMetaClass
 

	
 
    class Meta:
 
        """
 
        Overrides some of the default parameters used by Django for this model.
 

	
 
        Properties:
 
          verbose_name_plural - Changes the way Django Admin displays the model
conntrackt/templates/403.html
Show inline comments
 
new file 100644
 
{% extends "conntrackt/template.html" %}
 

	
 
{% block content %}
 
<h1>Access denied</h1>
 

	
 
<div class="alert alert-error">You have insufficient privileges to access this resource. Please contact your local system administrator if you believe you should have been granted access.</div>
 

	
 
{% endblock content %}
conntrackt/views.py
Show inline comments
 
# Standard library imports.
 
from StringIO import StringIO
 
from zipfile import ZipFile, ZIP_DEFLATED
 

	
 
# Django imports.
 
from django.contrib.auth.decorators import permission_required
 
from django.http import HttpResponse
 
from django.shortcuts import render_to_response, get_object_or_404
 
from django.views.generic import TemplateView, DetailView
 

	
 
# Third-party application imports.
 
from braces.views import MultiplePermissionsRequiredMixin
 

	
 
# Application imports.
 
from .models import Project, Entity, Location
 
from .utils import generate_entity_iptables
 

	
 

	
 
class IndexView(TemplateView):
 
class IndexView(MultiplePermissionsRequiredMixin, TemplateView):
 
    """
 
    Custom view used for rendering the index page.
 
    """
 

	
 
    template_name = 'conntrackt/index.html'
 

	
 
    # Required permissions.
 
    permissions = {
 
        "all": ("conntrackt.view_project", "conntrackt.view_location",),
 
        }
 
    # Raise authorisation denied exception for unmet permissions.
 
    raise_exception = True
 

	
 
    def get_context_data(self, **kwargs):
 
        """
 
        Returns the context data that should be used for rendering of the
 
        template.
 

	
 
        Adds the 'projects' context object containing all of the projects
 
        available sorted aplhabetically by name.
 
        """
 

	
 
        # Set the context using the parent class.
 
        context = super(IndexView, self).get_context_data(**kwargs)
 

	
 
        context['projects'] = Project.objects.all().order_by('name')
 
        # Store information about all projcts in context. Optimise database
 
        # access for the view.
 
        context['projects'] = Project.objects.all().prefetch_related('entity_set').order_by('name')
 

	
 
        return context
 

	
 

	
 
class ProjectView(DetailView):
 
class ProjectView(MultiplePermissionsRequiredMixin, DetailView):
 
    """
 
    Custom view for presenting the project information.
 
    """
 

	
 
    model = Project
 

	
 
    permissions = {
 
        "all": ("conntrackt.view_project", "conntrackt.view_location",)
 
        }
 
    # Raise authorisation denied exception for unmet permissions.
 
    raise_exception = True
 

	
 
    def get_context_data(self, **kwargs):
 
        """
 
        Returns the context data that should be used for rendering of the
 
        template.
 

	
 
        Adds the 'location_entities' context object that contains tuples of the
 
@@ -70,17 +88,30 @@ class ProjectView(DetailView):
 
        context['location_entities'] = location_entities
 

	
 
        # Finally return the context.
 
        return context
 

	
 

	
 
class EntityView(DetailView):
 
class EntityView(MultiplePermissionsRequiredMixin, DetailView):
 
    """
 
    Custom view for presenting entity information.
 
    """
 
    model = Entity
 

	
 
    # Optimise the query to fetch the related data from reverse relationships.
 
    queryset = Entity.objects.all()
 
    queryset = queryset.prefetch_related('interface_set__destination_set__source__entity')
 
    queryset = queryset.prefetch_related('interface_set__destination_set__destination__entity')
 
    queryset = queryset.prefetch_related('interface_set__source_set__source__entity')
 
    queryset = queryset.prefetch_related('interface_set__source_set__destination__entity')
 

	
 
    # Required permissions.
 
    permissions = {
 
        "all": ("conntrackt.view_entity",)
 
        }
 
    # Raise authorisation denied exception for unmet permissions.
 
    raise_exception = True
 

	
 
    def get_context_data(self, **kwargs):
 
        """
 
        Returns the context data that should be used for rendering of the
 
        template.
 

	
 
@@ -94,12 +125,13 @@ class EntityView(DetailView):
 
        # Add the rendered iptables rules to the context.
 
        context['entity_iptables'] = generate_entity_iptables(self.object)
 

	
 
        return context
 

	
 

	
 
@permission_required("conntrackt.view_entity", raise_exception = True)
 
def entity_iptables(request, pk):
 
    """
 
    Custom view that returns response containing iptables rules generated for an
 
    entity.
 

	
 
    Makes sure to set the Content-Disposition of a response in order to
 
@@ -126,12 +158,13 @@ def entity_iptables(request, pk):
 
    # browser to download the file with suggested filename.
 
    response['Content-Disposition']="attachment; filename=%s-iptables.conf" % entity.name.lower().replace(" ", "_")
 

	
 
    return response
 

	
 

	
 
@permission_required("conntrackt.view_entity", raise_exception = True)
 
def project_iptables(request, project_id, location_id=None):
 
    """
 
    Custom view for obtaining iptables for all entities of a project or project
 
    location in a single ZIP file.
 

	
 
    Arguments:
0 comments (0 inline, 0 general)