Module to align code with thoughts of users and designers. Also magically handles navigation and permissions.

Overview

This readme will introduce you to Carteblanche and walk you through an example app, please refer to carteblanche-django-starter for the full example project.

python-carteblanche

A menuing system of unlimited power. Holds and serializes the in-memory relationship between urls and objects and users.

Installation

You can obtain the source code for carteblanche from here:

https://github.com/neuman/python-carteblanche

Or install it with pip from the console

pip install carteblanche

Add 'carteblanche' to your django settings INSTALLED_APPS array.

Changes

This version contains significant changes from the original version and substantially breaks the API. The decision to break the original API was not made lightly, but was deemed necesary. The original version was created to see if there was interest in such a tool and was met with TONS of downloads. From now on I will attempt to keep the API as in tact as possible.

Fundamentally carteblanche is designed to make the process of developing an MVC app closer to the proccess of designing one. Designers, product owners and users tend to think of software in terms of:

  • What are the objects
  • What actions are available on those objects
  • Who can perform which actions on which objects at what time

Carteblanche makes it possible to structure your project in a way that directly mirrors that thought process. By breaking your permissions out into reusable verb classes that include permission conditions, it becomes possible to automatically:

  • Dynamically generate navigation appropriate for each user
  • Dynamically allow or block each user's access to specific views
  • Avoid spaghetti code by consistently handing condition variables down from model to view to template

There are three major components in Carteblanche:

  • Verb class
  • Noun mixin
  • NounView mixin

A verb class glues together a view, its named URL, a particular model, and a function that determines if the view is available to the requesting user.

The Noun mixin is intended to be mixed into a model class and along with the attribute 'verb_classes' makes the model aware of what verbs to check availability for.

The NounView mixin is intended to be mixed in with a View class and allows the view to be aware of what noun it represents.

Guided Intro

Your first step is to create a verbs.py file. This is typically done at the same level as your models.py file. This file will contain the conditional permissions for your entire app in once centralized location which makes for very easy adjustments later on when your designer/product owner/user decides they want a change.

Start out by importing the carteblanche basics, and putting together a class that includes some simple info for convenience. The 'condition_name' attribute exists to avoid repeatedly running the same 'is_available' function. If a Verb has a 'condition_name', Carteblanche stores the result of its 'is_available' function temporarily and skips running 'is_available' for any following Verbs with the same 'condition_name' on the Noun being checked. This sounds super complicated, but in practice is achieved by simple inheritance.

from django.core.urlresolvers import reverse
from carteblanche.base import Noun
from carteblanche.mixins import DjangoVerb, availability_login_required

APPNAME = 'core'

class CoreVerb(DjangoVerb):
    app = APPNAME
    condition_name = 'is_public'

Next, add base classes for simple 'is_authenticated' and 'is_not_authenticated' conditions. These may become a part of the next release, but because avoiding colisions in condition names are so critical, it's left up to you to explicitly write your own for now. Inherit from these for any Verbs that should only be available to users who are either logged in or not such as 'SiteJoinVerb' and 'SiteLoginVerb' below.

class AuthenticatedVerb(CoreVerb):
    '''
    abstract class for all verbs only visible to authenticated users
    '''
    condition_name = 'is_authenticated'
    required = True

    def is_available(self, user):
        return user.is_authenticated()


class NotAuthenticatedVerb(CoreVerb):
    '''
    abstract class for all verbs only visible to users who are not authenticated
    '''
    condition_name = 'is_not_authenticated'
    required = True

    def is_available(self, user):
        #only available to non-logged in users
        if user.is_authenticated():
            return False
        return True

class SiteJoinVerb(NotAuthenticatedVerb):
    display_name = "Join Indiepen"
    view_name='user_create'


class SiteLoginVerb(NotAuthenticatedVerb):
    display_name = "Login"
    view_name='user_login'

Lets assume that our app has a model called 'Sprocket' that has a ManyToMany of it's members. Our urls.py file has named urls for:

  • 'sprocket_detail' which should be available to anyone logged in
  • 'sprocket_update' which should be available only to users listed in the Sprocket's members
  • 'sprocket_delete' which should be available only to users listed in the Sprocket's members

You would add the following to our verbs.py file. You can see how easy it is to avoid running the same 'is_available' (by having SprocketUpdateVerb and SprocketUpdateVerb inherit from SprocketeerVerb they share a 'condition_name').

