Commit | Line | Data |
---|---|---|
427beb08 E |
1 | # GNU MediaGoblin -- federated, autonomous media hosting |
2 | # Copyright (C) 2013 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 | |
398d3841 | 18 | import re |
c732f422 JW |
19 | from os.path import splitext |
20 | import shutil | |
427beb08 | 21 | |
90d7de25 | 22 | from werkzeug.exceptions import MethodNotAllowed, BadRequest, NotImplemented |
e4e5948c | 23 | from werkzeug.wrappers import BaseResponse |
427beb08 E |
24 | |
25 | from mediagoblin.meddleware.csrf import csrf_exempt | |
7fb419dd | 26 | from mediagoblin.auth.lib import fake_login_attempt |
c732f422 JW |
27 | from mediagoblin.media_types import sniff_media |
28 | from mediagoblin.submit.lib import check_file_field, prepare_queue_task, \ | |
6c1467d5 | 29 | run_process_media, new_upload_entry |
c732f422 | 30 | |
41501106 MS |
31 | from mediagoblin.user_pages.lib import add_media_to_collection |
32 | from mediagoblin.db.models import Collection | |
33 | ||
4adc3a85 E |
34 | from .tools import CmdTable, response_xml, check_form, \ |
35 | PWGSession, PwgNamedArray, PwgError | |
c1df8d19 | 36 | from .forms import AddSimpleForm, AddForm |
427beb08 E |
37 | |
38 | ||
39 | _log = logging.getLogger(__name__) | |
40 | ||
41 | ||
427beb08 E |
42 | @CmdTable("pwg.session.login", True) |
43 | def pwg_login(request): | |
44 | username = request.form.get("username") | |
45 | password = request.form.get("password") | |
7fb419dd E |
46 | user = request.db.User.query.filter_by(username=username).first() |
47 | if not user: | |
f035ec3d | 48 | _log.info("User %r not found", username) |
7fb419dd | 49 | fake_login_attempt() |
4adc3a85 | 50 | return PwgError(999, 'Invalid username/password') |
7fb419dd | 51 | if not user.check_login(password): |
f035ec3d | 52 | _log.warn("Wrong password for %r", username) |
4adc3a85 | 53 | return PwgError(999, 'Invalid username/password') |
f035ec3d | 54 | _log.info("Logging %r in", username) |
7fb419dd E |
55 | request.session["user_id"] = user.id |
56 | request.session.save() | |
e4e5948c | 57 | return True |
bd3bc044 E |
58 | |
59 | ||
60 | @CmdTable("pwg.session.logout") | |
61 | def pwg_logout(request): | |
62 | _log.info("Logout") | |
7fb419dd | 63 | request.session.delete() |
e4e5948c | 64 | return True |
bd3bc044 E |
65 | |
66 | ||
67 | @CmdTable("pwg.getVersion") | |
68 | def pwg_getversion(request): | |
9924cd0f | 69 | return "2.5.0 (MediaGoblin)" |
cf0816c1 E |
70 | |
71 | ||
72 | @CmdTable("pwg.session.getStatus") | |
73 | def pwg_session_getStatus(request): | |
66594603 E |
74 | if request.user: |
75 | username = request.user.username | |
76 | else: | |
77 | username = "guest" | |
78 | return {'username': username} | |
e4e5948c E |
79 | |
80 | ||
81 | @CmdTable("pwg.categories.getList") | |
82 | def pwg_categories_getList(request): | |
41501106 MS |
83 | collections = Collection.query.filter_by( |
84 | get_creator=request.user).order_by(Collection.title) | |
85 | ||
86 | catlist = [{'id': -29711, | |
cf0816c1 | 87 | 'uppercats': "-29711", |
41501106 MS |
88 | 'name': "All my images"}] |
89 | ||
7da90d56 MS |
90 | if request.user: |
91 | for c in collections: | |
92 | catlist.append({'id': c.id, | |
93 | 'uppercats': str(c.id), | |
94 | 'name': c.title, | |
95 | 'comment': c.description | |
96 | }) | |
41501106 | 97 | |
e4e5948c E |
98 | return { |
99 | 'categories': PwgNamedArray( | |
100 | catlist, | |
101 | 'category', | |
102 | ( | |
103 | 'id', | |
104 | 'url', | |
105 | 'nb_images', | |
106 | 'total_nb_images', | |
107 | 'nb_categories', | |
108 | 'date_last', | |
109 | 'max_date_last', | |
110 | ) | |
111 | ) | |
112 | } | |
427beb08 E |
113 | |
114 | ||
398d3841 E |
115 | @CmdTable("pwg.images.exist") |
116 | def pwg_images_exist(request): | |
117 | return {} | |
118 | ||
119 | ||
79f87b97 E |
120 | @CmdTable("pwg.images.addSimple", True) |
121 | def pwg_images_addSimple(request): | |
122 | form = AddSimpleForm(request.form) | |
123 | if not form.validate(): | |
124 | _log.error("addSimple: form failed") | |
125 | raise BadRequest() | |
126 | dump = [] | |
127 | for f in form: | |
128 | dump.append("%s=%r" % (f.name, f.data)) | |
18e64476 MS |
129 | _log.info("addSimple: %r %s %r", request.form, " ".join(dump), |
130 | request.files) | |
79f87b97 | 131 | |
f6f55769 E |
132 | if not check_file_field(request, 'image'): |
133 | raise BadRequest() | |
134 | ||
c732f422 JW |
135 | filename = request.files['image'].filename |
136 | ||
137 | # Sniff the submitted media to determine which | |
138 | # media plugin should handle processing | |
139 | media_type, media_manager = sniff_media( | |
140 | request.files['image']) | |
141 | ||
142 | # create entry and save in database | |
6c1467d5 | 143 | entry = new_upload_entry(request.user) |
c732f422 JW |
144 | entry.media_type = unicode(media_type) |
145 | entry.title = ( | |
146 | unicode(form.name.data) | |
147 | or unicode(splitext(filename)[0])) | |
148 | ||
149 | entry.description = unicode(form.comment.data) | |
150 | ||
c732f422 JW |
151 | ''' |
152 | # Process the user's folksonomy "tags" | |
153 | entry.tags = convert_to_tag_list_of_dicts( | |
154 | form.tags.data) | |
155 | ''' | |
156 | ||
157 | # Generate a slug from the title | |
158 | entry.generate_slug() | |
159 | ||
160 | queue_file = prepare_queue_task(request.app, entry, filename) | |
161 | ||
162 | with queue_file: | |
163 | shutil.copyfileobj(request.files['image'].stream, | |
164 | queue_file, | |
165 | length=4 * 1048576) | |
166 | ||
167 | # Save now so we have this data before kicking off processing | |
168 | entry.save() | |
169 | ||
170 | # Pass off to processing | |
171 | # | |
172 | # (... don't change entry after this point to avoid race | |
173 | # conditions with changes to the document via processing code) | |
174 | feed_url = request.urlgen( | |
175 | 'mediagoblin.user_pages.atom_feed', | |
176 | qualified=True, user=request.user.username) | |
177 | run_process_media(entry, feed_url) | |
178 | ||
41501106 MS |
179 | collection_id = form.category.data |
180 | if collection_id > 0: | |
181 | collection = Collection.query.get(collection_id) | |
94d31920 MS |
182 | if collection is not None and collection.creator == request.user.id: |
183 | add_media_to_collection(collection, entry, "") | |
41501106 | 184 | |
c732f422 JW |
185 | return {'image_id': entry.id, 'url': entry.url_for_self(request.urlgen, |
186 | qualified=True)} | |
187 | ||
79f87b97 | 188 | |
398d3841 E |
189 | md5sum_matcher = re.compile(r"^[0-9a-fA-F]{32}$") |
190 | ||
c732f422 | 191 | |
398d3841 E |
192 | def fetch_md5(request, parm_name, optional_parm=False): |
193 | val = request.form.get(parm_name) | |
194 | if (val is None) and (not optional_parm): | |
195 | _log.error("Parameter %s missing", parm_name) | |
196 | raise BadRequest("Parameter %s missing" % parm_name) | |
197 | if not md5sum_matcher.match(val): | |
198 | _log.error("Parameter %s=%r has no valid md5 value", parm_name, val) | |
199 | raise BadRequest("Parameter %s is not md5" % parm_name) | |
200 | return val | |
201 | ||
202 | ||
203 | @CmdTable("pwg.images.addChunk", True) | |
204 | def pwg_images_addChunk(request): | |
205 | o_sum = fetch_md5(request, 'original_sum') | |
206 | typ = request.form.get('type') | |
207 | pos = request.form.get('position') | |
208 | data = request.form.get('data') | |
209 | ||
210 | # Validate params: | |
211 | pos = int(pos) | |
212 | if not typ in ("file", "thumb"): | |
213 | _log.error("type %r not allowed for now", typ) | |
214 | return False | |
215 | ||
216 | _log.info("addChunk for %r, type %r, position %d, len: %d", | |
217 | o_sum, typ, pos, len(data)) | |
218 | if typ == "thumb": | |
219 | _log.info("addChunk: Ignoring thumb, because we create our own") | |
220 | return True | |
221 | ||
222 | return True | |
223 | ||
224 | ||
c1df8d19 E |
225 | @CmdTable("pwg.images.add", True) |
226 | def pwg_images_add(request): | |
227 | _log.info("add: %r", request.form) | |
228 | form = AddForm(request.form) | |
229 | check_form(form) | |
230 | ||
231 | return {'image_id': 123456, 'url': ''} | |
232 | ||
233 | ||
427beb08 E |
234 | @csrf_exempt |
235 | def ws_php(request): | |
236 | if request.method not in ("GET", "POST"): | |
237 | _log.error("Method %r not supported", request.method) | |
238 | raise MethodNotAllowed() | |
239 | ||
240 | func = CmdTable.find_func(request) | |
241 | if not func: | |
242 | _log.warn("wsphp: Unhandled %s %r %r", request.method, | |
243 | request.args, request.form) | |
90d7de25 | 244 | raise NotImplemented() |
427beb08 | 245 | |
7fb419dd E |
246 | with PWGSession(request) as session: |
247 | result = func(request) | |
427beb08 | 248 | |
7fb419dd E |
249 | if isinstance(result, BaseResponse): |
250 | return result | |
e4e5948c | 251 | |
7fb419dd E |
252 | response = response_xml(result) |
253 | session.save_to_cookie(response) | |
dc7c26f3 | 254 | |
7fb419dd | 255 | return response |