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
,
27 from mediagoblin
.tools
.response
import (redirect
, render_404
,
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 get_optional_media_comment_by_id(controller
):
309 Pass in a MediaComment based off of a url component. Because of this decor-
310 -ator's use in filing Media or Comment Reports, it has two valid outcomes.
312 :returns The view function being wrapped with kwarg `comment` set to
313 the MediaComment who's id is in the URL. If there is a
314 comment id in the URL and if it is valid.
315 :returns The view function being wrapped with kwarg `comment` set to
316 None. If there is no comment id in the URL.
317 :returns A 404 Error page, if there is a comment if in the URL and it
321 def wrapper(request
, *args
, **kwargs
):
322 if 'comment' in request
.matchdict
:
323 comment
= MediaComment
.query
.filter_by(
324 id=request
.matchdict
['comment']).first()
327 return render_404(request
)
329 return controller(request
, comment
=comment
, *args
, **kwargs
)
331 return controller(request
, comment
=None, *args
, **kwargs
)
335 def auth_enabled(controller
):
336 """Decorator for if an auth plugin is enabled"""
338 def wrapper(request
, *args
, **kwargs
):
340 messages
.add_message(
343 _('Sorry, authentication is disabled on this instance.'))
344 return redirect(request
, 'index')
346 return controller(request
, *args
, **kwargs
)
350 def require_admin_or_moderator_login(controller
):
352 Require a login from an administrator or a moderator.
355 def new_controller_func(request
, *args
, **kwargs
):
356 if request
.user
and \
357 not request
.user
.has_privilege(u
'admin',u
'moderator'):
360 elif not request
.user
:
362 request
.urlgen('mediagoblin.auth.login',
366 return redirect(request
, 'mediagoblin.auth.login',
369 return controller(request
, *args
, **kwargs
)
371 return new_controller_func
375 def oauth_required(controller
):
376 """ Used to wrap API endpoints where oauth is required """
378 def wrapper(request
, *args
, **kwargs
):
379 data
= request
.headers
380 authorization
= decode_authorization_header(data
)
382 if authorization
== dict():
383 error
= "Missing required parameter."
384 return json_response({"error": error
}, status
=400)
387 request_validator
= GMGRequestValidator()
388 resource_endpoint
= ResourceEndpoint(request_validator
)
389 valid
, request
= resource_endpoint
.validate_protected_resource_request(
391 http_method
=request
.method
,
392 body
=request
.get_data(),
393 headers
=dict(request
.headers
),
397 error
= "Invalid oauth prarameter."
398 return json_response({"error": error
}, status
=400)
400 return controller(request
, *args
, **kwargs
)