class SprocketDetailVerb(AuthenticatedVerb):
    display_name = "View Sprocket"
    view_name = 'sprocket_detail'

    def get_url(self):
        return reverse(viewname=self.view_name, args=[self.noun.id], current_app=self.app)

class SprocketeerVerb(CoreVerb):
    '''
    abstract class for all verbs available only to a sprocket's sprocketeers
    '''
    denied_message = "You must be one of the sprocket's sprocketeers to upload to this post."
    condition_name = "is_sprocketeer"

    @availability_login_required
    def is_available(self, user):
        return self.noun.is_sprocketeer(user)

    def get_url(self):
        return reverse(viewname=self.view_name, args=[self.noun.id], current_app=self.app)


class SprocketUpdateVerb(SprocketeerVerb):
    display_name = "Update Sprocket"
    view_name = 'sprocket_update'


class SprocketDeleteVerb(SprocketeerVerb):
    display_name = "Delete Sprocket"
    view_name = 'sprocket_delete'

In order to make these Verbs actually work for us, you must link them to a Noun. Make an existing model into a Noun by adding the mixin after models.Model in the inheritance chain, and adding a 'verb_classes' attribute as seen below.

from django.db import models
from django.contrib.auth.models import User
from django.core.urlresolvers import reverse
from carteblanche.base import Noun
from core.verbs import *

class Sprocket(models.Model, Noun):
    sprocketeers = models.ManyToManyField(User)
    title = models.CharField(max_length=300)
    verb_classes = [SprocketDetailVerb, SprocketUpdateVerb, SprocketListVerb]

    def __str__(self):
        return self.title

    def is_sprocketeer(self, user):
        return self.sprocketeers.filter(id=user.id).count() > 0

    def get_absolute_url(self):
        return SprocketDetailVerb(self).get_url()

Now that your model has become a Noun, any views pertaining to it need to become NounViews. Add the NounView mixin before View in the inheritance chain. You must also add a 'get_noun' function that returns the instance of the model this view pertains to. Look how clean these views are!

from django.views.generic.base import TemplateView
from django.views.generic.edit import CreateView, UpdateView
from carteblanche.mixins import NounView
import core.models as cm

class SprocketView(NounView):

    def get_noun(self, **kwargs):
        return cm.Sprocket.objects.get(id=self.kwargs['pk'])


class SprocketDetailView(SprocketView, TemplateView):
    template_name = 'base.html'


class SprocketUpdateView(SprocketView, UpdateView):
    model = cm.Sprocket
    template_name = 'form.html'
    success_url = '/'

    def get_success_url(self):
        return cm.SprocketDetailVerb(self.noun).get_url()

At this point, all of the above views should automatically allow access to users who are members of a given sprocket and deny access to everyone else, but what about those other verbs we defined earlier that don't actually have a Noun? SiteJoinVerb and SiteLoginVerb are actions pertaining to the site itself rather than a particular model, so we'll just create a Noun for the site along with a few more verbs that are available at the siteroot. Add the following to your verbs.py file.

class SprocketCreateVerb(CoreVerb):
    display_name = "Create New Sprocket"
    view_name='sprocket_create'
    condition_name = 'is_authenticated'
    required = True

    @availability_login_required
    def is_available(self, user):
        return True

class SprocketListVerb(AuthenticatedVerb):
    display_name = "List Sprockets"
    view_name = 'sprocket_list'

class SiteRoot(Noun):
    '''
    A convenient hack that lets pages that have no actual noun have verbs and verb-based permissions. 
    '''
    verb_classes = [SiteJoinVerb, SiteLoginVerb, SprocketCreateVerb]

    def __unicode__(self):
        return 'Site Root'

    class Meta:
        abstract = True

Now add the following to your views.py file.

class SiteRootView(NounView):
    def get_noun(self, **kwargs):
        siteroot = cm.SiteRoot()
        return siteroot

class IndexView(SiteRootView, TemplateView):
    template_name = 'index.html'

#this login/user create stuff might be better off in a different app
class UserCreateView(SiteRootView, CreateView):
    model = User
    template_name = 'form.html'
    form_class = cf.RegistrationForm
    success_url = '/'

    def form_valid(self, form):
        user = User.objects.create_user(uuid4().hex, form.cleaned_data['email'], form.cleaned_data['password1'])
        user.first_name = form.cleaned_data['first_name']
        user.last_name = form.cleaned_data['first_name']
        user.save()
        user = authenticate(username=user.username, password=form.cleaned_data['password1'])
        login(self.request, user)
        form.instance = user
        return super(UserCreateView, self).form_valid(form)


