Row-Level, URL-based permissions for FlatPages

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
#########################
# models.py
#########################
from django.db import models
from django.contrib.flatpages.models import FlatPage
from django.contrib.auth.models import User

class Permission(models.Model):
    '''
    A mapping of Flatpage URLs to Users. 
    NOTE: for this to work, the user must already have 
    permissions to edit FlatPages.
    '''
    url = models.CharField(max_length=255, \
        help_text='The selected Users will be able to edit all FlatPages \
        that begin with this URL. For example: "/johndoe/"')
    users = models.ManyToManyField(User, related_name="flatpagepermission")

    def __unicode__(self):
        return self.url

    class Meta:
        ordering = ['url', ]

def user_has_flatpage_permission(user, url):
    '''
    A helper function to check to see if the given user has 
    permission to edit the flatpage associated with the given URL.

    user = a django.contrib.auth.models.User object
    url = a URL fragment for a FlatPage. E.g. /about/something/else
    '''
    if user.is_superuser:
        return True

    perms = Permission.objects.filter(users=user)
    for p in perms:
        if url.startswith(p.url):
            return True
    return False

#########################
# admin.py
#########################
from flatpage_addons.models import Permission
from django.contrib import admin

class PermissionAdmin(admin.ModelAdmin):
    list_display = ('url', )

admin.site.register(Permission, PermissionAdmin)

##################################
# templatetags/flatpage_addons_extras.py
##################################
from django import template
from django.template import Variable, VariableDoesNotExist
from django.contrib.auth.models import User
from de_concierge.flatpage_addons.models import user_has_flatpage_permission
from django.contrib.admin.templatetags import admin_list

register = template.Library()

def results(user, cl):
    '''
    Modified from django.contrib.admin.templatetags.admin_list
    Generates a list of items for the Admin's change_list page.
    This function filters out those FlatPage objects that do 
    for which the current user does not have Permission.
    '''
    for res in cl.result_list:
        if user_has_flatpage_permission(user, res.url):
            yield list(admin_list.items_for_result(cl,res))
            
@register.inclusion_tag('admin/change_list_results.html')
def flatpage_result_list(user, cl):
    ''' 
    Based on django.contrib.admin.templatetag.admin_list.result_list;
    An inclusion tag that omits flatpages that the user 
    does not have permission to edit.
    '''
    return {'cl':cl,
            'result_headers':list(admin_list.result_headers(cl)),
            'results': list(results(user, cl))}

class IfHasFlatPagePermissionNode(template.Node):
    ''' 
    Execute code in this block if the given User has permission to
    the given FlatPage URL. 
    '''
    def __init__(self, user, url, nodelist_true, nodelist_false):
        self.user = Variable(user)
        self.url = Variable(url)
        self.nodelist_true = nodelist_true
        self.nodelist_false = nodelist_false

    def __repr__(self):
        return "<IfHasFlatPagePermissionNode>"

    def render(self, context):
        try:
            user_obj = self.user.resolve(context)
            flatpage_url = self.url.resolve(context)

            if user_has_flatpage_permission(user_obj, flatpage_url):
                return self.nodelist_true.render(context)
        except VariableDoesNotExist:
            pass

        return self.nodelist_false.render(context)

def do_ifhasflatpagepermission(parser, token):
    ''' 
    Parser for Template:
        {% ifhasflatpagepermission <user> <url> %} 
            {# execute contents #}
        {% endifhasflatpagepermission %}
    '''
    bits = list(token.split_contents())
    if len(bits) != 3:
        raise template.TemplateSyntaxError, "%r takes 2 arguments: a User object and a URL."%bits[0]
    end_tag = 'end' + bits[0]
    nodelist_true = parser.parse(('else', end_tag))
    token = parser.next_token()
    if token.contents == 'else':
        nodelist_false = parser.parse((end_tag, ))
        parser.delete_first_token()
    else:
        nodelist_false = template.NodeList()
    return IfHasFlatPagePermissionNode(bits[1], bits[2], nodelist_true, nodelist_false)

# Register the new tag
register.tag('ifhasflatpagepermission', do_ifhasflatpagepermission)


##########################################
# Lastly, we override the change_form.html and the
# change_list.html admin templates for the flatpage app:
# /my_project/templates/admin/flatpages/flatpage/
##########################################

##########################################
# change_form.html
##########################################
{% extends "admin/change_form.html" %}
{% load flatpage_addons_extras %}

{% block content %}
    {% ifhasflatpagepermission user original.url %}
        {{ block.super }}
    {% else %}
        <h1> You do not have permission to Edit this page </h1>
    {% endifhasflatpagepermission %}
{% endblock %}

##########################################
# change_list.html
##########################################
{% extends "admin/change_list.html" %}
{% load adminmedia admin_list i18n %}
{% load flatpage_addons_extras %}

{% block result_list %}
    {# {% result_list cl %} #}
    {% flatpage_result_list user cl %}
{% endblock %}

More like this

  1. FieldsetForm by Ciantic 7 years ago
  2. Allow template tags in a Flatpage's content by kylefox 5 years, 9 months ago
  3. Hierarchical Flatpage Tag by 0sn 5 years, 5 months ago
  4. Variable resolving URL template tag by UloPe 5 years, 1 month ago
  5. Default Template Loading by nirvdrum 6 years, 8 months ago

Comments

bartTC (on June 17, 2009):

The admin part looks complicated to me. I guess it's enough to just overwrite the ModelAdmin.queryset method to filter the rows that the user has permission to.

#

bradmontgomery (on July 15, 2009):

bartTC, I'm assuming you meant the admin template part? I really didn't want to touch the flatpage code, so that's why I just override the template (which I'm doing for flatpages anyway). I'm sure this is not the best solution, but it solves my problems :)

#

(Forgotten your password?)