Skip to content

Commit

Permalink
finished rough draft of documentation
Browse files Browse the repository at this point in the history
  • Loading branch information
paltman committed Apr 21, 2011
1 parent 63acb71 commit 88d71a0
Showing 1 changed file with 136 additions and 2 deletions.
138 changes: 136 additions & 2 deletions README.rst
Expand Up @@ -144,18 +144,152 @@ You will need to add and register a privileges handler::
privileges.register(has_privilege)


Delegated Privileges
********************
As you can see above, I added ``has_privilege`` and registered it with ``privileges.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.


Achievement Based Privileges
****************************

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
import privileges
from glue.badges import ProfileCompletionBadge
from personas.models import DefaultPersona
from privileges.models import Privilege
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)
privileges.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.


Privileges in the Template
**************************

In order to assist in validating privileges in the template to control bits of
your UI, there is a template tag called ``check_privilege`` and it is used like
so::

{% load privileges_tags %}
....
{% check_privilege 'foo_feature_enabled' for user as has_foo %}
{% if has_foo %}
....
{% endif %}


Privileges in the View
**********************

While the template tag is good to control bits in the UI, you will likely want
to make sure POST requests can't be forged. Just because you don't show a form
in the UI, doesn't mean there isn't a url accepting POST requests. This is the
reason for the ``privilege_required`` decorator.

By putting this decorator on views, it will validate that the user calling the
view as the specified privilege, otherwise it will redirect, by default, to
the login url::

from privileges.decorators import privilege_required
@privilege_required("widget_management_feature_enabled")
def add_widget(request):
....

0 comments on commit 88d71a0

Please sign in to comment.