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/>.
20 from functools
import wraps
21 from werkzeug
.exceptions
import Forbidden
22 from werkzeug
.wrappers
import Response
24 from six
.moves
.urllib
.parse
import urljoin
26 from mediagoblin
import mg_globals
27 from mediagoblin
.tools
.pluginapi
import PluginManager
28 from mediagoblin
.storage
.filestorage
import BasicFileStorage
30 _log
= logging
.getLogger(__name__
)
35 An object with two significant methods, 'trigger' and 'run'.
37 Using a similar object to this, plugins can register specific
38 authentication logic, for example the GET param 'access_token' for OAuth.
40 - trigger: Analyze the 'request' argument, return True if you think you
41 can handle the request, otherwise return False
42 - run: The authentication logic, set the request.user object to the user
43 you intend to authenticate and return True, otherwise return False.
45 If run() returns False, an HTTP 403 Forbidden error will be shown.
47 You may also display custom errors, just raise them within the run()
50 def trigger(self
, request
):
51 raise NotImplemented()
53 def __call__(self
, request
, *args
, **kw
):
54 raise NotImplemented()
56 def get_entry_serializable(entry
, urlgen
):
58 Returns a serializable dict() of a MediaEntry instance.
60 :param entry: A MediaEntry instance
61 :param urlgen: An urlgen instance, can be found on the request object passed
65 'user': entry
.get_uploader
.username
,
66 'user_id': entry
.get_uploader
.id,
67 'user_bio': entry
.get_uploader
.bio
,
68 'user_bio_html': entry
.get_uploader
.bio_html
,
69 'user_permalink': urlgen('mediagoblin.user_pages.user_home',
70 user
=entry
.get_uploader
.username
,
73 'created': entry
.created
.isoformat(),
75 'license': entry
.license
,
76 'description': entry
.description
,
77 'description_html': entry
.description_html
,
78 'media_type': entry
.media_type
,
80 'permalink': entry
.url_for_self(urlgen
, qualified
=True),
81 'media_files': get_media_file_paths(entry
.media_files
, urlgen
)}
84 def get_media_file_paths(media_files
, urlgen
):
86 Returns a dictionary of media files with `file_handle` => `qualified URL`
88 :param media_files: dict-like object consisting of `file_handle => `listy
90 :param urlgen: An urlgen object, usually found on request.urlgen.
94 for key
, val
in media_files
.items():
95 if isinstance(mg_globals
.public_store
, BasicFileStorage
):
96 # BasicFileStorage does not provide a qualified URI
97 media_urls
[key
] = urljoin(
98 urlgen('index', qualified
=True),
99 mg_globals
.public_store
.file_url(val
))
101 media_urls
[key
] = mg_globals
.public_store
.file_url(val
)
106 def api_auth(controller
):
108 Decorator, allows plugins to register auth methods that will then be
109 evaluated against the request, finally a worthy authenticator object is
110 chosen and used to decide whether to grant or deny access.
113 def wrapper(request
, *args
, **kw
):
116 for auth
in PluginManager().get_hook_callables('auth'):
117 if auth
.trigger(request
):
118 _log
.debug('{0} believes it is capable of authenticating this request.'.format(auth
))
119 auth_candidates
.append(auth
)
121 # If we can't find any authentication methods, we should not let them
123 if not auth_candidates
:
126 # For now, just select the first one in the list
127 auth
= auth_candidates
[0]
129 _log
.debug('Using {0} to authorize request {1}'.format(
132 if not auth(request
, *args
, **kw
):
133 if getattr(auth
, 'errors', []):
134 return json_response({
136 'errors': auth
.errors
})
140 return controller(request
, *args
, **kw
)