The best way to familiarize yourself with privileges is to walk through some examples. So let’s get started.
You are building a site that has a number of different personas so you decide to model that using idios and end up with something that looks like:
from idios.models import ProfileBase
class Persona(ProfileBase):
name = models.CharField(max_length=50, null=True, blank=True)
class MemberPersona(Persona):
expired = models.BooleanField(default=False)
class StaffPersona(Persona):
pass
You will need to add and register a privileges handler:
from idios.models import ProfileBase
from privileges.models import Privilege
from privileges.registration import registry
class Persona(ProfileBase):
name = models.CharField(max_length=50, null=True, blank=True)
class MemberPersona(Persona):
expired = models.BooleanField(default=False)
class StaffPersona(Persona):
pass
class PersonaPrivilege(models.Model):
persona_type = models.ForeignKey(ContentType)
privilege = models.ForeignKey(Privilege)
class Meta:
verbose_name = "Persona Privilege"
unique_together = ["persona_type", "privilege"]
def __unicode__(self):
return unicode("%s has '%s'" % (self.persona_type, self.privilege.label))
def has_privilege(user, privilege):
"""
Checks each Persona that a user has and it's privileges
"""
if user.is_superuser:
return True
for p in [MemberPersona, StaffPersona]:
for persona in p.objects.filter(user=user):
ct_type = ContentType.objects.get_for_model(persona)
if PersonaPrivilege.objects.filter(
persona_type=ct_type,
privilege__label=privilege
).exists():
return True
return False
registry.register(has_privilege)
As you can see above, I added has_privilege and registered it with registry.register.
The handler that you register can be any callable that takes two parameters, a user object, and a string that matches the label of one of the privilege objects in your database.
Another example of how you might employ the use of privileges in your project is by only giving users that have earned a certain reputation or score depending on your chosen nomenclature. Using another open source app by Eldarion, brabeion, we can hook in the same type of handler.
First a quick setup of braebion. Start an a new app in your project. Let’s call it glue as that’s what it’s doing – gluing parts of different apps together. So in glue/badges.py you will have:
from brabeion.base import Badge, BadgeAwarded
class ProfileCompletionBadge(Badge):
slug = "profile_completion"
levels = [
"Bronze",
"Silver",
"Gold",
]
events = [
"profile_updated",
]
multiple = False
def award(self, **state):
user = state["user"]
profile = user.get_profile()
if profile.name and profile.about and profile.location and profile.website:
return BadgeAwarded(level=3)
elif profile.name and profile.about and profile.location:
return BadgeAwarded(level=2)
elif profile.name and profile.location:
return BadgeAwarded(level=1)
Then in glue/models.py will want to create a model to link the ProfileCompletionBadge with a certain set of privileges. In addition, we write and register the has_privilege handler here as well:
from django.db import models
from django.db.models.signals import post_save
from brabeion import badges
from glue.badges import ProfileCompletionBadge
from personas.models import DefaultPersona
from privileges.models import Privilege
from privileges.registration import registry
BADGE_CHOICES = [
(
"%s:%s" % (ProfileCompletionBadge.slug, x[0]),
"%s - %s" % (ProfileCompletionBadge.slug, x[1])
)
for x in enumerate(ProfileCompletionBadge.levels)
]
class BadgePrivilege(models.Model):
badge = models.CharField(max_length=128, choices=BADGE_CHOICES)
privilege = models.ForeignKey(Privilege)
def has_privilege(user, privilege):
if not hasattr(user, "badges_earned"):
return False
for b in user.badges_earned.all():
badge = "%s:%s" % (b.slug, b.level)
if BadgePrivilege.objects.filter(
badge=badge,
privilege__label__iexact=privilege
).exists():
return True
return False
def handle_saved_persona(sender, instance, created, **kwargs):
badges.possibly_award_badge("profile_updated", user=instance.user)
badges.register(ProfileCompletionBadge)
post_save.connect(handle_saved_persona, sender=DefaultPersona)
registry.register(has_privilege)
As you will notice from the code above, the implementation of the handler is completely different from that of the Persona handler written about previously. Don’t be distracted by the braebion details around badges and whatnot, the important thing to realize is that you, the site developer (or app developer), can control exactly how different privileges are evaluated in contexts that you control.
In addition, this example and the previous example where we attached privileges to personas/profiles, are not mutually exclusive. They can work together. What happens when privileges are checked is that all registered handlers are evaluated until either it either finds one that evaluates to True or gets to the end of all registered handlers, which it then will return False.