Make changes for displaying page listing all the blogs created by user.
[mediagoblin.git] / mediagoblin / plugins / api / tools.py
1 # GNU MediaGoblin -- federated, autonomous media hosting
2 # Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS.
3 #
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.
8 #
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.
13 #
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/>.
16
17 import logging
18 import json
19
20 from functools import wraps
21 from urlparse import urljoin
22 from werkzeug.exceptions import Forbidden
23 from werkzeug.wrappers import Response
24 from mediagoblin import mg_globals
25 from mediagoblin.tools.pluginapi import PluginManager
26 from mediagoblin.storage.filestorage import BasicFileStorage
27
28 _log = logging.getLogger(__name__)
29
30
31 class Auth(object):
32 '''
33 An object with two significant methods, 'trigger' and 'run'.
34
35 Using a similar object to this, plugins can register specific
36 authentication logic, for example the GET param 'access_token' for OAuth.
37
38 - trigger: Analyze the 'request' argument, return True if you think you
39 can handle the request, otherwise return False
40 - run: The authentication logic, set the request.user object to the user
41 you intend to authenticate and return True, otherwise return False.
42
43 If run() returns False, an HTTP 403 Forbidden error will be shown.
44
45 You may also display custom errors, just raise them within the run()
46 method.
47 '''
48 def trigger(self, request):
49 raise NotImplemented()
50
51 def __call__(self, request, *args, **kw):
52 raise NotImplemented()
53
54 def get_entry_serializable(entry, urlgen):
55 '''
56 Returns a serializable dict() of a MediaEntry instance.
57
58 :param entry: A MediaEntry instance
59 :param urlgen: An urlgen instance, can be found on the request object passed
60 to views.
61 '''
62 return {
63 'user': entry.get_uploader.username,
64 'user_id': entry.get_uploader.id,
65 'user_bio': entry.get_uploader.bio,
66 'user_bio_html': entry.get_uploader.bio_html,
67 'user_permalink': urlgen('mediagoblin.user_pages.user_home',
68 user=entry.get_uploader.username,
69 qualified=True),
70 'id': entry.id,
71 'created': entry.created.isoformat(),
72 'title': entry.title,
73 'license': entry.license,
74 'description': entry.description,
75 'description_html': entry.description_html,
76 'media_type': entry.media_type,
77 'state': entry.state,
78 'permalink': entry.url_for_self(urlgen, qualified=True),
79 'media_files': get_media_file_paths(entry.media_files, urlgen)}
80
81
82 def get_media_file_paths(media_files, urlgen):
83 '''
84 Returns a dictionary of media files with `file_handle` => `qualified URL`
85
86 :param media_files: dict-like object consisting of `file_handle => `listy
87 filepath` pairs.
88 :param urlgen: An urlgen object, usually found on request.urlgen.
89 '''
90 media_urls = {}
91
92 for key, val in media_files.items():
93 if isinstance(mg_globals.public_store, BasicFileStorage):
94 # BasicFileStorage does not provide a qualified URI
95 media_urls[key] = urljoin(
96 urlgen('index', qualified=True),
97 mg_globals.public_store.file_url(val))
98 else:
99 media_urls[key] = mg_globals.public_store.file_url(val)
100
101 return media_urls
102
103
104 def api_auth(controller):
105 '''
106 Decorator, allows plugins to register auth methods that will then be
107 evaluated against the request, finally a worthy authenticator object is
108 chosen and used to decide whether to grant or deny access.
109 '''
110 @wraps(controller)
111 def wrapper(request, *args, **kw):
112 auth_candidates = []
113
114 for auth in PluginManager().get_hook_callables('auth'):
115 if auth.trigger(request):
116 _log.debug('{0} believes it is capable of authenticating this request.'.format(auth))
117 auth_candidates.append(auth)
118
119 # If we can't find any authentication methods, we should not let them
120 # pass.
121 if not auth_candidates:
122 raise Forbidden()
123
124 # For now, just select the first one in the list
125 auth = auth_candidates[0]
126
127 _log.debug('Using {0} to authorize request {1}'.format(
128 auth, request.url))
129
130 if not auth(request, *args, **kw):
131 if getattr(auth, 'errors', []):
132 return json_response({
133 'status': 403,
134 'errors': auth.errors})
135
136 raise Forbidden()
137
138 return controller(request, *args, **kw)
139
140 return wrapper