Only log output and write progress to db if it has changed
[mediagoblin.git] / mediagoblin / decorators.py
1 # GNU MediaGoblin -- federated, autonomous media hosting
2 # Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS.
3 #
4 # This program is free software: you can redistribute it and/or modify
5 # it under the terms of the GNU Affero General Public License as published by
6 # the Free Software Foundation, either version 3 of the License, or
7 # (at your option) any later version.
8 #
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU Affero General Public License for more details.
13 #
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16
17 from functools import wraps
18
19 from urlparse import urljoin
20 from urllib import urlencode
21
22 from webob import exc
23
24 from mediagoblin.db.util import ObjectId, InvalidId
25 from mediagoblin.db.sql.models import User
26 from mediagoblin.tools.response import redirect, render_404
27
28
29 def require_active_login(controller):
30 """
31 Require an active login from the user.
32 """
33 @wraps(controller)
34 def new_controller_func(request, *args, **kwargs):
35 if request.user and \
36 request.user.get('status') == u'needs_email_verification':
37 return redirect(
38 request, 'mediagoblin.user_pages.user_home',
39 user=request.user.username)
40 elif not request.user or request.user.get('status') != u'active':
41 next_url = urljoin(
42 request.urlgen('mediagoblin.auth.login',
43 qualified=True),
44 request.url)
45
46 return exc.HTTPFound(
47 location='?'.join([
48 request.urlgen('mediagoblin.auth.login'),
49 urlencode({
50 'next': next_url})]))
51
52 return controller(request, *args, **kwargs)
53
54 return new_controller_func
55
56 def active_user_from_url(controller):
57 """Retrieve User() from <user> URL pattern and pass in as url_user=...
58
59 Returns a 404 if no such active user has been found"""
60 @wraps(controller)
61 def wrapper(request, *args, **kwargs):
62 user = User.query.filter_by(username=request.matchdict['user']).first()
63 if user is None:
64 return render_404(request)
65
66 return controller(request, *args, url_user=user, **kwargs)
67
68 return wrapper
69
70
71 def user_may_delete_media(controller):
72 """
73 Require user ownership of the MediaEntry to delete.
74 """
75 @wraps(controller)
76 def wrapper(request, *args, **kwargs):
77 uploader_id = request.db.MediaEntry.find_one(
78 {'_id': ObjectId(request.matchdict['media'])}).uploader
79 if not (request.user.is_admin or
80 request.user._id == uploader_id):
81 return exc.HTTPForbidden()
82
83 return controller(request, *args, **kwargs)
84
85 return wrapper
86
87
88 def user_may_alter_collection(controller):
89 """
90 Require user ownership of the Collection to modify.
91 """
92 @wraps(controller)
93 def wrapper(request, *args, **kwargs):
94 creator_id = request.db.User.find_one(
95 {'username': request.matchdict['user']}).id
96 if not (request.user.is_admin or
97 request.user._id == creator_id):
98 return exc.HTTPForbidden()
99
100 return controller(request, *args, **kwargs)
101
102 return wrapper
103
104
105 def uses_pagination(controller):
106 """
107 Check request GET 'page' key for wrong values
108 """
109 @wraps(controller)
110 def wrapper(request, *args, **kwargs):
111 try:
112 page = int(request.GET.get('page', 1))
113 if page < 0:
114 return render_404(request)
115 except ValueError:
116 return render_404(request)
117
118 return controller(request, page=page, *args, **kwargs)
119
120 return wrapper
121
122
123 def get_user_media_entry(controller):
124 """
125 Pass in a MediaEntry based off of a url component
126 """
127 @wraps(controller)
128 def wrapper(request, *args, **kwargs):
129 user = request.db.User.find_one(
130 {'username': request.matchdict['user']})
131
132 if not user:
133 return render_404(request)
134 media = request.db.MediaEntry.find_one(
135 {'slug': request.matchdict['media'],
136 'state': u'processed',
137 'uploader': user._id})
138
139 # no media via slug? Grab it via ObjectId
140 if not media:
141 try:
142 media = request.db.MediaEntry.find_one(
143 {'_id': ObjectId(request.matchdict['media']),
144 'state': u'processed',
145 'uploader': user._id})
146 except InvalidId:
147 return render_404(request)
148
149 # Still no media? Okay, 404.
150 if not media:
151 return render_404(request)
152
153 return controller(request, media=media, *args, **kwargs)
154
155 return wrapper
156
157
158 def get_user_collection(controller):
159 """
160 Pass in a Collection based off of a url component
161 """
162 @wraps(controller)
163 def wrapper(request, *args, **kwargs):
164 user = request.db.User.find_one(
165 {'username': request.matchdict['user']})
166
167 if not user:
168 return render_404(request)
169
170 collection = request.db.Collection.find_one(
171 {'slug': request.matchdict['collection'],
172 'creator': user._id})
173
174 # Still no collection? Okay, 404.
175 if not collection:
176 return render_404(request)
177
178 return controller(request, collection=collection, *args, **kwargs)
179
180 return wrapper
181
182
183 def get_user_collection_item(controller):
184 """
185 Pass in a CollectionItem based off of a url component
186 """
187 @wraps(controller)
188 def wrapper(request, *args, **kwargs):
189 user = request.db.User.find_one(
190 {'username': request.matchdict['user']})
191
192 if not user:
193 return render_404(request)
194
195 collection = request.db.Collection.find_one(
196 {'slug': request.matchdict['collection'],
197 'creator': user._id})
198
199 collection_item = request.db.CollectionItem.find_one(
200 {'_id': request.matchdict['collection_item'] })
201
202 # Still no collection item? Okay, 404.
203 if not collection_item:
204 return render_404(request)
205
206 return controller(request, collection_item=collection_item, *args, **kwargs)
207
208 return wrapper
209
210
211 def get_media_entry_by_id(controller):
212 """
213 Pass in a MediaEntry based off of a url component
214 """
215 @wraps(controller)
216 def wrapper(request, *args, **kwargs):
217 try:
218 media = request.db.MediaEntry.find_one(
219 {'_id': ObjectId(request.matchdict['media']),
220 'state': u'processed'})
221 except InvalidId:
222 return render_404(request)
223
224 # Still no media? Okay, 404.
225 if not media:
226 return render_404(request)
227
228 return controller(request, media=media, *args, **kwargs)
229
230 return wrapper