Merge branch 'master' into dbmodule
[mygpo.git] / mygpo / decorators.py
blob2cec28c56d9a586a30d8638403546641fd463a42
1 # -*- coding: utf-8 -*-
3 # gPodder - A media aggregator and podcast client
4 # Copyright (c) 2005-2009 Thomas Perl and the gPodder Team
6 # gPodder is free software; you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation; either version 3 of the License, or
9 # (at your option) any later version.
11 # gPodder is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 # GNU General Public License for more details.
16 # You should have received a copy of the GNU General Public License
17 # along with this program. If not, see <http://www.gnu.org/licenses/>.
20 from functools import wraps
22 from django.http import Http404
23 from django.shortcuts import render
24 from django.http import HttpResponseForbidden, HttpResponseNotAllowed
27 def requires_token(token_name, denied_template=None):
28 """
29 returns a decorator that checks if the security token in the 'token' GET
30 parameter matches the requires token for the resource. The protected
31 resource is indicated by
32 * the username parameter passed to the decorated function
33 * token_name passed to this method
35 The decorated method is returned, if
36 * no token is required for the resource
37 * the token in the 'token' GET parameter matches the required token
39 If the passed token does not match
40 * the denied_template is rendered and returned if given
41 * HttpResponseForbidden is returned, if denied_template is not given
42 """
43 def decorator(fn):
44 @wraps(fn)
45 def tmp(request, username, *args, **kwargs):
47 from mygpo.users.models import User
48 user = User.get_user(username)
49 if not user:
50 raise Http404
52 token = user.get_token(token_name)
53 u_token = request.GET.get('token', '')
55 if token == '' or token == u_token:
56 return fn(request, username, *args, **kwargs)
58 else:
59 if denied_template:
60 return render(request, denied_template, {
61 'other_user': user
64 else:
65 return HttpResponseForbidden()
67 return tmp
68 return decorator
71 def allowed_methods(methods):
72 def decorator(fn):
73 @wraps(fn)
74 def tmp(request, *args, **kwargs):
75 if request.method in methods:
76 return fn(request, *args, **kwargs)
77 else:
78 return HttpResponseNotAllowed(methods)
80 return tmp
82 return decorator
85 def repeat_on_conflict(obj_names=[], reload_f=None):
86 """
87 In case of a CouchDB ResourceConflict, reloads the parameter with the
88 given name and repeats the function call until it succeeds.
89 When calling the function, the parameter that should be reloaded must be
90 given as a keyword-argument
91 """
92 from couchdbkit import ResourceConflict
94 def default_reload(obj):
95 return obj.__class__.get(obj._id)
97 reload_f = reload_f or default_reload
99 def decorator(f):
100 @wraps(f)
101 def tmp(*args, **kwargs):
102 while True:
103 try:
104 return f(*args, **kwargs)
105 break
106 except ResourceConflict:
107 for obj_name in obj_names:
108 obj = kwargs[obj_name]
109 kwargs[obj_name] = reload_f(obj)
111 return tmp
113 return decorator
116 def query_if_required():
117 """ If required, queries some resource before calling the function
119 The decorated method is expected to be bound and its class is
120 expected to have define the methods _needs_query() and _query().
123 def decorator(f):
124 @wraps(f)
125 def wrapper(self, *args, **kwargs):
127 if self._needs_query():
128 self._query()
130 return f(self, *args, **kwargs)
132 return wrapper
133 return decorator