Commit | Line | Data |
---|---|---|
7f4ebeed | 1 | # GNU MediaGoblin -- federated, autonomous media hosting |
cf29e8a8 | 2 | # Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. |
9a16e16f SS |
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 | ||
fb2fbe2c | 17 | import logging |
64712915 | 18 | import datetime |
52359e91 | 19 | |
3a8c3a38 | 20 | from mediagoblin import messages, mg_globals |
f2c0bf3e SS |
21 | from mediagoblin.db.models import (MediaEntry, MediaTag, Collection, |
22 | CollectionItem, User) | |
2e6ee596 E |
23 | from mediagoblin.tools.response import render_to_response, render_404, \ |
24 | redirect, redirect_obj | |
a789b713 | 25 | from mediagoblin.tools.translate import pass_to_ugettext as _ |
152a3bfa | 26 | from mediagoblin.tools.pagination import Pagination |
9074ee7c | 27 | from mediagoblin.user_pages import forms as user_forms |
6bea8a90 E |
28 | from mediagoblin.user_pages.lib import (send_comment_email, |
29 | add_media_to_collection) | |
f6249408 | 30 | |
50854db0 | 31 | from mediagoblin.decorators import (uses_pagination, get_user_media_entry, |
461dd971 | 32 | get_media_entry_by_id, |
6d1e55b2 | 33 | require_active_login, user_may_delete_media, user_may_alter_collection, |
64c2a400 | 34 | get_user_collection, get_user_collection_item, active_user_from_url) |
9a16e16f | 35 | |
00c39256 | 36 | from werkzeug.contrib.atom import AtomFeed |
1301a8ad | 37 | |
9074ee7c | 38 | |
fb2fbe2c JAN |
39 | _log = logging.getLogger(__name__) |
40 | _log.setLevel(logging.DEBUG) | |
41 | ||
64712915 | 42 | |
3eb6fc4f | 43 | @uses_pagination |
1301a8ad | 44 | def user_home(request, page): |
9a16e16f | 45 | """'Homepage' of a User()""" |
af008743 SS |
46 | # TODO: decide if we only want homepages for active users, we can |
47 | # then use the @get_active_user decorator and also simplify the | |
48 | # template html. | |
49 | user = User.query.filter_by(username=request.matchdict['user']).first() | |
7acdbfd3 | 50 | if not user: |
de12b4e7 | 51 | return render_404(request) |
7a3d00ec | 52 | elif user.status != u'active': |
990d3b69 CAW |
53 | return render_to_response( |
54 | request, | |
55 | 'mediagoblin/user_pages/user.html', | |
56 | {'user': user}) | |
9a16e16f | 57 | |
2fb36dac SS |
58 | cursor = MediaEntry.query.\ |
59 | filter_by(uploader = user.id, | |
0efe9e27 | 60 | state = u'processed').order_by(MediaEntry.created.desc()) |
9a16e16f | 61 | |
1301a8ad | 62 | pagination = Pagination(page, cursor) |
ca3ca51c | 63 | media_entries = pagination() |
44e3e917 | 64 | |
ae85ed0f BK |
65 | #if no data is available, return NotFound |
66 | if media_entries == None: | |
de12b4e7 | 67 | return render_404(request) |
243c3843 | 68 | |
5949be9a CAW |
69 | user_gallery_url = request.urlgen( |
70 | 'mediagoblin.user_pages.user_gallery', | |
5a4e3ff1 | 71 | user=user.username) |
5949be9a | 72 | |
9038c9f9 CAW |
73 | return render_to_response( |
74 | request, | |
c9c24934 E |
75 | 'mediagoblin/user_pages/user.html', |
76 | {'user': user, | |
5949be9a | 77 | 'user_gallery_url': user_gallery_url, |
c9c24934 E |
78 | 'media_entries': media_entries, |
79 | 'pagination': pagination}) | |
f6249408 | 80 | |
243c3843 | 81 | |
64c2a400 | 82 | @active_user_from_url |
184f2240 | 83 | @uses_pagination |
64c2a400 | 84 | def user_gallery(request, page, url_user=None): |
184f2240 | 85 | """'Gallery' of a User()""" |
f2c0bf3e | 86 | tag = request.matchdict.get('tag', None) |
64c2a400 SS |
87 | cursor = MediaEntry.query.filter_by( |
88 | uploader=url_user.id, | |
89 | state=u'processed').order_by(MediaEntry.created.desc()) | |
af008743 | 90 | |
f2c0bf3e SS |
91 | # Filter potentially by tag too: |
92 | if tag: | |
93 | cursor = cursor.filter( | |
94 | MediaEntry.tags_helper.any( | |
38905733 | 95 | MediaTag.slug == request.matchdict['tag'])) |
f2c0bf3e | 96 | |
64c2a400 | 97 | # Paginate gallery |
184f2240 | 98 | pagination = Pagination(page, cursor) |
99 | media_entries = pagination() | |
100 | ||
101 | #if no data is available, return NotFound | |
64c2a400 | 102 | # TODO: Should we really also return 404 for empty galleries? |
184f2240 | 103 | if media_entries == None: |
de12b4e7 | 104 | return render_404(request) |
243c3843 | 105 | |
4b5f5a08 | 106 | return render_to_response( |
107 | request, | |
108 | 'mediagoblin/user_pages/gallery.html', | |
f2c0bf3e | 109 | {'user': url_user, 'tag': tag, |
4b5f5a08 | 110 | 'media_entries': media_entries, |
111 | 'pagination': pagination}) | |
184f2240 | 112 | |
6f59a3a3 | 113 | MEDIA_COMMENTS_PER_PAGE = 50 |
434b3221 | 114 | |
243c3843 | 115 | |
01674e10 | 116 | @get_user_media_entry |
9074ee7c | 117 | @uses_pagination |
6f59a3a3 | 118 | def media_home(request, media, page, **kwargs): |
9074ee7c JW |
119 | """ |
120 | 'Homepage' of a MediaEntry() | |
121 | """ | |
7d16a01b E |
122 | comment_id = request.matchdict.get('comment', None) |
123 | if comment_id: | |
af2fcba5 | 124 | pagination = Pagination( |
7c378f2c CAW |
125 | page, media.get_comments( |
126 | mg_globals.app_config['comments_ascending']), | |
127 | MEDIA_COMMENTS_PER_PAGE, | |
7d16a01b | 128 | comment_id) |
af2fcba5 JW |
129 | else: |
130 | pagination = Pagination( | |
7c378f2c CAW |
131 | page, media.get_comments( |
132 | mg_globals.app_config['comments_ascending']), | |
133 | MEDIA_COMMENTS_PER_PAGE) | |
9074ee7c | 134 | |
6f59a3a3 | 135 | comments = pagination() |
9074ee7c | 136 | |
111a609d | 137 | comment_form = user_forms.MediaCommentForm(request.form) |
9074ee7c | 138 | |
5f8b4ae8 | 139 | media_template_name = media.media_manager['display_template'] |
93bdab9d | 140 | |
9038c9f9 CAW |
141 | return render_to_response( |
142 | request, | |
93bdab9d | 143 | media_template_name, |
9074ee7c JW |
144 | {'media': media, |
145 | 'comments': comments, | |
146 | 'pagination': pagination, | |
3a8c3a38 JW |
147 | 'comment_form': comment_form, |
148 | 'app_config': mg_globals.app_config}) | |
9074ee7c | 149 | |
95e6da02 | 150 | |
461dd971 | 151 | @get_media_entry_by_id |
9074ee7c | 152 | @require_active_login |
95e12bf2 | 153 | def media_post_comment(request, media): |
9074ee7c JW |
154 | """ |
155 | recieves POST from a MediaEntry() comment form, saves the comment. | |
156 | """ | |
95e12bf2 CAW |
157 | assert request.method == 'POST' |
158 | ||
9074ee7c | 159 | comment = request.db.MediaComment() |
8efcd405 E |
160 | comment.media_entry = media.id |
161 | comment.author = request.user.id | |
111a609d | 162 | comment.content = unicode(request.form['comment_content']) |
9074ee7c | 163 | |
99338b6a DT |
164 | # Show error message if commenting is disabled. |
165 | if not mg_globals.app_config['allow_comments']: | |
166 | messages.add_message( | |
167 | request, | |
168 | messages.ERROR, | |
169 | _("Sorry, comments are disabled.")) | |
170 | elif not comment.content.strip(): | |
7298ffa1 AW |
171 | messages.add_message( |
172 | request, | |
173 | messages.ERROR, | |
eae7d058 | 174 | _("Oops, your comment was empty.")) |
7298ffa1 AW |
175 | else: |
176 | comment.save() | |
b5d3aec6 | 177 | |
7298ffa1 AW |
178 | messages.add_message( |
179 | request, messages.SUCCESS, | |
eae7d058 | 180 | _('Your comment has been posted!')) |
52359e91 | 181 | |
252eaf21 DM |
182 | media_uploader = media.get_uploader |
183 | #don't send email if you comment on your own post | |
184 | if (comment.author != media_uploader and | |
00722c99 | 185 | media_uploader.wants_comment_notification): |
252eaf21 DM |
186 | send_comment_email(media_uploader, comment, media, request) |
187 | ||
2e6ee596 | 188 | return redirect_obj(request, media) |
00c39256 | 189 | |
95e6da02 | 190 | |
96a2249b | 191 | @get_media_entry_by_id |
be5be115 AW |
192 | @require_active_login |
193 | def media_collect(request, media): | |
f6bc0336 | 194 | """Add media to collection submission""" |
be5be115 | 195 | |
111a609d | 196 | form = user_forms.MediaCollectForm(request.form) |
f6bc0336 | 197 | # A user's own collections: |
2fb36dac SS |
198 | form.collection.query = Collection.query.filter_by( |
199 | creator = request.user.id).order_by(Collection.title) | |
f6bc0336 SS |
200 | |
201 | if request.method != 'POST' or not form.validate(): | |
202 | # No POST submission, or invalid form | |
203 | if not form.validate(): | |
204 | messages.add_message(request, messages.ERROR, | |
205 | _('Please check your entries and try again.')) | |
be5be115 | 206 | |
f6bc0336 SS |
207 | return render_to_response( |
208 | request, | |
209 | 'mediagoblin/user_pages/media_collect.html', | |
210 | {'media': media, | |
211 | 'form': form}) | |
212 | ||
213 | # If we are here, method=POST and the form is valid, submit things. | |
214 | # If the user is adding a new collection, use that: | |
c5d341d7 | 215 | if form.collection_title.data: |
f6bc0336 SS |
216 | # Make sure this user isn't duplicating an existing collection |
217 | existing_collection = Collection.query.filter_by( | |
218 | creator=request.user.id, | |
2263a4cb | 219 | title=form.collection_title.data).first() |
f6bc0336 SS |
220 | if existing_collection: |
221 | messages.add_message(request, messages.ERROR, | |
918d811a E |
222 | _('You already have a collection called "%s"!') |
223 | % existing_collection.title) | |
be5be115 | 224 | return redirect(request, "mediagoblin.user_pages.media_home", |
b7a3798e E |
225 | user=media.get_uploader.username, |
226 | media=media.slug_or_id) | |
be5be115 | 227 | |
f6bc0336 | 228 | collection = Collection() |
2263a4cb HL |
229 | collection.title = form.collection_title.data |
230 | collection.description = form.collection_description.data | |
f6bc0336 SS |
231 | collection.creator = request.user.id |
232 | collection.generate_slug() | |
b39d1f23 | 233 | collection.save() |
be5be115 | 234 | |
f6bc0336 SS |
235 | # Otherwise, use the collection selected from the drop-down |
236 | else: | |
e9330b95 E |
237 | collection = form.collection.data |
238 | if collection and collection.creator != request.user.id: | |
239 | collection = None | |
be5be115 | 240 | |
f6bc0336 SS |
241 | # Make sure the user actually selected a collection |
242 | if not collection: | |
243 | messages.add_message( | |
244 | request, messages.ERROR, | |
245 | _('You have to select or add a collection')) | |
ba5ea989 SS |
246 | return redirect(request, "mediagoblin.user_pages.media_collect", |
247 | user=media.get_uploader.username, | |
17e4679d | 248 | media_id=media.id) |
ba5ea989 | 249 | |
f6bc0336 SS |
250 | |
251 | # Check whether media already exists in collection | |
252 | elif CollectionItem.query.filter_by( | |
253 | media_entry=media.id, | |
254 | collection=collection.id).first(): | |
255 | messages.add_message(request, messages.ERROR, | |
918d811a E |
256 | _('"%s" already in collection "%s"') |
257 | % (media.title, collection.title)) | |
f6bc0336 | 258 | else: # Add item to collection |
6bea8a90 | 259 | add_media_to_collection(collection, media, form.note.data) |
f6bc0336 SS |
260 | |
261 | messages.add_message(request, messages.SUCCESS, | |
918d811a E |
262 | _('"%s" added to collection "%s"') |
263 | % (media.title, collection.title)) | |
f6bc0336 | 264 | |
2e6ee596 | 265 | return redirect_obj(request, media) |
f6bc0336 SS |
266 | |
267 | ||
268 | #TODO: Why does @user_may_delete_media not implicate @require_active_login? | |
461dd971 | 269 | @get_media_entry_by_id |
502073f2 JW |
270 | @require_active_login |
271 | @user_may_delete_media | |
272 | def media_confirm_delete(request, media): | |
273 | ||
111a609d | 274 | form = user_forms.ConfirmDeleteForm(request.form) |
502073f2 JW |
275 | |
276 | if request.method == 'POST' and form.validate(): | |
8daef28d | 277 | if form.confirm.data is True: |
05751758 | 278 | username = media.get_uploader.username |
fdc34b8b | 279 | # Delete MediaEntry and all related files, comments etc. |
502073f2 | 280 | media.delete() |
ea33f636 E |
281 | messages.add_message( |
282 | request, messages.SUCCESS, _('You deleted the media.')) | |
502073f2 JW |
283 | |
284 | return redirect(request, "mediagoblin.user_pages.user_home", | |
285 | user=username) | |
286 | else: | |
d0ba62e2 PUS |
287 | messages.add_message( |
288 | request, messages.ERROR, | |
56bfd91a | 289 | _("The media was not deleted because you didn't check that you were sure.")) |
2e6ee596 | 290 | return redirect_obj(request, media) |
502073f2 | 291 | |
bec591d8 | 292 | if ((request.user.is_admin and |
5c2b8486 | 293 | request.user.id != media.uploader)): |
7a4c0126 CAW |
294 | messages.add_message( |
295 | request, messages.WARNING, | |
296 | _("You are about to delete another user's media. " | |
297 | "Proceed with caution.")) | |
298 | ||
502073f2 JW |
299 | return render_to_response( |
300 | request, | |
301 | 'mediagoblin/user_pages/media_confirm_delete.html', | |
302 | {'media': media, | |
303 | 'form': form}) | |
304 | ||
305 | ||
e2ae0f59 | 306 | @active_user_from_url |
be5be115 | 307 | @uses_pagination |
e2ae0f59 | 308 | def user_collection(request, page, url_user=None): |
be5be115 | 309 | """A User-defined Collection""" |
e2ae0f59 SS |
310 | collection = Collection.query.filter_by( |
311 | get_creator=url_user, | |
312 | slug=request.matchdict['collection']).first() | |
be5be115 | 313 | |
61e39d90 JW |
314 | if not collection: |
315 | return render_404(request) | |
316 | ||
e2ae0f59 | 317 | cursor = collection.get_collection_items() |
be5be115 AW |
318 | |
319 | pagination = Pagination(page, cursor) | |
320 | collection_items = pagination() | |
321 | ||
e2ae0f59 SS |
322 | # if no data is available, return NotFound |
323 | # TODO: Should an empty collection really also return 404? | |
be5be115 AW |
324 | if collection_items == None: |
325 | return render_404(request) | |
326 | ||
327 | return render_to_response( | |
328 | request, | |
329 | 'mediagoblin/user_pages/collection.html', | |
e2ae0f59 | 330 | {'user': url_user, |
be5be115 AW |
331 | 'collection': collection, |
332 | 'collection_items': collection_items, | |
333 | 'pagination': pagination}) | |
334 | ||
335 | ||
b0cc1ade | 336 | @active_user_from_url |
4f8f0353 | 337 | def collection_list(request, url_user=None): |
b0cc1ade SZ |
338 | """A User-defined Collection""" |
339 | collections = Collection.query.filter_by( | |
340 | get_creator=url_user) | |
341 | ||
b0cc1ade SZ |
342 | return render_to_response( |
343 | request, | |
4f8f0353 | 344 | 'mediagoblin/user_pages/collection_list.html', |
b0cc1ade | 345 | {'user': url_user, |
947f38c0 | 346 | 'collections': collections}) |
b0cc1ade SZ |
347 | |
348 | ||
be5be115 AW |
349 | @get_user_collection_item |
350 | @require_active_login | |
351 | @user_may_alter_collection | |
352 | def collection_item_confirm_remove(request, collection_item): | |
353 | ||
111a609d | 354 | form = user_forms.ConfirmCollectionItemRemoveForm(request.form) |
be5be115 AW |
355 | |
356 | if request.method == 'POST' and form.validate(): | |
357 | username = collection_item.in_collection.get_creator.username | |
358 | collection = collection_item.in_collection | |
359 | ||
360 | if form.confirm.data is True: | |
361 | entry = collection_item.get_media_entry | |
362 | entry.collected = entry.collected - 1 | |
363 | entry.save() | |
364 | ||
365 | collection_item.delete() | |
6d1e55b2 | 366 | collection.items = collection.items - 1 |
be5be115 AW |
367 | collection.save() |
368 | ||
369 | messages.add_message( | |
370 | request, messages.SUCCESS, _('You deleted the item from the collection.')) | |
371 | else: | |
372 | messages.add_message( | |
373 | request, messages.ERROR, | |
374 | _("The item was not removed because you didn't check that you were sure.")) | |
375 | ||
2e6ee596 | 376 | return redirect_obj(request, collection) |
be5be115 AW |
377 | |
378 | if ((request.user.is_admin and | |
5c2b8486 | 379 | request.user.id != collection_item.in_collection.creator)): |
be5be115 AW |
380 | messages.add_message( |
381 | request, messages.WARNING, | |
382 | _("You are about to delete an item from another user's collection. " | |
383 | "Proceed with caution.")) | |
384 | ||
385 | return render_to_response( | |
386 | request, | |
387 | 'mediagoblin/user_pages/collection_item_confirm_remove.html', | |
388 | {'collection_item': collection_item, | |
389 | 'form': form}) | |
390 | ||
391 | ||
392 | @get_user_collection | |
393 | @require_active_login | |
394 | @user_may_alter_collection | |
395 | def collection_confirm_delete(request, collection): | |
396 | ||
111a609d | 397 | form = user_forms.ConfirmDeleteForm(request.form) |
be5be115 AW |
398 | |
399 | if request.method == 'POST' and form.validate(): | |
400 | ||
401 | username = collection.get_creator.username | |
402 | ||
403 | if form.confirm.data is True: | |
404 | collection_title = collection.title | |
405 | ||
406 | # Delete all the associated collection items | |
407 | for item in collection.get_collection_items(): | |
408 | entry = item.get_media_entry | |
409 | entry.collected = entry.collected - 1 | |
410 | entry.save() | |
411 | item.delete() | |
412 | ||
413 | collection.delete() | |
2041ceae E |
414 | messages.add_message(request, messages.SUCCESS, |
415 | _('You deleted the collection "%s"') % collection_title) | |
be5be115 AW |
416 | |
417 | return redirect(request, "mediagoblin.user_pages.user_home", | |
418 | user=username) | |
419 | else: | |
420 | messages.add_message( | |
421 | request, messages.ERROR, | |
422 | _("The collection was not deleted because you didn't check that you were sure.")) | |
423 | ||
2e6ee596 | 424 | return redirect_obj(request, collection) |
be5be115 AW |
425 | |
426 | if ((request.user.is_admin and | |
5c2b8486 | 427 | request.user.id != collection.creator)): |
be5be115 AW |
428 | messages.add_message( |
429 | request, messages.WARNING, | |
430 | _("You are about to delete another user's collection. " | |
431 | "Proceed with caution.")) | |
432 | ||
433 | return render_to_response( | |
434 | request, | |
435 | 'mediagoblin/user_pages/collection_confirm_delete.html', | |
436 | {'collection': collection, | |
437 | 'form': form}) | |
438 | ||
439 | ||
a5303e47 | 440 | ATOM_DEFAULT_NR_OF_UPDATED_ITEMS = 15 |
00c39256 | 441 | |
243c3843 | 442 | |
00c39256 BK |
443 | def atom_feed(request): |
444 | """ | |
445 | generates the atom feed with the newest images | |
446 | """ | |
2fb36dac SS |
447 | user = User.query.filter_by( |
448 | username = request.matchdict['user'], | |
449 | status = u'active').first() | |
00c39256 | 450 | if not user: |
de12b4e7 | 451 | return render_404(request) |
00c39256 | 452 | |
2fb36dac SS |
453 | cursor = MediaEntry.query.filter_by( |
454 | uploader = user.id, | |
455 | state = u'processed').\ | |
0efe9e27 | 456 | order_by(MediaEntry.created.desc()).\ |
2fb36dac | 457 | limit(ATOM_DEFAULT_NR_OF_UPDATED_ITEMS) |
00c39256 | 458 | |
1df68a35 MA |
459 | """ |
460 | ATOM feed id is a tag URI (see http://en.wikipedia.org/wiki/Tag_URI) | |
461 | """ | |
5b1a7bae MA |
462 | atomlinks = [{ |
463 | 'href': request.urlgen( | |
464 | 'mediagoblin.user_pages.user_home', | |
64712915 | 465 | qualified=True, user=request.matchdict['user']), |
5b1a7bae MA |
466 | 'rel': 'alternate', |
467 | 'type': 'text/html' | |
64712915 JW |
468 | }] |
469 | ||
bb025ebd MA |
470 | if mg_globals.app_config["push_urls"]: |
471 | for push_url in mg_globals.app_config["push_urls"]: | |
472 | atomlinks.append({ | |
473 | 'rel': 'hub', | |
474 | 'href': push_url}) | |
5b1a7bae | 475 | |
1df68a35 MA |
476 | feed = AtomFeed( |
477 | "MediaGoblin: Feed for user '%s'" % request.matchdict['user'], | |
00c39256 | 478 | feed_url=request.url, |
64712915 JW |
479 | id='tag:{host},{year}:gallery.user-{user}'.format( |
480 | host=request.host, | |
481 | year=datetime.datetime.today().strftime('%Y'), | |
482 | user=request.matchdict['user']), | |
5b1a7bae MA |
483 | links=atomlinks) |
484 | ||
00c39256 BK |
485 | for entry in cursor: |
486 | feed.add(entry.get('title'), | |
1e72e075 | 487 | entry.description_html, |
64712915 | 488 | id=entry.url_for_self(request.urlgen, qualified=True), |
00c39256 | 489 | content_type='html', |
1df68a35 MA |
490 | author={ |
491 | 'name': entry.get_uploader.username, | |
492 | 'uri': request.urlgen( | |
493 | 'mediagoblin.user_pages.user_home', | |
494 | qualified=True, user=entry.get_uploader.username)}, | |
00c39256 | 495 | updated=entry.get('created'), |
1df68a35 MA |
496 | links=[{ |
497 | 'href': entry.url_for_self( | |
498 | request.urlgen, | |
be5be115 AW |
499 | qualified=True), |
500 | 'rel': 'alternate', | |
501 | 'type': 'text/html'}]) | |
502 | ||
503 | return feed.get_response() | |
504 | ||
6d1e55b2 | 505 | |
be5be115 AW |
506 | def collection_atom_feed(request): |
507 | """ | |
508 | generates the atom feed with the newest images from a collection | |
509 | """ | |
2fb36dac SS |
510 | user = User.query.filter_by( |
511 | username = request.matchdict['user'], | |
512 | status = u'active').first() | |
be5be115 AW |
513 | if not user: |
514 | return render_404(request) | |
515 | ||
af008743 SS |
516 | collection = Collection.query.filter_by( |
517 | creator=user.id, | |
518 | slug=request.matchdict['collection']).first() | |
61e39d90 JW |
519 | if not collection: |
520 | return render_404(request) | |
be5be115 | 521 | |
af008743 SS |
522 | cursor = CollectionItem.query.filter_by( |
523 | collection=collection.id) \ | |
20be9bb7 | 524 | .order_by(CollectionItem.added.desc()) \ |
be5be115 AW |
525 | .limit(ATOM_DEFAULT_NR_OF_UPDATED_ITEMS) |
526 | ||
527 | """ | |
528 | ATOM feed id is a tag URI (see http://en.wikipedia.org/wiki/Tag_URI) | |
529 | """ | |
530 | atomlinks = [{ | |
fc45b386 | 531 | 'href': collection.url_for_self(request.urlgen, qualified=True), |
be5be115 AW |
532 | 'rel': 'alternate', |
533 | 'type': 'text/html' | |
534 | }] | |
535 | ||
536 | if mg_globals.app_config["push_urls"]: | |
537 | for push_url in mg_globals.app_config["push_urls"]: | |
538 | atomlinks.append({ | |
539 | 'rel': 'hub', | |
540 | 'href': push_url}) | |
541 | ||
542 | feed = AtomFeed( | |
19ad2e0c JW |
543 | "MediaGoblin: Feed for %s's collection %s" % |
544 | (request.matchdict['user'], collection.title), | |
545 | feed_url=request.url, | |
ab9b0b41 | 546 | id=u'tag:{host},{year}:gnu-mediagoblin.{user}.collection.{slug}'\ |
19ad2e0c JW |
547 | .format( |
548 | host=request.host, | |
549 | year=collection.created.strftime('%Y'), | |
550 | user=request.matchdict['user'], | |
551 | slug=collection.slug), | |
552 | links=atomlinks) | |
be5be115 AW |
553 | |
554 | for item in cursor: | |
555 | entry = item.get_media_entry | |
556 | feed.add(entry.get('title'), | |
557 | item.note_html, | |
558 | id=entry.url_for_self(request.urlgen, qualified=True), | |
559 | content_type='html', | |
560 | author={ | |
561 | 'name': entry.get_uploader.username, | |
562 | 'uri': request.urlgen( | |
563 | 'mediagoblin.user_pages.user_home', | |
564 | qualified=True, user=entry.get_uploader.username)}, | |
565 | updated=item.get('added'), | |
566 | links=[{ | |
567 | 'href': entry.url_for_self( | |
568 | request.urlgen, | |
1df68a35 MA |
569 | qualified=True), |
570 | 'rel': 'alternate', | |
571 | 'type': 'text/html'}]) | |
00c39256 | 572 | |
9074ee7c | 573 | return feed.get_response() |
01c75c7e CAW |
574 | |
575 | ||
576 | @require_active_login | |
577 | def processing_panel(request): | |
578 | """ | |
579 | Show to the user what media is still in conversion/processing... | |
580 | and what failed, and why! | |
581 | """ | |
af008743 SS |
582 | user = User.query.filter_by(username=request.matchdict['user']).first() |
583 | # TODO: XXX: Should this be a decorator? | |
01c75c7e CAW |
584 | # |
585 | # Make sure we have permission to access this user's panel. Only | |
586 | # admins and this user herself should be able to do so. | |
dfc23dd1 | 587 | if not (user.id == request.user.id or request.user.is_admin): |
af008743 | 588 | # No? Simply redirect to this user's homepage. |
01c75c7e CAW |
589 | return redirect( |
590 | request, 'mediagoblin.user_pages.user_home', | |
af008743 | 591 | user=user.username) |
01c75c7e CAW |
592 | |
593 | # Get media entries which are in-processing | |
af008743 | 594 | processing_entries = MediaEntry.query.\ |
2fb36dac SS |
595 | filter_by(uploader = user.id, |
596 | state = u'processing').\ | |
af008743 | 597 | order_by(MediaEntry.created.desc()) |
01c75c7e CAW |
598 | |
599 | # Get media entries which have failed to process | |
af008743 | 600 | failed_entries = MediaEntry.query.\ |
2fb36dac SS |
601 | filter_by(uploader = user.id, |
602 | state = u'failed').\ | |
af008743 SS |
603 | order_by(MediaEntry.created.desc()) |
604 | ||
605 | processed_entries = MediaEntry.query.\ | |
2fb36dac SS |
606 | filter_by(uploader = user.id, |
607 | state = u'processed').\ | |
af008743 SS |
608 | order_by(MediaEntry.created.desc()).\ |
609 | limit(10) | |
64712915 | 610 | |
01c75c7e CAW |
611 | # Render to response |
612 | return render_to_response( | |
613 | request, | |
614 | 'mediagoblin/user_pages/processing_panel.html', | |
615 | {'user': user, | |
616 | 'processing_entries': processing_entries, | |
64712915 JW |
617 | 'failed_entries': failed_entries, |
618 | 'processed_entries': processed_entries}) |