1 # GNU MediaGoblin -- federated, autonomous media hosting
2 # Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS.
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.
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.
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/>.
17 from functools
import wraps
19 from urlparse
import urljoin
20 from werkzeug
.exceptions
import Forbidden
, NotFound
21 from oauthlib
.oauth1
import ResourceEndpoint
23 from mediagoblin
import mg_globals
as mgg
24 from mediagoblin
import messages
25 from mediagoblin
.db
.models
import MediaEntry
, User
, MediaComment
26 from mediagoblin
.tools
.response
import (
28 render_user_banned
, json_response
)
29 from mediagoblin
.tools
.translate
import pass_to_ugettext
as _
31 from mediagoblin
.oauth
.tools
.request
import decode_authorization_header
32 from mediagoblin
.oauth
.oauth
import GMGRequestValidator
35 def user_not_banned(controller
):
37 Requires that the user has not been banned. Otherwise redirects to the page
38 explaining why they have been banned
41 def wrapper(request
, *args
, **kwargs
):
43 if request
.user
.is_banned():
44 return render_user_banned(request
)
45 return controller(request
, *args
, **kwargs
)
50 def require_active_login(controller
):
52 Require an active login from the user. If the user is banned, redirects to
53 the "You are Banned" page.
57 def new_controller_func(request
, *args
, **kwargs
):
59 not request
.user
.has_privilege(u
'active'):
61 request
, 'mediagoblin.user_pages.user_home',
62 user
=request
.user
.username
)
63 elif not request
.user
or not request
.user
.has_privilege(u
'active'):
65 request
.urlgen('mediagoblin.auth.login',
69 return redirect(request
, 'mediagoblin.auth.login',
72 return controller(request
, *args
, **kwargs
)
74 return new_controller_func
77 def user_has_privilege(privilege_name
):
79 Requires that a user have a particular privilege in order to access a page.
80 In order to require that a user have multiple privileges, use this
81 decorator twice on the same view. This decorator also makes sure that the
82 user is not banned, or else it redirects them to the "You are Banned" page.
84 :param privilege_name A unicode object that is that represents
85 the privilege object. This object is
86 the name of the privilege, as assigned
87 in the Privilege.privilege_name column
90 def user_has_privilege_decorator(controller
):
93 def wrapper(request
, *args
, **kwargs
):
94 user_id
= request
.user
.id
95 if not request
.user
.has_privilege(privilege_name
):
98 return controller(request
, *args
, **kwargs
)
101 return user_has_privilege_decorator
104 def active_user_from_url(controller
):
105 """Retrieve User() from <user> URL pattern and pass in as url_user=...
107 Returns a 404 if no such active user has been found"""
109 def wrapper(request
, *args
, **kwargs
):
110 user
= User
.query
.filter_by(username
=request
.matchdict
['user']).first()
112 return render_404(request
)
114 return controller(request
, *args
, url_user
=user
, **kwargs
)
119 def user_may_delete_media(controller
):
121 Require user ownership of the MediaEntry to delete.
124 def wrapper(request
, *args
, **kwargs
):
125 uploader_id
= kwargs
['media'].uploader
126 if not (request
.user
.has_privilege(u
'admin') or
127 request
.user
.id == uploader_id
):
130 return controller(request
, *args
, **kwargs
)
135 def user_may_alter_collection(controller
):
137 Require user ownership of the Collection to modify.
140 def wrapper(request
, *args
, **kwargs
):
141 creator_id
= request
.db
.User
.query
.filter_by(
142 username
=request
.matchdict
['user']).first().id
143 if not (request
.user
.has_privilege(u
'admin') or
144 request
.user
.id == creator_id
):
147 return controller(request
, *args
, **kwargs
)
152 def uses_pagination(controller
):
154 Check request GET 'page' key for wrong values
157 def wrapper(request
, *args
, **kwargs
):
159 page
= int(request
.GET
.get('page', 1))
161 return render_404(request
)
163 return render_404(request
)
165 return controller(request
, page
=page
, *args
, **kwargs
)
170 def get_user_media_entry(controller
):
172 Pass in a MediaEntry based off of a url component
175 def wrapper(request
, *args
, **kwargs
):
176 user
= User
.query
.filter_by(username
=request
.matchdict
['user']).first()
182 # might not be a slug, might be an id, but whatever
183 media_slug
= request
.matchdict
['media']
185 # if it starts with id: it actually isn't a slug, it's an id.
186 if media_slug
.startswith(u
'id:'):
188 media
= MediaEntry
.query
.filter_by(
189 id=int(media_slug
[3:]),
191 uploader
=user
.id).first()
195 # no magical id: stuff? It's a slug!
196 media
= MediaEntry
.query
.filter_by(
199 uploader
=user
.id).first()
202 # Didn't find anything? Okay, 404.
205 return controller(request
, media
=media
, *args
, **kwargs
)
210 def get_user_collection(controller
):
212 Pass in a Collection based off of a url component
215 def wrapper(request
, *args
, **kwargs
):
216 user
= request
.db
.User
.query
.filter_by(
217 username
=request
.matchdict
['user']).first()
220 return render_404(request
)
222 collection
= request
.db
.Collection
.query
.filter_by(
223 slug
=request
.matchdict
['collection'],
224 creator
=user
.id).first()
226 # Still no collection? Okay, 404.
228 return render_404(request
)
230 return controller(request
, collection
=collection
, *args
, **kwargs
)
235 def get_user_collection_item(controller
):
237 Pass in a CollectionItem based off of a url component
240 def wrapper(request
, *args
, **kwargs
):
241 user
= request
.db
.User
.query
.filter_by(
242 username
=request
.matchdict
['user']).first()
245 return render_404(request
)
247 collection_item
= request
.db
.CollectionItem
.query
.filter_by(
248 id=request
.matchdict
['collection_item']).first()
250 # Still no collection item? Okay, 404.
251 if not collection_item
:
252 return render_404(request
)
254 return controller(request
, collection_item
=collection_item
, *args
, **kwargs
)
259 def get_media_entry_by_id(controller
):
261 Pass in a MediaEntry based off of a url component
264 def wrapper(request
, *args
, **kwargs
):
265 media
= MediaEntry
.query
.filter_by(
266 id=request
.matchdict
['media_id'],
267 state
=u
'processed').first()
268 # Still no media? Okay, 404.
270 return render_404(request
)
272 given_username
= request
.matchdict
.get('user')
273 if given_username
and (given_username
!= media
.get_uploader
.username
):
274 return render_404(request
)
276 return controller(request
, media
=media
, *args
, **kwargs
)
281 def get_workbench(func
):
282 """Decorator, passing in a workbench as kwarg which is cleaned up afterwards"""
285 def new_func(*args
, **kwargs
):
286 with mgg
.workbench_manager
.create() as workbench
:
287 return func(*args
, workbench
=workbench
, **kwargs
)
292 def allow_registration(controller
):
293 """ Decorator for if registration is enabled"""
295 def wrapper(request
, *args
, **kwargs
):
296 if not mgg
.app_config
["allow_registration"]:
297 messages
.add_message(
300 _('Sorry, registration is disabled on this instance.'))
301 return redirect(request
, "index")
303 return controller(request
, *args
, **kwargs
)
307 def allow_reporting(controller
):
308 """ Decorator for if reporting is enabled"""
310 def wrapper(request
, *args
, **kwargs
):
311 if not mgg
.app_config
["allow_reporting"]:
312 messages
.add_message(
315 _('Sorry, reporting is disabled on this instance.'))
316 return redirect(request
, 'index')
318 return controller(request
, *args
, **kwargs
)
322 def get_optional_media_comment_by_id(controller
):
324 Pass in a MediaComment based off of a url component. Because of this decor-
325 -ator's use in filing Media or Comment Reports, it has two valid outcomes.
327 :returns The view function being wrapped with kwarg `comment` set to
328 the MediaComment who's id is in the URL. If there is a
329 comment id in the URL and if it is valid.
330 :returns The view function being wrapped with kwarg `comment` set to
331 None. If there is no comment id in the URL.
332 :returns A 404 Error page, if there is a comment if in the URL and it
336 def wrapper(request
, *args
, **kwargs
):
337 if 'comment' in request
.matchdict
:
338 comment
= MediaComment
.query
.filter_by(
339 id=request
.matchdict
['comment']).first()
342 return render_404(request
)
344 return controller(request
, comment
=comment
, *args
, **kwargs
)
346 return controller(request
, comment
=None, *args
, **kwargs
)
350 def auth_enabled(controller
):
351 """Decorator for if an auth plugin is enabled"""
353 def wrapper(request
, *args
, **kwargs
):
355 messages
.add_message(
358 _('Sorry, authentication is disabled on this instance.'))
359 return redirect(request
, 'index')
361 return controller(request
, *args
, **kwargs
)
365 def require_admin_or_moderator_login(controller
):
367 Require a login from an administrator or a moderator.
370 def new_controller_func(request
, *args
, **kwargs
):
371 if request
.user
and \
372 not request
.user
.has_privilege(u
'admin',u
'moderator'):
375 elif not request
.user
:
377 request
.urlgen('mediagoblin.auth.login',
381 return redirect(request
, 'mediagoblin.auth.login',
384 return controller(request
, *args
, **kwargs
)
386 return new_controller_func
390 def oauth_required(controller
):
391 """ Used to wrap API endpoints where oauth is required """
393 def wrapper(request
, *args
, **kwargs
):
394 data
= request
.headers
395 authorization
= decode_authorization_header(data
)
397 if authorization
== dict():
398 error
= "Missing required parameter."
399 return json_response({"error": error
}, status
=400)
402 request_validator
= GMGRequestValidator()
403 resource_endpoint
= ResourceEndpoint(request_validator
)
404 valid
, request
= resource_endpoint
.validate_protected_resource_request(
406 http_method
=request
.method
,
407 body
=request
.get_data(),
408 headers
=dict(request
.headers
),
412 error
= "Invalid oauth prarameter."
413 return json_response({"error": error
}, status
=400)
415 return controller(request
, *args
, **kwargs
)