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
|
from functools import wraps
from flask import flash, request, render_template, url_for
from flask import redirect as _redirect
from .login import current_user
import datetime
today = datetime.date.today
def _gen_tpl(endpoint):
return endpoint.replace('.', '/') + '.jinja'
def templated(template=None):
"""Marks a view as being rendered by a template. The view then shall
return a dictionary holding the parameters for the template. Ig this
is not the case, the response is returned unchanged. This is needed
to support `redirect` and similar.
The correct template is deducted as:
- when passed nothing: the name of the view
- when passed a string '.bla', the endpoint 'bla' in the current
blueprint
- when passed any other string: this string (VERBATIM!)
Except for the last case, the hierarchy of blueprint and view is taken
as directories in the template directory. And '.jinja' is appended.
If the first argument is a function, this is taken as 'None' to allow:
>>> @templated
... def foo():
... ...
(else it would have to be ``@templated()``).
"""
fun = None
if template is not None and callable(template):
# a function was passed in
fun = template
template = None
def decorator(f):
@wraps(f)
def decorated_function(*args, **kwargs):
if template is None:
template_name = _gen_tpl(request.endpoint)
elif template[0] == '.' and request.blueprint is not None:
template_name = _gen_tpl(request.blueprint + template)
else:
template_name = template
ctx = f(*args, **kwargs)
if ctx is None:
ctx = {}
elif not isinstance(ctx, dict):
return ctx
return render_template(template_name, **ctx)
return decorated_function
if fun is None:
return decorator
else:
return decorator(fun)
def redirect (target, **kwargs):
"""Convenience wrapper for `flask.redirect`. It applies `url_for`
on the target, which also gets passed all arguments.
Special argument '_code' to set the HTTP-Code.
"""
code = kwargs.pop('_code', None)
url = url_for(target, **kwargs)
if code is None:
return _redirect(url)
else:
return _redirect(url, code)
def assert_authorisation(constructor, param):
"""Asserts that the current user has the right to load some specific data.
This is done by using the argument with keyword `param` and pass it
to `constructor`. If the resulting object has an attribute `user_id`,
this is checked to be equal to `current_user.id`.
Usage example::
@route('/job/<int:id>')
@assert_authorisation(Job, 'id')
def show_job(id):
# this is only executed if Job(id).user_id == current_user.id
"""
def decorator(f):
@wraps(f)
def decorated_function(*args, **kwargs):
p = kwargs.get(param, None)
if p is None:
raise TypeError("Keyword %s expected but not received." % param)
obj = constructor(p)
if obj is None:
flash(u"Eintrag existiert nicht!", u'error')
return redirect('index')
if not hasattr(obj, 'user_id'):
return f(*args, **kwargs)
# explicitly use user_id to avoid having to load the user object
if obj.user_id != current_user.id:
flash(u"Nicht erlaubte Operation!", u'error')
return redirect('index')
else:
return f(*args, **kwargs)
return decorated_function
return decorator
|