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 werkzeug
.exceptions
import Forbidden
, NotFound
20 from oauthlib
.oauth1
import ResourceEndpoint
22 from six
.moves
.urllib
.parse
import urljoin
24 from mediagoblin
import mg_globals
as mgg
25 from mediagoblin
import messages
26 from mediagoblin
.db
.models
import MediaEntry
, User
, MediaComment
27 from mediagoblin
.tools
.response
import (
29 render_user_banned
, json_response
)
30 from mediagoblin
.tools
.translate
import pass_to_ugettext
as _
32 from mediagoblin
.oauth
.tools
.request
import decode_authorization_header
33 from mediagoblin
.oauth
.oauth
import GMGRequestValidator
36 def user_not_banned(controller
):
38 Requires that the user has not been banned. Otherwise redirects to the page
39 explaining why they have been banned
42 def wrapper(request
, *args
, **kwargs
):
44 if request
.user
.is_banned():
45 return render_user_banned(request
)
46 return controller(request
, *args
, **kwargs
)
51 def require_active_login(controller
):
53 Require an active login from the user. If the user is banned, redirects to
54 the "You are Banned" page.
58 def new_controller_func(request
, *args
, **kwargs
):
60 not request
.user
.has_privilege(u
'active'):
62 request
, 'mediagoblin.user_pages.user_home',
63 user
=request
.user
.username
)
64 elif not request
.user
or not request
.user
.has_privilege(u
'active'):
66 request
.urlgen('mediagoblin.auth.login',
70 return redirect(request
, 'mediagoblin.auth.login',
73 return controller(request
, *args
, **kwargs
)
75 return new_controller_func
78 def user_has_privilege(privilege_name
):
80 Requires that a user have a particular privilege in order to access a page.
81 In order to require that a user have multiple privileges, use this
82 decorator twice on the same view. This decorator also makes sure that the
83 user is not banned, or else it redirects them to the "You are Banned" page.
85 :param privilege_name A unicode object that is that represents
86 the privilege object. This object is
87 the name of the privilege, as assigned
88 in the Privilege.privilege_name column
91 def user_has_privilege_decorator(controller
):
94 def wrapper(request
, *args
, **kwargs
):
95 user_id
= request
.user
.id
96 if not request
.user
.has_privilege(privilege_name
):
99 return controller(request
, *args
, **kwargs
)
102 return user_has_privilege_decorator
105 def active_user_from_url(controller
):
106 """Retrieve User() from <user> URL pattern and pass in as url_user=...
108 Returns a 404 if no such active user has been found"""
110 def wrapper(request
, *args
, **kwargs
):
111 user
= User
.query
.filter_by(username
=request
.matchdict
['user']).first()
113 return render_404(request
)
115 return controller(request
, *args
, url_user
=user
, **kwargs
)
120 def user_may_delete_media(controller
):
122 Require user ownership of the MediaEntry to delete.
125 def wrapper(request
, *args
, **kwargs
):
126 uploader_id
= kwargs
['media'].uploader
127 if not (request
.user
.has_privilege(u
'admin') or
128 request
.user
.id == uploader_id
):
131 return controller(request
, *args
, **kwargs
)
136 def user_may_alter_collection(controller
):
138 Require user ownership of the Collection to modify.
141 def wrapper(request
, *args
, **kwargs
):
142 creator_id
= request
.db
.User
.query
.filter_by(
143 username
=request
.matchdict
['user']).first().id
144 if not (request
.user
.has_privilege(u
'admin') or
145 request
.user
.id == creator_id
):
148 return controller(request
, *args
, **kwargs
)
153 def uses_pagination(controller
):
155 Check request GET 'page' key for wrong values
158 def wrapper(request
, *args
, **kwargs
):
160 page
= int(request
.GET
.get('page', 1))
162 return render_404(request
)
164 return render_404(request
)
166 return controller(request
, page
=page
, *args
, **kwargs
)
171 def get_user_media_entry(controller
):
173 Pass in a MediaEntry based off of a url component
176 def wrapper(request
, *args
, **kwargs
):
177 user
= User
.query
.filter_by(username
=request
.matchdict
['user']).first()
183 # might not be a slug, might be an id, but whatever
184 media_slug
= request
.matchdict
['media']
186 # if it starts with id: it actually isn't a slug, it's an id.
187 if media_slug
.startswith(u
'id:'):
189 media
= MediaEntry
.query
.filter_by(
190 id=int(media_slug
[3:]),
192 uploader
=user
.id).first()
196 # no magical id: stuff? It's a slug!
197 media
= MediaEntry
.query
.filter_by(
200 uploader
=user
.id).first()
203 # Didn't find anything? Okay, 404.
206 return controller(request
, media
=media
, *args
, **kwargs
)
211 def get_user_collection(controller
):
213 Pass in a Collection based off of a url component
216 def wrapper(request
, *args
, **kwargs
):
217 user
= request
.db
.User
.query
.filter_by(
218 username
=request
.matchdict
['user']).first()
221 return render_404(request
)
223 collection
= request
.db
.Collection
.query
.filter_by(
224 slug
=request
.matchdict
['collection'],
225 creator
=user
.id).first()
227 # Still no collection? Okay, 404.
229 return render_404(request
)
231 return controller(request
, collection
=collection
, *args
, **kwargs
)
236 def get_user_collection_item(controller
):
238 Pass in a CollectionItem based off of a url component
241 def wrapper(request
, *args
, **kwargs
):
242 user
= request
.db
.User
.query
.filter_by(
243 username
=request
.matchdict
['user']).first()
246 return render_404(request
)
248 collection_item
= request
.db
.CollectionItem
.query
.filter_by(
249 id=request
.matchdict
['collection_item']).first()
251 # Still no collection item? Okay, 404.
252 if not collection_item
:
253 return render_404(request
)
255 return controller(request
, collection_item
=collection_item
, *args
, **kwargs
)
260 def get_media_entry_by_id(controller
):
262 Pass in a MediaEntry based off of a url component
265 def wrapper(request
, *args
, **kwargs
):
266 media
= MediaEntry
.query
.filter_by(
267 id=request
.matchdict
['media_id'],
268 state
=u
'processed').first()
269 # Still no media? Okay, 404.
271 return render_404(request
)
273 given_username
= request
.matchdict
.get('user')
274 if given_username
and (given_username
!= media
.get_uploader
.username
):
275 return render_404(request
)
277 return controller(request
, media
=media
, *args
, **kwargs
)
282 def get_workbench(func
):
283 """Decorator, passing in a workbench as kwarg which is cleaned up afterwards"""
286 def new_func(*args
, **kwargs
):
287 with mgg
.workbench_manager
.create() as workbench
:
288 return func(*args
, workbench
=workbench
, **kwargs
)
293 def allow_registration(controller
):
294 """ Decorator for if registration is enabled"""
296 def wrapper(request
, *args
, **kwargs
):
297 if not mgg
.app_config
["allow_registration"]:
298 messages
.add_message(
301 _('Sorry, registration is disabled on this instance.'))
302 return redirect(request
, "index")
304 return controller(request
, *args
, **kwargs
)
308 def allow_reporting(controller
):
309 """ Decorator for if reporting is enabled"""
311 def wrapper(request
, *args
, **kwargs
):
312 if not mgg
.app_config
["allow_reporting"]:
313 messages
.add_message(
316 _('Sorry, reporting is disabled on this instance.'))
317 return redirect(request
, 'index')
319 return controller(request
, *args
, **kwargs
)
323 def get_optional_media_comment_by_id(controller
):
325 Pass in a MediaComment based off of a url component. Because of this decor-
326 -ator's use in filing Media or Comment Reports, it has two valid outcomes.
328 :returns The view function being wrapped with kwarg `comment` set to
329 the MediaComment who's id is in the URL. If there is a
330 comment id in the URL and if it is valid.
331 :returns The view function being wrapped with kwarg `comment` set to
332 None. If there is no comment id in the URL.
333 :returns A 404 Error page, if there is a comment if in the URL and it
337 def wrapper(request
, *args
, **kwargs
):
338 if 'comment' in request
.matchdict
:
339 comment
= MediaComment
.query
.filter_by(
340 id=request
.matchdict
['comment']).first()
343 return render_404(request
)
345 return controller(request
, comment
=comment
, *args
, **kwargs
)
347 return controller(request
, comment
=None, *args
, **kwargs
)
351 def auth_enabled(controller
):
352 """Decorator for if an auth plugin is enabled"""
354 def wrapper(request
, *args
, **kwargs
):
356 messages
.add_message(
359 _('Sorry, authentication is disabled on this instance.'))
360 return redirect(request
, 'index')
362 return controller(request
, *args
, **kwargs
)
366 def require_admin_or_moderator_login(controller
):
368 Require a login from an administrator or a moderator.
371 def new_controller_func(request
, *args
, **kwargs
):
372 if request
.user
and \
373 not request
.user
.has_privilege(u
'admin',u
'moderator'):
376 elif not request
.user
:
378 request
.urlgen('mediagoblin.auth.login',
382 return redirect(request
, 'mediagoblin.auth.login',
385 return controller(request
, *args
, **kwargs
)
387 return new_controller_func
391 def oauth_required(controller
):
392 """ Used to wrap API endpoints where oauth is required """
394 def wrapper(request
, *args
, **kwargs
):
395 data
= request
.headers
396 authorization
= decode_authorization_header(data
)
398 if authorization
== dict():
399 error
= "Missing required parameter."
400 return json_response({"error": error
}, status
=400)
403 request_validator
= GMGRequestValidator()
404 resource_endpoint
= ResourceEndpoint(request_validator
)
405 valid
, request
= resource_endpoint
.validate_protected_resource_request(
407 http_method
=request
.method
,
408 body
=request
.get_data(),
409 headers
=dict(request
.headers
),
413 error
= "Invalid oauth prarameter."
414 return json_response({"error": error
}, status
=400)
416 return controller(request
, *args
, **kwargs
)