480f28cce200e33ebb0b0dcd0ca88a0b6b69ac89
[auf_django_permissions.git] / auf / django / permissions / __init__.py
1 # encoding: utf-8
2
3 from collections import defaultdict
4
5
6 class Predicate(object):
7 """
8 Wrapper pour une fonction ``f(user, obj, cls)``.
9
10 Le paramètre ``user`` est l'utilisateur pour lequel la permission est testée.
11
12 Si le prédicat est testé sur un seul objet, cet objet est passé dans
13 le paramètre ``obj`` et le paramètre ``cls`` est ``None``. Inversement,
14 si le prédicat sert à filtrer un queryset, le modèle du queryset est
15 passé dans le paramètre ``cls`` et le paramètre ``obj`` est ``None``.
16
17 La fonction peut retourner un booléen ou un objet ``Q``. Un booléen
18 indique si le test a passé ou pas. Un objet ``Q`` indique les filtres à
19 appliquer pour ne garder que les objets qui passent le test. Si un objet
20 ``Q`` est retourné lors d'un test sur un seul objet, le test retournera
21 un booléen indiquant si l'objet satisfait au filtre.
22
23 Les prédicats peuvent être combinés à l'aide des opérateurs booléens
24 ``&``, ``|`` et ``~``.
25 """
26
27 def __init__(self, func_or_value):
28 """
29 On peut initialiser un prédicat avec une fonction ayant la signature
30 ``f(user, obj, cls)`` ou avec une valeur constante.
31 """
32 if callable(func_or_value):
33 self.func = func_or_value
34 else:
35 self.func = lambda user, obj, cls: func_or_value
36
37 def __call__(self, user, obj=None, cls=None):
38 """
39 Appelle la fonction encapsulée.
40 """
41 return self.func(user, obj, cls)
42
43 def __and__(self, other):
44 def func(user, obj, cls):
45 my_result = self(user, obj, cls)
46 if my_result is False:
47 return False
48 other_result = other(user, obj, cls)
49 if my_result is True:
50 return other_result
51 elif other_result is True:
52 return my_result
53 else:
54 return my_result & other_result
55 return Predicate(func)
56
57 def __or__(self, other):
58 def func(user, obj, cls):
59 my_result = self(user, obj, cls)
60 if my_result is True:
61 return True
62 other_result = other(user, obj, cls)
63 if my_result is False:
64 return other_result
65 elif other_result is False:
66 return my_result
67 else:
68 return my_result | other_result
69 return Predicate(func)
70
71 def __invert__(self):
72 def func(user, obj, cls):
73 result = self(user, obj, cls)
74 if isinstance(result, bool):
75 return not result
76 else:
77 return ~result
78 return Predicate(func)
79
80
81 class Rules(object):
82
83 def __init__(self, allow_default=None, deny_default=None):
84 self.allow_rules = defaultdict(lambda: allow_default or Predicate(False))
85 self.deny_rules = defaultdict(lambda: deny_default or Predicate(False))
86
87 def allow(self, perm, cls, predicate):
88 if not isinstance(predicate, Predicate):
89 raise TypeError("the third argument to allow() must be a Predicate")
90 self.allow_rules[(perm, cls)] |= predicate
91
92 def deny(self, perm, cls, predicate):
93 if not isinstance(predicate, Predicate):
94 raise TypeError("the third argument to deny() must be a Predicate")
95 self.deny_rules[(perm, cls)] |= predicate
96
97 def predicate_for_perm(self, perm, cls):
98 return self.allow_rules[(perm, cls)] & ~self.deny_rules[(perm, cls)]
99
100 def user_has_perm(self, user, perm, obj):
101 result = self.predicate_for_perm(perm, obj.__class__)(user, obj)
102 if isinstance(result, bool):
103 return result
104 else:
105 return obj._default_manager.filter(pk=obj.pk).filter(result).exists()
106
107 def filter_queryset(self, user, perm, queryset):
108 result = self.predicate_for_perm(perm, queryset.model)(user, cls=queryset.model)
109 if result is True:
110 return queryset
111 elif result is False:
112 return queryset.none()
113 else:
114 return queryset.filter(result)
115
116 def clear():
117 self.allow_rules.clear()
118 self.deny_rules.clear()
119
120
121 class AuthenticationBackend(object):
122 supports_anonymous_user = True
123 supports_inactive_user = True
124 supports_object_permissions = True
125 rules = None
126
127 def has_perm(self, user, perm, obj=None):
128 if self.rules is None or obj is None:
129 return False
130 return self.rules.user_has_perm(user, perm, obj)
131
132 def authenticate(self, username=None, password=None):
133 # We don't authenticate
134 return None
135
136 def get_user(self, user_id):
137 # We don't authenticate
138 return None