.. _create-custom-permisson:

==========================
Create a custom permission
==========================

django-authority allows you to define powerful custom permission. Let's start
again with an example code::

    import authority
    from authority import permissions
    from django.contrib.flatpages.models import Flatpage

    class FlatpagePermission(permissions.BasePermission):
        label = 'flatpage_permission'

    authority.register(Flatpage, FlatpagePermission)

A custom permission is a simple method of the permission class::

    import authority
    from authority import permissions
    from django.contrib.flatpages.models import Flatpage

    class FlatpagePermission(permissions.BasePermission):
        label = 'flatpage_permission'
        checks = ('my_custom_check',)

        def my_custom_check(self, flatpage):
            if(flatpage.url == '/about/'):
                return True
            return False

    authority.register(Flatpage, FlatpagePermission)

Note that we first added the name of your custom permission to the ``checks``
attribute, like in :ref:`create-per-object-permission`::

    checks = ('my_custom_check',)

The permission itself is a simple function that accepts an arbitrary number of
arguments. A permission class should always return a boolean whether the
permission is True or False::

    def my_custom_check(self, flatpage):
        if flatpage.url == '/about/':
            return True
        return False

.. warning:: Although it's possible to return other values than ``True``, for
   example an object which also evluates to True, we highly advise to only
   return booleans.

Custom permissions are not necessary related to a model, you can define simpler
permissions too. For example, return True if it's between 10 and 12 o'clock::

    def datetime_check(self):
        hour = int(datetime.datetime.now().strftime("%H"))
        if hour >= 10 and hour <= 12:
            return True
        return False

But most often you want to combine such permissions checks. The next example
would allow an user to have permission to edit a flatpage only between
8 and 12 o'clock in the morning::

    def morning_flatpage_check(self, flatpage):
        hour = int(datetime.datetime.now().strftime("%H"))
        if hour >= 8 and hour <= 12 and flatpage.url == '/about/':
            return True
        return False

Check custom permissions
========================

The permission check is similar to :ref:`create-basic-permission` and
:ref:`create-per-object-permission`.

.. warning:: Although *per-object* permissions are translated to
   ``<permname>_<modelname>`` this is not the case for custom permissions!
   A custom permission ``my_custom_check`` remains ``my_custom_check``.

In your python code
-------------------
::

    from myapp.permissions import FlatPagePermission
    def my_view(request):
        check = FlatPagePermission(request.user)
        flatpage_object = Flatpage.objects.get(url='/homepage/')
        if check.my_custom_check(flatpage=flatpage_object):
            print "Yay, you can change *this* flatpage!"

Using the view decorator
------------------------
::

    from django.contrib.auth import Flatpage
    from authority.decorators import permission_required_or_403

    @permission_required_or_403('flatpage_permission.my_custom_check',
                                (Flatpage, 'url__iexact', 'url')) # The flatpage_object
    def my_view(request, url):
        # ...

See :ref:`check-decorator` how the decorator works in detail.

In your templates
-----------------
::

    {% ifhasperm "flatpage_permission.my_custom_check" request.user flatpage_object %}
        Yay, you can change *this* flatpage!
    {% else %}
        Nope, sorry. You aren't allowed to change *this* flatpage.
    {% endifhasperm %}

See :ref:`check-templates` how the templatetag works in detail.
