1
|
|
|
# coding=utf-8 |
2
|
|
|
""" |
3
|
|
|
permission_required decorator for generic function view |
4
|
|
|
""" |
5
|
|
|
import copy |
6
|
|
|
from functools import wraps |
7
|
|
|
from django.shortcuts import get_object_or_404 |
8
|
|
|
from django.utils.decorators import available_attrs |
9
|
|
|
from django.core.exceptions import PermissionDenied |
10
|
|
|
from permission.decorators.utils import redirect_to_login |
11
|
|
|
|
12
|
|
|
|
13
|
|
|
def permission_required(perm, queryset=None, |
14
|
|
|
login_url=None, raise_exception=False): |
15
|
|
|
""" |
16
|
|
|
Permission check decorator for function-base generic view |
17
|
|
|
|
18
|
|
|
This decorator works as function decorator |
19
|
|
|
|
20
|
|
|
Parameters |
21
|
|
|
---------- |
22
|
|
|
perm : string |
23
|
|
|
A permission string |
24
|
|
|
queryset_or_model : queryset or model |
25
|
|
|
A queryset or model for finding object. |
26
|
|
|
With classbased generic view, ``None`` for using view default queryset. |
27
|
|
|
When the view does not define ``get_queryset``, ``queryset``, |
28
|
|
|
``get_object``, or ``object`` then ``obj=None`` is used to check |
29
|
|
|
permission. |
30
|
|
|
With functional generic view, ``None`` for using passed queryset. |
31
|
|
|
When non queryset was passed then ``obj=None`` is used to check |
32
|
|
|
permission. |
33
|
|
|
|
34
|
|
|
Examples |
35
|
|
|
-------- |
36
|
|
|
>>> @permission_required('auth.change_user') |
37
|
|
|
>>> def update_auth_user(request, *args, **kwargs): |
38
|
|
|
... pass |
39
|
|
|
""" |
40
|
|
|
def wrapper(view_func): |
41
|
|
|
@wraps(view_func, assigned=available_attrs(view_func)) |
42
|
|
|
def inner(request, *args, **kwargs): |
43
|
|
|
_kwargs = copy.copy(kwargs) |
44
|
|
|
# overwrite queryset if specified |
45
|
|
|
if queryset: |
46
|
|
|
_kwargs['queryset'] = queryset |
47
|
|
|
|
48
|
|
|
# get object from view |
49
|
|
|
if 'date_field' in _kwargs: |
50
|
|
|
fn = get_object_from_date_based_view |
51
|
|
|
else: |
52
|
|
|
fn = get_object_from_list_detail_view |
53
|
|
|
if fn.validate(request, *args, **_kwargs): |
54
|
|
|
obj = fn(request, *args, **_kwargs) |
55
|
|
|
else: |
56
|
|
|
# required arguments is not passed |
57
|
|
|
obj = None |
58
|
|
|
|
59
|
|
|
if not request.user.has_perm(perm, obj=obj): |
60
|
|
|
if raise_exception: |
61
|
|
|
raise PermissionDenied |
62
|
|
|
else: |
63
|
|
|
return redirect_to_login(request, login_url) |
64
|
|
|
return view_func(request, *args, **_kwargs) |
65
|
|
|
return inner |
66
|
|
|
return wrapper |
67
|
|
|
|
68
|
|
|
|
69
|
|
|
def get_object_from_list_detail_view(request, *args, **kwargs): |
70
|
|
|
""" |
71
|
|
|
Get object from generic list_detail.detail view |
72
|
|
|
|
73
|
|
|
Parameters |
74
|
|
|
---------- |
75
|
|
|
request : instance |
76
|
|
|
An instance of HttpRequest |
77
|
|
|
|
78
|
|
|
Returns |
79
|
|
|
------- |
80
|
|
|
instance |
81
|
|
|
An instance of model object or None |
82
|
|
|
""" |
83
|
|
|
queryset = kwargs['queryset'] |
84
|
|
|
object_id = kwargs.get('object_id', None) |
85
|
|
|
slug = kwargs.get('slug', None) |
86
|
|
|
slug_field = kwargs.get('slug_field', 'slug') |
87
|
|
|
if object_id: |
88
|
|
|
obj = get_object_or_404(queryset, pk=object_id) |
89
|
|
|
elif slug and slug_field: |
90
|
|
|
obj = get_object_or_404(queryset, **{slug_field: slug}) |
91
|
|
|
else: |
92
|
|
|
raise AttributeError( |
93
|
|
|
"Generic detail view must be called with either an " |
94
|
|
|
"object_id or a slug/slug_field." |
95
|
|
|
) |
96
|
|
|
return obj |
97
|
|
|
def _get_object_from_list_detail_view_validation(request, *args, **kwargs): |
98
|
|
|
if 'queryset' not in kwargs: |
99
|
|
|
return False |
100
|
|
|
elif 'object_id' not in kwargs and 'slug' not in kwargs: |
101
|
|
|
return False |
102
|
|
|
return True |
103
|
|
|
get_object_from_list_detail_view.validate = \ |
104
|
|
|
_get_object_from_list_detail_view_validation |
105
|
|
|
|
106
|
|
|
|
107
|
|
|
def get_object_from_date_based_view(request, *args, **kwargs): # noqa |
108
|
|
|
""" |
109
|
|
|
Get object from generic date_based.detail view |
110
|
|
|
|
111
|
|
|
Parameters |
112
|
|
|
---------- |
113
|
|
|
request : instance |
114
|
|
|
An instance of HttpRequest |
115
|
|
|
|
116
|
|
|
Returns |
117
|
|
|
------- |
118
|
|
|
instance |
119
|
|
|
An instance of model object or None |
120
|
|
|
""" |
121
|
|
|
import time |
122
|
|
|
import datetime |
123
|
|
|
from django.http import Http404 |
124
|
|
|
from django.db.models.fields import DateTimeField |
125
|
|
|
try: |
126
|
|
|
from django.utils import timezone |
127
|
|
|
datetime_now = timezone.now |
128
|
|
|
except ImportError: |
129
|
|
|
datetime_now = datetime.datetime.now |
130
|
|
|
year, month, day = kwargs['year'], kwargs['month'], kwargs['day'] |
131
|
|
|
month_format = kwargs.get('month_format', '%b') |
132
|
|
|
day_format = kwargs.get('day_format', '%d') |
133
|
|
|
date_field = kwargs['date_field'] |
134
|
|
|
queryset = kwargs['queryset'] |
135
|
|
|
object_id = kwargs.get('object_id', None) |
136
|
|
|
slug = kwargs.get('slug', None) |
137
|
|
|
slug_field = kwargs.get('slug_field', 'slug') |
138
|
|
|
|
139
|
|
|
try: |
140
|
|
|
tt = time.strptime( |
141
|
|
|
'%s-%s-%s' % (year, month, day), |
142
|
|
|
'%s-%s-%s' % ('%Y', month_format, day_format) |
143
|
|
|
) |
144
|
|
|
date = datetime.date(*tt[:3]) |
145
|
|
|
except ValueError: |
146
|
|
|
raise Http404 |
147
|
|
|
|
148
|
|
|
model = queryset.model |
149
|
|
|
|
150
|
|
|
if isinstance(model._meta.get_field(date_field), DateTimeField): |
151
|
|
|
lookup_kwargs = { |
152
|
|
|
'%s__range' % date_field: ( |
153
|
|
|
datetime.datetime.combine(date, datetime.time.min), |
154
|
|
|
datetime.datetime.combine(date, datetime.time.max), |
155
|
|
|
)} |
156
|
|
|
else: |
157
|
|
|
lookup_kwargs = {date_field: date} |
158
|
|
|
|
159
|
|
|
now = datetime_now() |
160
|
|
|
if date >= now.date() and not kwargs.get('allow_future', False): |
161
|
|
|
lookup_kwargs['%s__lte' % date_field] = now |
162
|
|
|
if object_id: |
163
|
|
|
lookup_kwargs['pk'] = object_id |
164
|
|
|
elif slug and slug_field: |
165
|
|
|
lookup_kwargs['%s__exact' % slug_field] = slug |
166
|
|
|
else: |
167
|
|
|
raise AttributeError( |
168
|
|
|
"Generic detail view must be called with either an " |
169
|
|
|
"object_id or a slug/slug_field." |
170
|
|
|
) |
171
|
|
|
return get_object_or_404(queryset, **lookup_kwargs) |
172
|
|
|
def _get_object_from_date_based_view_validation(request, *args, **kwargs): |
173
|
|
|
if 'queryset' not in kwargs: |
174
|
|
|
return False |
175
|
|
|
elif 'year' not in kwargs or 'month' not in kwargs or 'day' not in kwargs: |
176
|
|
|
return False |
177
|
|
|
elif 'object_id' not in kwargs and 'slug' not in kwargs: |
178
|
|
|
return False |
179
|
|
|
return True |
180
|
|
|
get_object_from_date_based_view.validate = \ |
181
|
|
|
_get_object_from_date_based_view_validation |
182
|
|
|
|