class Organisation(models.Model):
    name = models.CharField(max_length=100)

    class Meta:
        ordering = ('name',)

    class TutelaryMeta:
        perm_type = 'organisation'
        path_fields = ('name',)
        actions = [
            ('organisation.list',   {'permissions_object': None}),
            ('organisation.create', {'permissions_object': None}),
            'organisation.delete'
        ]

    def __str__(self):
        return self.name class Project(models.Model):
    name = models.CharField(max_length=100)
    organisation = models.ForeignKey(Organisation)

    class Meta:
        ordering = ('organisation', 'name')

    class TutelaryMeta:
        perm_type = 'project'
        path_fields = ('organisation', 'name')
        actions = [
            ('project.list', {'permissions_object': 'organisation'}),
            ('project.create', {'permissions_object': 'organisation'}),
            'project.delete'
        ]

    def __str__(self):
        return self.name class Party(models.Model):
    project = models.ForeignKey(Project)
    name = models.CharField(max_length=100)

    class Meta:
        ordering = ('project', 'name')

    class TutelaryMeta:
        perm_type = 'party'
        path_fields = ('project', 'pk')
        actions = [
            ('party.list',   {'description': "List existing parties",
                              'permissions_object': 'project'}),
            ('party.create', {'description': "Create parties",
                              'permissions_object': 'project'}),
            ('party.detail', {'description': "View details of a party"}),
            ('party.edit',   {'description': "Update existing parties"}),
            ('party.delete', {'description': "Delete parties"})
        ]

    def get_absolute_url(self):
        return reverse('party-detail', kwargs={'pk': self.pk}) class Parcel(models.Model):
    project = models.ForeignKey(Project)
    address = models.CharField(max_length=200)

    class Meta:
        ordering = ('project', 'address')

    class TutelaryMeta:
        perm_type = 'parcel'
        path_fields = ('project', 'pk')
        actions = [
            ('parcel.list',   {'description': "List existing parcels",
                               'permissions_object': 'project'}),
            ('parcel.create', {'description': "Create parcels",
                               'permissions_object': 'project'}),
            ('parcel.detail', {'description': "View details of a parcel"}),
            ('parcel.edit',   {'description': "Update existing parcels"}),
            ('parcel.delete', {'description': "Delete parcels"})
        ]

    def get_absolute_url(self):
        return reverse('parcel-detail', kwargs={'pk': self.pk}) class UserPolicyAssignment(models.Model):
    user = models.ForeignKey(User)
    policy = models.ForeignKey(Policy)
    organisation = models.ForeignKey(Organisation, null=True, blank=True)
    project = models.ForeignKey(Project, null=True, blank=True)
    index = models.IntegerField()

    class Meta:
        ordering = ('index',) def set_user_policies(user):
    def do_one(pol_assign):
        vs = dict(
            organisation=(pol_assign.organisation.name
                          if pol_assign.organisation else None),
            project=(pol_assign.project.name
                     if pol_assign.project else None),
        )
        pol = Policy.objects.get(name=pol_assign.policy)
        return (pol, vs) if vs else pol
    pols = [do_one(pa)
            for pa in UserPolicyAssignment.objects.filter(user=user)]
    user.assign_policies(*pols) class Action(SimpleSeparated):
    """Actions are represented by period-separated sequences of elements
    (e.g. ``parcel.edit``, ``admin.assign-role``) with wildcard
    elements indicated by ``*`` (e.g. ``party.*``).  A list of
    *registered* actions is maintained to support permissions set
    queries to find the set of actions that are permitted on a
    specified object pattern.

    """
    separator = '.'

    registered = set()

    def register(action):
        """Action registration is used to support generating lists of
        permitted actions from a permission set and an object pattern.
        Only registered actions will be returned by such queries.

        """
        if isinstance(action, str):
            Action.register(Action(action))
        elif isinstance(action, Action):
            Action.registered.add(action)
        else:
            for a in action:
                Action.register(a) class Policy(models.Model):
    """An individual policy has a name and a JSON policy body.  Changes to
    policies are audited.

    """

    name = models.CharField(max_length=200)
    """Policy name field."""

    body = models.TextField()
    """Policy JSON body."""

    audit_log = AuditLog()

    def __str__(self):
        return self.name

    def variable_names(self):
        pat = re.compile(r'\$(?:([_a-z][_a-z0-9]*)|{([_a-z][_a-z0-9]*)})')
        return set([m[0] for m in re.findall(pat, self.body)])

    def save(self, *args, **kwargs):
        super().save(*args, **kwargs)
        self.refresh()

    def refresh(self):
        for pset in _policy_psets([self]):
            pset.refresh() class UserSwitchForm(forms.Form):
    username = forms.ChoiceField(label='Select user',
                                 choices=user_choices) class UserForm(forms.ModelForm):
    class Meta:
        model = User
        fields = ('username',) class UserPolicyForm(forms.Form):
    MAX_POLICIES = 8

    policy = forms.ModelChoiceField(queryset=Policy.objects.all(),
                                    required=False)
    organisation = forms.ModelChoiceField(
        queryset=Organisation.objects.all(), empty_label='*', required=False
    )
    project = forms.ModelChoiceField(
        queryset=Project.objects.all(), empty_label='*', required=False
    )