class UserLoginView(SiteRootView, FormView):
    template_name = 'form.html'
    form_class = cf.LoginForm
    success_url = '/'

    def form_valid(self, form):
        user = form.user_cache
        login(self.request, user)
        form.instance = user
        return super(UserLoginView, self).form_valid(form)    

class SprocketCreateView(SiteRootView, CreateView):
    model = cm.Sprocket
    template_name = 'form.html'
    form_class = cf.SprocketForm
    success_url = '/'

    def get_success_url(self):
        self.object.sprocketeers.add(self.request.user)
        return cm.SprocketDetailVerb(self.object).get_url()

###Displaying in a Template The NounView mixin automatically includes 'available_verbs', 'conditions' and 'noun' in the cointext it hands to the template renderer. All you have to do to display the dynamically rendered navigation menu is include the following somewhere in your template.

<ul>
  {% for verb in noun.get_available_verbs %}
      <li><a href="{{ verb.url }}">{{ verb.display_name }}</a></li>
  {% endfor %}
</ul>

When view access is denied to a user, Carteblanche uses django's messaging system to display the appropriate Verb's 'denied_message'. You can set 'MESSAGES_TEMPLATE' to a custom template in your settings file. The messages template should include something similar to the following:

{% for message in messages %}
    <div class="alert alert-{{ message.tags }}">{{ message }}</div>
{% endfor %}
You might also like...
A python script to decrypt media files encrypted using the Android application 'Secret Calculator Photo Vault'. Supports brute force of PIN also.

A python script to decrypt media files encrypted using the Android application 'Secret Calculator Photo Vault'. Supports brute force of PIN also.

The refactoring tutorial I wrote for PyConDE 2022. You can also work through the exercises on your own.
The refactoring tutorial I wrote for PyConDE 2022. You can also work through the exercises on your own.

Refactoring 101 planet images by Justin Nichol on opengameart.org CC-BY 3.0 Goal of this Tutorial In this tutorial, you will refactor a space travel t

A Python application that helps users determine their calorie intake, and automatically generates customized weekly meal and workout plans based on metrics computed using their physical parameters

A Python application that helps users determine their calorie intake, and automatically generates customized weekly meal and workout plans based on metrics computed using their physical parameters

Simple plug-and-play installer for users who want to LineageOS from stock firmware, or from another custom ROM.

LineageOS for the Teracube 2e Simple plug-and-play installer for users who want to LineageOS from stock firmware, or from another custom ROM. Dependen

Serverless demo showing users how they can capture (and obfuscate) their Lambda payloads in Datadog APM
Serverless demo showing users how they can capture (and obfuscate) their Lambda payloads in Datadog APM

Serverless-capture-lambda-payload-demo Serverless demo showing users how they can capture (and obfuscate) their Lambda payloads in Datadog APM This wi

Sample python script for monitoring Rocketchat database and get statistics of users.
Sample python script for monitoring Rocketchat database and get statistics of users.

rocketchat-DB-monitoring Sample python script for monitoring Rocketchat database and get statistics of users. 1. Update python: yum check-update && yu

Dicionario-git-github - Dictionary created to help train new users of Git and GitHub applications
Dicionario-git-github - Dictionary created to help train new users of Git and GitHub applications

Dicionário 📕 Dicionário criado com o objetivo de auxiliar no treinamento de nov

Users can read others' travel journeys in addition to being able to upload and delete posts detailing their own experiences

Users can read others' travel journeys in addition to being able to upload and delete posts detailing their own experiences! Posts are organized by country and destination within that country.

tg-nearby Trilateration of nearby Telegram users as described in my corresponding article.

tg-nearby Trilateration of nearby Telegram users as described in my corresponding article. Setup If you want to toy with the code in this repository

Releases(v0.0.3)
Owner
Eric Neuman
Eric Neuman
Data 25 Star Wars Project With Python

Data 25 Star Wars Project Instructions The character data in your MongoDB database has been pulled from https://swapi.tech/. As well as 'people', the

1 Dec 24, 2021
Like Docker, but for Squeak. You know, for kids.

Squeaker Like Docker, but for Smalltalk images. You know, for kids. It's a small program that helps in automated derivation of configured Smalltalk im

Tony Garnock-Jones 14 Sep 11, 2022
Python library to decorate and beautify strings

