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
26 from mediagoblin
.tools
.response
import json_response
, redirect
, render_404
27 from mediagoblin
.tools
.translate
import pass_to_ugettext
as _
29 from mediagoblin
.oauth
.tools
.request
import decode_authorization_header
30 from mediagoblin
.oauth
.oauth
import GMGRequestValidator
32 def require_active_login(controller
):
34 Require an active login from the user.
37 def new_controller_func(request
, *args
, **kwargs
):
39 request
.user
.status
== u
'needs_email_verification':
41 request
, 'mediagoblin.user_pages.user_home',
42 user
=request
.user
.username
)
43 elif not request
.user
or request
.user
.status
!= u
'active':
45 request
.urlgen('mediagoblin.auth.login',
49 return redirect(request
, 'mediagoblin.auth.login',
52 return controller(request
, *args
, **kwargs
)
54 return new_controller_func
56 def active_user_from_url(controller
):
57 """Retrieve User() from <user> URL pattern and pass in as url_user=...
59 Returns a 404 if no such active user has been found"""
61 def wrapper(request
, *args
, **kwargs
):
62 user
= User
.query
.filter_by(username
=request
.matchdict
['user']).first()
64 return render_404(request
)
66 return controller(request
, *args
, url_user
=user
, **kwargs
)
71 def user_may_delete_media(controller
):
73 Require user ownership of the MediaEntry to delete.
76 def wrapper(request
, *args
, **kwargs
):
77 uploader_id
= kwargs
['media'].uploader
78 if not (request
.user
.is_admin
or
79 request
.user
.id == uploader_id
):
82 return controller(request
, *args
, **kwargs
)
87 def user_may_alter_collection(controller
):
89 Require user ownership of the Collection to modify.
92 def wrapper(request
, *args
, **kwargs
):
93 creator_id
= request
.db
.User
.query
.filter_by(
94 username
=request
.matchdict
['user']).first().id
95 if not (request
.user
.is_admin
or
96 request
.user
.id == creator_id
):
99 return controller(request
, *args
, **kwargs
)
104 def uses_pagination(controller
):
106 Check request GET 'page' key for wrong values
109 def wrapper(request
, *args
, **kwargs
):
111 page
= int(request
.GET
.get('page', 1))
113 return render_404(request
)
115 return render_404(request
)
117 return controller(request
, page
=page
, *args
, **kwargs
)
122 def get_user_media_entry(controller
):
124 Pass in a MediaEntry based off of a url component
127 def wrapper(request
, *args
, **kwargs
):
128 user
= User
.query
.filter_by(username
=request
.matchdict
['user']).first()
134 # might not be a slug, might be an id, but whatever
135 media_slug
= request
.matchdict
['media']
137 # if it starts with id: it actually isn't a slug, it's an id.
138 if media_slug
.startswith(u
'id:'):
140 media
= MediaEntry
.query
.filter_by(
141 id=int(media_slug
[3:]),
143 uploader
=user
.id).first()
147 # no magical id: stuff? It's a slug!
148 media
= MediaEntry
.query
.filter_by(
151 uploader
=user
.id).first()
154 # Didn't find anything? Okay, 404.
157 return controller(request
, media
=media
, *args
, **kwargs
)
162 def get_user_collection(controller
):
164 Pass in a Collection based off of a url component
167 def wrapper(request
, *args
, **kwargs
):
168 user
= request
.db
.User
.query
.filter_by(
169 username
=request
.matchdict
['user']).first()
172 return render_404(request
)
174 collection
= request
.db
.Collection
.query
.filter_by(
175 slug
=request
.matchdict
['collection'],
176 creator
=user
.id).first()
178 # Still no collection? Okay, 404.
180 return render_404(request
)
182 return controller(request
, collection
=collection
, *args
, **kwargs
)
187 def get_user_collection_item(controller
):
189 Pass in a CollectionItem based off of a url component
192 def wrapper(request
, *args
, **kwargs
):
193 user
= request
.db
.User
.query
.filter_by(
194 username
=request
.matchdict
['user']).first()
197 return render_404(request
)
199 collection_item
= request
.db
.CollectionItem
.query
.filter_by(
200 id=request
.matchdict
['collection_item']).first()
202 # Still no collection item? Okay, 404.
203 if not collection_item
:
204 return render_404(request
)
206 return controller(request
, collection_item
=collection_item
, *args
, **kwargs
)
211 def get_media_entry_by_id(controller
):
213 Pass in a MediaEntry based off of a url component
216 def wrapper(request
, *args
, **kwargs
):
217 media
= MediaEntry
.query
.filter_by(
218 id=request
.matchdict
['media_id'],
219 state
=u
'processed').first()
220 # Still no media? Okay, 404.
222 return render_404(request
)
224 given_username
= request
.matchdict
.get('user')
225 if given_username
and (given_username
!= media
.get_uploader
.username
):
226 return render_404(request
)
228 return controller(request
, media
=media
, *args
, **kwargs
)
233 def get_workbench(func
):
234 """Decorator, passing in a workbench as kwarg which is cleaned up afterwards"""
237 def new_func(*args
, **kwargs
):
238 with mgg
.workbench_manager
.create() as workbench
:
239 return func(*args
, workbench
=workbench
, **kwargs
)
244 def allow_registration(controller
):
245 """ Decorator for if registration is enabled"""
247 def wrapper(request
, *args
, **kwargs
):
248 if not mgg
.app_config
["allow_registration"]:
249 messages
.add_message(
252 _('Sorry, registration is disabled on this instance.'))
253 return redirect(request
, "index")
255 return controller(request
, *args
, **kwargs
)
260 def auth_enabled(controller
):
261 """Decorator for if an auth plugin is enabled"""
263 def wrapper(request
, *args
, **kwargs
):
265 messages
.add_message(
268 _('Sorry, authentication is disabled on this instance.'))
269 return redirect(request
, 'index')
271 return controller(request
, *args
, **kwargs
)
275 def oauth_required(controller
):
276 """ Used to wrap API endpoints where oauth is required """
278 def wrapper(request
, *args
, **kwargs
):
279 data
= request
.headers
280 authorization
= decode_authorization_header(data
)
282 if authorization
== dict():
283 error
= "Missing required parameter."
284 return json_response({"error": error
}, status
=400)
287 request_validator
= GMGRequestValidator()
288 resource_endpoint
= ResourceEndpoint(request_validator
)
289 valid
, request
= resource_endpoint
.validate_protected_resource_request(
291 http_method
=request
.method
,
292 body
=request
.get_data(),
293 headers
=dict(request
.headers
),
297 error
= "Invalid oauth prarameter."
298 return json_response({"error": error
}, status
=400)
300 return controller(request
, *args
, **kwargs
)