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 (redirect
, render_404
,
27 render_user_banned
, json_response
)
28 from mediagoblin
.tools
.translate
import pass_to_ugettext
as _
30 from mediagoblin
.oauth
.tools
.request
import decode_authorization_header
31 from mediagoblin
.oauth
.oauth
import GMGRequestValidator
34 def user_not_banned(controller
):
36 Requires that the user has not been banned. Otherwise redirects to the page
37 explaining why they have been banned
40 def wrapper(request
, *args
, **kwargs
):
42 if request
.user
.is_banned():
43 return render_user_banned(request
)
44 return controller(request
, *args
, **kwargs
)
49 def require_active_login(controller
):
51 Require an active login from the user. If the user is banned, redirects to
52 the "You are Banned" page.
56 def new_controller_func(request
, *args
, **kwargs
):
58 not request
.user
.has_privilege(u
'active'):
60 request
, 'mediagoblin.user_pages.user_home',
61 user
=request
.user
.username
)
62 elif not request
.user
or not request
.user
.has_privilege(u
'active'):
64 request
.urlgen('mediagoblin.auth.login',
68 return redirect(request
, 'mediagoblin.auth.login',
71 return controller(request
, *args
, **kwargs
)
73 return new_controller_func
76 def user_has_privilege(privilege_name
):
78 Requires that a user have a particular privilege in order to access a page.
79 In order to require that a user have multiple privileges, use this
80 decorator twice on the same view. This decorator also makes sure that the
81 user is not banned, or else it redirects them to the "You are Banned" page.
83 :param privilege_name A unicode object that is that represents
84 the privilege object. This object is
85 the name of the privilege, as assigned
86 in the Privilege.privilege_name column
89 def user_has_privilege_decorator(controller
):
92 def wrapper(request
, *args
, **kwargs
):
93 user_id
= request
.user
.id
94 if not request
.user
.has_privilege(privilege_name
):
97 return controller(request
, *args
, **kwargs
)
100 return user_has_privilege_decorator
103 def active_user_from_url(controller
):
104 """Retrieve User() from <user> URL pattern and pass in as url_user=...
106 Returns a 404 if no such active user has been found"""
108 def wrapper(request
, *args
, **kwargs
):
109 user
= User
.query
.filter_by(username
=request
.matchdict
['user']).first()
111 return render_404(request
)
113 return controller(request
, *args
, url_user
=user
, **kwargs
)
118 def user_may_delete_media(controller
):
120 Require user ownership of the MediaEntry to delete.
123 def wrapper(request
, *args
, **kwargs
):
124 uploader_id
= kwargs
['media'].uploader
125 if not (request
.user
.has_privilege(u
'admin') or
126 request
.user
.id == uploader_id
):
129 return controller(request
, *args
, **kwargs
)
134 def user_may_alter_collection(controller
):
136 Require user ownership of the Collection to modify.
139 def wrapper(request
, *args
, **kwargs
):
140 creator_id
= request
.db
.User
.query
.filter_by(
141 username
=request
.matchdict
['user']).first().id
142 if not (request
.user
.has_privilege(u
'admin') or
143 request
.user
.id == creator_id
):
146 return controller(request
, *args
, **kwargs
)
151 def uses_pagination(controller
):
153 Check request GET 'page' key for wrong values
156 def wrapper(request
, *args
, **kwargs
):
158 page
= int(request
.GET
.get('page', 1))
160 return render_404(request
)
162 return render_404(request
)
164 return controller(request
, page
=page
, *args
, **kwargs
)
169 def get_user_media_entry(controller
):
171 Pass in a MediaEntry based off of a url component
174 def wrapper(request
, *args
, **kwargs
):
175 user
= User
.query
.filter_by(username
=request
.matchdict
['user']).first()
181 # might not be a slug, might be an id, but whatever
182 media_slug
= request
.matchdict
['media']
184 # if it starts with id: it actually isn't a slug, it's an id.
185 if media_slug
.startswith(u
'id:'):
187 media
= MediaEntry
.query
.filter_by(
188 id=int(media_slug
[3:]),
190 uploader
=user
.id).first()
194 # no magical id: stuff? It's a slug!
195 media
= MediaEntry
.query
.filter_by(
198 uploader
=user
.id).first()
201 # Didn't find anything? Okay, 404.
204 return controller(request
, media
=media
, *args
, **kwargs
)
209 def get_user_collection(controller
):
211 Pass in a Collection based off of a url component
214 def wrapper(request
, *args
, **kwargs
):
215 user
= request
.db
.User
.query
.filter_by(
216 username
=request
.matchdict
['user']).first()
219 return render_404(request
)
221 collection
= request
.db
.Collection
.query
.filter_by(
222 slug
=request
.matchdict
['collection'],
223 creator
=user
.id).first()
225 # Still no collection? Okay, 404.
227 return render_404(request
)
229 return controller(request
, collection
=collection
, *args
, **kwargs
)
234 def get_user_collection_item(controller
):
236 Pass in a CollectionItem based off of a url component
239 def wrapper(request
, *args
, **kwargs
):
240 user
= request
.db
.User
.query
.filter_by(
241 username
=request
.matchdict
['user']).first()
244 return render_404(request
)
246 collection_item
= request
.db
.CollectionItem
.query
.filter_by(
247 id=request
.matchdict
['collection_item']).first()
249 # Still no collection item? Okay, 404.
250 if not collection_item
:
251 return render_404(request
)
253 return controller(request
, collection_item
=collection_item
, *args
, **kwargs
)
258 def get_media_entry_by_id(controller
):
260 Pass in a MediaEntry based off of a url component
263 def wrapper(request
, *args
, **kwargs
):
264 media
= MediaEntry
.query
.filter_by(
265 id=request
.matchdict
['media_id'],
266 state
=u
'processed').first()
267 # Still no media? Okay, 404.
269 return render_404(request
)
271 given_username
= request
.matchdict
.get('user')
272 if given_username
and (given_username
!= media
.get_uploader
.username
):
273 return render_404(request
)
275 return controller(request
, media
=media
, *args
, **kwargs
)
280 def get_workbench(func
):
281 """Decorator, passing in a workbench as kwarg which is cleaned up afterwards"""
284 def new_func(*args
, **kwargs
):
285 with mgg
.workbench_manager
.create() as workbench
:
286 return func(*args
, workbench
=workbench
, **kwargs
)
291 def allow_registration(controller
):
292 """ Decorator for if registration is enabled"""
294 def wrapper(request
, *args
, **kwargs
):
295 if not mgg
.app_config
["allow_registration"]:
296 messages
.add_message(
299 _('Sorry, registration is disabled on this instance.'))
300 return redirect(request
, "index")
302 return controller(request
, *args
, **kwargs
)
306 def allow_reporting(controller
):
307 """ Decorator for if reporting is enabled"""
309 def wrapper(request
, *args
, **kwargs
):
310 if not mgg
.app_config
["allow_reporting"]:
311 messages
.add_message(
314 _('Sorry, reporting is disabled on this instance.'))
315 return redirect(request
, 'index')
317 return controller(request
, *args
, **kwargs
)
321 def get_optional_media_comment_by_id(controller
):
323 Pass in a MediaComment based off of a url component. Because of this decor-
324 -ator's use in filing Media or Comment Reports, it has two valid outcomes.
326 :returns The view function being wrapped with kwarg `comment` set to
327 the MediaComment who's id is in the URL. If there is a
328 comment id in the URL and if it is valid.
329 :returns The view function being wrapped with kwarg `comment` set to
330 None. If there is no comment id in the URL.
331 :returns A 404 Error page, if there is a comment if in the URL and it
335 def wrapper(request
, *args
, **kwargs
):
336 if 'comment' in request
.matchdict
:
337 comment
= MediaComment
.query
.filter_by(
338 id=request
.matchdict
['comment']).first()
341 return render_404(request
)
343 return controller(request
, comment
=comment
, *args
, **kwargs
)
345 return controller(request
, comment
=None, *args
, **kwargs
)
349 def auth_enabled(controller
):
350 """Decorator for if an auth plugin is enabled"""
352 def wrapper(request
, *args
, **kwargs
):
354 messages
.add_message(
357 _('Sorry, authentication is disabled on this instance.'))
358 return redirect(request
, 'index')
360 return controller(request
, *args
, **kwargs
)
364 def require_admin_or_moderator_login(controller
):
366 Require a login from an administrator or a moderator.
369 def new_controller_func(request
, *args
, **kwargs
):
370 if request
.user
and \
371 not request
.user
.has_privilege(u
'admin',u
'moderator'):
374 elif not request
.user
:
376 request
.urlgen('mediagoblin.auth.login',
380 return redirect(request
, 'mediagoblin.auth.login',
383 return controller(request
, *args
, **kwargs
)
385 return new_controller_func
389 def oauth_required(controller
):
390 """ Used to wrap API endpoints where oauth is required """
392 def wrapper(request
, *args
, **kwargs
):
393 data
= request
.headers
394 authorization
= decode_authorization_header(data
)
396 if authorization
== dict():
397 error
= "Missing required parameter."
398 return json_response({"error": error
}, status
=400)
401 request_validator
= GMGRequestValidator()
402 resource_endpoint
= ResourceEndpoint(request_validator
)
403 valid
, request
= resource_endpoint
.validate_protected_resource_request(
405 http_method
=request
.method
,
406 body
=request
.get_data(),
407 headers
=dict(request
.headers
),
411 error
= "Invalid oauth prarameter."
412 return json_response({"error": error
}, status
=400)
414 return controller(request
, *args
, **kwargs
)