outputformater Python library to decorate and beautify your standard output 💖 I

Felipe Delestro Matos 259 Dec 13, 2022
MiniJVM is simple java virtual machine written by python language, it can load class file from file system and run it.

MiniJVM MiniJVM是一款使用python编写的简易JVM,能够从本地加载class文件并且执行绝大多数指令。 支持的功能 1.从本地磁盘加载class并解析 2.支持绝大多数指令集的执行 3.支持虚拟机内存分区以及对象的创建 4.支持方法的调用和参数传递 5.支持静态代码块的初始化 不支

keguoyu 60 Apr 01, 2022
Tucan Discord Token Generator - Remastered

TucanGEN-SRC Tucan Discord Token Generator - Remastered Tucan source made better by me. -- idk if it works anymore Includes: hCaptcha Bypass Automatic

Vast 8 Nov 04, 2022
A fluid medium for storing, relating, and surfacing thoughts.

Conceptarium A fluid medium for storing, relating, and surfacing thoughts. Read more... Instructions The conceptarium takes up about 1GB RAM when runn

115 Dec 19, 2022
All you need to understand CRUD and MVP in DRF

Book-Store-API This an API which has been put in place just to make you order for books, upload books with price, image and all, pay and automtically

Oladipo Adesiyan 6 Jul 03, 2022
A Python version of Canvacord

A copy of canvacord made in python! Installation Run any of these commands in terminal: Mac / Linux pip install canvacord Windows python -m pip insta

10 Mar 28, 2022
Paimon is a pixie (or script) who was made for anyone from {EPITECH} who are struggling with the Coding Style.

Paimon Paimon is a pixie (or script) who was made for anyone from {EPITECH} who are struggling with the Coding Style. Her goal is to assist you in you

Lyy 2 Oct 17, 2021
Helps to arrange nodes

Relax brush for nodes, helps to arrange nodes easier.

336 Dec 15, 2022
vFuzzer is a tool developed for fuzzing buffer overflows, For now, It can be used for fuzzing plain vanilla stack based buffer overflows

vFuzzer vFuzzer is a tool developed for fuzzing buffer overflows, For now, It can be used for fuzzing plain vanilla stack based buffer overflows, The

Vedant Bhalgama 5 Nov 12, 2022
Awesome & interesting talks about programming

Programming Talks I watch a lot of talks that I love to share with my friends, fellows and coworkers. As I consider all GitHubbers my friends (oh yeah

Veit Heller 7k Dec 26, 2022
Online-update est un programme python permettant de mettre a jour des dossier et de fichier depuis une adresse web.

Démarrage rapide Online-update est un programme python permettant de mettre a jour des dossier et de fichier depuis une adresse web. Mode préconfiguré

pf4 2 Nov 26, 2021
Sudoku-Solver

Sudoku-Solver This is a personal project, that put all my today knowledges to the test, is a project that im developing alone with a lot of effort and

Carlos Ismael Gitto Bernales 5 Nov 08, 2021
Airflow Operator for running Soda SQL scans

Airflow Operator for running Soda SQL scans

Todd de Quincey 7 Oct 18, 2022
Show Public IP Information In Linux Taskbar

IP Information In Linux Taskbar 📍 How Use IP Script? 🤔 Download ip.py script and save somewhere in your system. Add command applet in your taskbar a

HOP 2 Jan 25, 2022
PyScaffold is a project generator for bootstrapping high quality Python packages

PyScaffold is a project generator for bootstrapping high quality Python packages, ready to be shared on PyPI and installable via pip. It is easy to use and encourages the adoption of the best tools a

PyScaffold 1.7k Jan 03, 2023
Tools for teachers and students using nng (Natural Number Game)

nngtools Usage Place your nngsave.json to the directory in which you want to extract the level files. Place nngmap.json on the same directory. Run nng

Thanos Tsouanas 1 Dec 12, 2021
Simple Python tool to check if there is an Office 365 instance linked to a domain.

o365chk.py Simple Python script to check if there is an Office365 instance linked to a particular domain.

Steven Harris 37 Jan 02, 2023
Drug Discovery App Using Lipinski's Rule-of-Five.

Drug Discovery App A Drug Discovery App Using Lipinski's Rule-of-Five. TAPIWA CHAMBOKO 🚀 About Me I'm a full stack developer experienced in deploying

tapiwa chamboko 3 Nov 08, 2022