import json
import itertools
import re
import django.views.generic as generic
import django.views.generic.edit as edit
import tutelary.mixins
from django.db import transaction
from django.core.urlresolvers import reverse, reverse_lazy
from django.contrib.auth import authenticate, login, logout, get_backends
from django.contrib import messages
from django.forms import ModelForm, ModelChoiceField
from django.shortcuts import redirect, render
from django.http import HttpResponseRedirect
from .models import (
    Organisation, Project, Party, Parcel, UserPolicyAssignment,
    set_user_policies
)
from django.contrib.auth.models import User
from tutelary.engine import Action
from tutelary.models import Policy
from .forms import UserSwitchForm, UserForm, UserPolicyForm
    model = User
    success_url = reverse_lazy('user-list')
    permission_required = 'user.delete'


class SwitchUser(generic.View):
    def post(self, request, *args, **kwargs):
        newuser = authenticate(username=request.POST['username'])
        if newuser is not None:
            login(request, newuser)
        else:
            logout(request)
        return redirect(request.META.get('HTTP_REFERER', '/'))


# ----------------------------------------------------------------------
#
#  POLICIES
#

class PolicyList(ListView):
    model = Policy
    permission_required = 'policy.list'


class PolicyDetail(DetailView):
    model = Policy
    permission_required = 'policy.detail'

    def get_context_data(self, **kwargs):
        context = super(PolicyDetail, self).get_context_data(**kwargs)
        outlines = []
        in_array = False
        accum_line = None
        for line in json.dumps(json.loads(context['object'].body),
                               indent=2, sort_keys=True).splitlines():
            if not in_array:
                if (re.match(r'\s+"action": \[', line) or
                   re.match(r'\s+"object": \[', line)):
                    accum_line = line
                    in_array = True
                else:
                    outlines.append(line)
            else:
                accum_line += ' ' + line.replace(' ', '')
                if re.match(r'\s+],?', line):
                    outlines.append(accum_line)
                    in_array = False
                    accum_line = None
        body = '\n'.join(outlines)
        context['pretty_body'] = body
        return context


class PolicyCreate(CreateView):
    model = Policy
    fields = ('name', 'body')
    permission_required = 'policy.create'

    def get_success_url(self):
        return reverse('policy-detail', kwargs={'pk': self.object.pk})


class PolicyUpdate(UpdateView):
    model = Policy
    fields = ('name', 'body')
    template_name_suffix = '_update_form'
    permission_required = 'policy.edit'

    def get_success_url(self):
        return reverse('policy-detail', kwargs={'pk': self.object.pk})


class PolicyDelete(DeleteView):
    model = Policy
    success_url = reverse_lazy('policy-list')
    permission_required = 'policy.delete'


# ----------------------------------------------------------------------
#
#  ORGANISATIONS
#

class OrganisationList(ListView):
    model = Organisation
    permission_required = 'organisation.list'


class OrganisationCreate(CreateView):
    model = Organisation
    fields = ('name',)
    success_url = reverse_lazy('organisation-list')
    permission_required = {'GET': None, 'POST': 'organisation.create'}


class OrganisationDelete(DeleteView):
    model = Organisation
    success_url = reverse_lazy('organisation-list')
    permission_required = 'organisation.delete'


# ----------------------------------------------------------------------
#
#  PROJECTS
#

class ProjectList(ListView):
    model = Project
    permission_required = 'project.list'


class ProjectForm(ModelForm):
    class Meta:
        model = Project
        fields = ('name', 'organisation')

    def __init__(self, *args, **kwargs):
        super(ProjectForm, self).__init__(*args, **kwargs)
        self.fields['organisation'] = ModelChoiceField(

            queryset=Organisation.objects.all(), empty_label=None