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