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