Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
path: root/Pootle-2.0.0/local_apps/pootle_app/models/permissions.py
blob: bcb3c9cbe36750b84fb064156587716665fb175d (plain)
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
167
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# 
# Copyright 2008 Zuza Software Foundation
# 
# This file is part of translate.
#
# translate is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
# 
# translate is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with translate; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

from django.db import models
from django.contrib.auth.models import Permission
from django.contrib.contenttypes.models import ContentType
from django.db.models.signals           import pre_delete, post_save

from pootle_app.lib.util import RelatedManager
from pootle_app.models.directory import Directory

def get_pootle_permission(codename):
    # The content type of our permission
    content_type = ContentType.objects.get(name='pootle', app_label='pootle_app')
    # Get the pootle view permission
    return Permission.objects.get(content_type=content_type, codename=codename)

def get_pootle_permissions(codenames=None):
    """gets the available rights and their localized names"""
    # l10n: Verb
    content_type = ContentType.objects.get(name='pootle', app_label='pootle_app')
    if codenames is not None:
        permissions = Permission.objects.filter(content_type=content_type, codename__in=codenames)
    else:
        permissions = Permission.objects.filter(content_type=content_type)
    return dict((permission.codename, permission) for permission in permissions)

def get_permission_set_by_username(username, directory):
    try:
        return PermissionSet.objects.get(profile__user__username=username, directory=directory)
    except PermissionSet.DoesNotExist:
        pass
    try:
        return PermissionSet.objects.get(profile__user__username='default', directory=directory)
    except PermissionSet.DoesNotExist:
        return None

def get_matching_permission_set(profile, directory):
    if profile.user.is_authenticated():
        try:
            return PermissionSet.objects.get(profile=profile, directory=directory)
        except PermissionSet.DoesNotExist:
            return get_permission_set_by_username('default', directory)
    else:
        return get_permission_set_by_username('nobody', directory)

def get_matching_permissions_recurse(profile, directory):
    """Build a (permission codename -> permission) dictionary which
    reflects the permissions that the PootleProfile 'profile' has in
    the directory 'directory'. This is done by taking the permissions
    associated with 'profile' in all parent directories into account.

    Recurse from 'directory' all the way up to the root directory.
    Once we hit the root, find a PermissionSet which matches the
    supplied PootleProfile 'profile' and Directory 'directory'. Add
    the positive permissions from this PermissionSet to the dictionary
    which we are building and use the negative permissions associated
    with the root directory to remove permissions from the permissions
    dictionary.
    
    Once this has been done for the root directory, we recurse one
    level up and do the same to the child directory and so on until we
    reach the directory from which we started this process. By that
    point we'll have a permissions dictionary reflecting the
    permissions that 'profile' has in 'directory'."""
    if directory.parent is not None:
        permissions = get_matching_permissions(profile, directory.parent)
    else:
        permissions = {}

    permission_set = get_matching_permission_set(profile, directory)
    if permission_set is not None:
        permissions.update((permission.codename, permission)
                           for permission in permission_set.positive_permissions.all())
        for permission in permission_set.negative_permissions.all():
            if permission.codename in permissions:
                del permissions[permission.codename]
    return permissions

def get_matching_permissions(profile, directory):
    try:
        cached_permission_set = PermissionSetCache.objects.get(profile=profile, directory=directory)
        return dict((permission.codename, permission) for permission in cached_permission_set.permissions.all())
    except PermissionSetCache.DoesNotExist:
        permissions = get_matching_permissions_recurse(profile, directory)
        # Ensure that administrative superusers always get admin rights
        if profile.user.is_superuser and 'administrate' not in permissions:
            permissions['administrate'] = get_pootle_permission('administrate')
        cached_permission_set = PermissionSetCache(profile=profile, directory=directory)
        cached_permission_set.save()
        cached_permission_set.permissions = permissions.values()
        cached_permission_set.save()
        return permissions


def check_profile_permission(profile, permission_codename, directory):
    """it checks if current user has the permission the perform C{permission_codename}"""
    if profile.user.is_superuser:
        return True
    permissions = get_matching_permissions(profile, directory)
    return permission_codename in permissions

def check_permission(permission_codename, request):
    """it checks if current user has the permission the perform C{permission_codename}"""
    if request.user.is_superuser:
        return True
    return permission_codename in request.permissions

class PermissionSet(models.Model):
    objects = RelatedManager()
    class Meta:
        unique_together = ('profile', 'directory')
        app_label = "pootle_app"

    profile                = models.ForeignKey('pootle_app.PootleProfile', db_index=True)
    directory              = models.ForeignKey(Directory, db_index=True, related_name='permission_sets')
    positive_permissions   = models.ManyToManyField(Permission, db_index=True, related_name='permission_sets_positive')
    negative_permissions   = models.ManyToManyField(Permission, db_index=True, related_name='permission_sets_negative')

class PermissionSetCache(models.Model):
    objects = RelatedManager()
    class Meta:
        unique_together = ('profile', 'directory')
        app_label = "pootle_app"
        

    profile                = models.ForeignKey('pootle_app.PootleProfile', db_index=True)
    directory              = models.ForeignKey(Directory, db_index=True, related_name='permission_set_caches')
    permissions            = models.ManyToManyField(Permission, related_name='cached_permissions', db_index=True)


def nuke_permission_set_caches(profile, directory):
    """Delete all PermissionSetCache objects matching the current
    profile and whose directories are subdirectories of directory."""
    for permission_set_cache in PermissionSetCache.objects.filter(profile=profile, directory__pootle_path__startswith=directory.pootle_path):
        permission_set_cache.delete()

def void_cached_permissions(sender, instance, **kwargs):
    if instance.profile.user.username == 'default':
        profile_to_permission_set = dict((permission_set.profile, permission_set) for permission_set
                                            in PermissionSet.objects.filter(directory=instance.directory))
        for permission_set_cache in PermissionSetCache.objects.filter(directory=instance.directory):
            if permission_set_cache.profile not in profile_to_permission_set:
                nuke_permission_set_caches(permission_set_cache.profile, instance.directory)
    else:
        nuke_permission_set_caches(instance.profile, instance.directory)

post_save.connect(void_cached_permissions, sender=PermissionSet)
pre_delete.connect(void_cached_permissions, sender=PermissionSet)