diff options
Diffstat (limited to 'mediagoblin/user_pages/views.py')
-rw-r--r-- | mediagoblin/user_pages/views.py | 346 |
1 files changed, 221 insertions, 125 deletions
diff --git a/mediagoblin/user_pages/views.py b/mediagoblin/user_pages/views.py index 78751a28..eaae1bd7 100644 --- a/mediagoblin/user_pages/views.py +++ b/mediagoblin/user_pages/views.py @@ -18,14 +18,19 @@ import logging import datetime import json +import six + from mediagoblin import messages, mg_globals -from mediagoblin.db.models import (MediaEntry, MediaTag, Collection, - CollectionItem, User) +from mediagoblin.db.models import (MediaEntry, MediaTag, Collection, Comment, + CollectionItem, LocalUser, Activity, \ + GenericModelReference) +from mediagoblin.plugins.api.tools import get_media_file_paths from mediagoblin.tools.response import render_to_response, render_404, \ redirect, redirect_obj from mediagoblin.tools.text import cleaned_markdown_conversion from mediagoblin.tools.translate import pass_to_ugettext as _ from mediagoblin.tools.pagination import Pagination +from mediagoblin.tools.federation import create_activity from mediagoblin.user_pages import forms as user_forms from mediagoblin.user_pages.lib import (send_comment_email, add_media_to_collection, build_report_object) @@ -50,8 +55,8 @@ _log.setLevel(logging.DEBUG) @user_not_banned @uses_pagination def user_home(request, page): - """'Homepage' of a User()""" - user = User.query.filter_by(username=request.matchdict['user']).first() + """'Homepage' of a LocalUser()""" + user = LocalUser.query.filter_by(username=request.matchdict['user']).first() if not user: return render_404(request) elif not user.has_privilege(u'active'): @@ -61,7 +66,7 @@ def user_home(request, page): {'user': user}) cursor = MediaEntry.query.\ - filter_by(uploader = user.id, + filter_by(actor = user.id, state = u'processed').order_by(MediaEntry.created.desc()) pagination = Pagination(page, cursor) @@ -87,10 +92,10 @@ def user_home(request, page): @active_user_from_url @uses_pagination def user_gallery(request, page, url_user=None): - """'Gallery' of a User()""" + """'Gallery' of a LocalUser()""" tag = request.matchdict.get('tag', None) cursor = MediaEntry.query.filter_by( - uploader=url_user.id, + actor=url_user.id, state=u'processed').order_by(MediaEntry.created.desc()) # Filter potentially by tag too: @@ -175,10 +180,9 @@ def media_post_comment(request, media): if not request.method == 'POST': raise MethodNotAllowed() - comment = request.db.MediaComment() - comment.media_entry = media.id - comment.author = request.user.id - comment.content = unicode(request.form['comment_content']) + comment = request.db.TextComment() + comment.actor = request.user.id + comment.content = six.text_type(request.form['comment_content']) # Show error message if commenting is disabled. if not mg_globals.app_config['allow_comments']: @@ -192,15 +196,20 @@ def media_post_comment(request, media): messages.ERROR, _("Oops, your comment was empty.")) else: + create_activity("post", comment, comment.actor, target=media) + add_comment_subscription(request.user, media) comment.save() + link = request.db.Comment() + link.target = media + link.comment = comment + link.save() + messages.add_message( - request, messages.SUCCESS, + request, + messages.SUCCESS, _('Your comment has been posted!')) - - trigger_notification(comment, media, request) - - add_comment_subscription(request.user, media) + trigger_notification(link, media, request) return redirect_obj(request, media) @@ -212,7 +221,7 @@ def media_preview_comment(request): if not request.is_xhr: return render_404(request) - comment = unicode(request.form['comment_content']) + comment = six.text_type(request.form['comment_content']) cleancomment = { "content":cleaned_markdown_conversion(comment)} return Response(json.dumps(cleancomment)) @@ -226,12 +235,16 @@ def media_collect(request, media): form = user_forms.MediaCollectForm(request.form) # A user's own collections: form.collection.query = Collection.query.filter_by( - creator = request.user.id).order_by(Collection.title) + actor=request.user.id, + type=Collection.USER_DEFINED_TYPE + ).order_by(Collection.title) if request.method != 'POST' or not form.validate(): # No POST submission, or invalid form if not form.validate(): - messages.add_message(request, messages.ERROR, + messages.add_message( + request, + messages.ERROR, _('Please check your entries and try again.')) return render_to_response( @@ -245,52 +258,67 @@ def media_collect(request, media): if form.collection_title.data: # Make sure this user isn't duplicating an existing collection existing_collection = Collection.query.filter_by( - creator=request.user.id, - title=form.collection_title.data).first() + actor=request.user.id, + title=form.collection_title.data, + type=Collection.USER_DEFINED_TYPE + ).first() if existing_collection: - messages.add_message(request, messages.ERROR, - _('You already have a collection called "%s"!') - % existing_collection.title) + messages.add_message( + request, + messages.ERROR, + _('You already have a collection called "%s"!') % + existing_collection.title) return redirect(request, "mediagoblin.user_pages.media_home", - user=media.get_uploader.username, + user=media.get_actor.username, media=media.slug_or_id) collection = Collection() collection.title = form.collection_title.data collection.description = form.collection_description.data - collection.creator = request.user.id + collection.actor = request.user.id + collection.type = Collection.USER_DEFINED_TYPE collection.generate_slug() + collection.get_public_id(request.urlgen) + create_activity("create", collection, collection.actor) collection.save() # Otherwise, use the collection selected from the drop-down else: collection = form.collection.data - if collection and collection.creator != request.user.id: + if collection and collection.actor != request.user.id: collection = None # Make sure the user actually selected a collection + item = CollectionItem.query.filter_by(collection=collection.id) + item = item.join(CollectionItem.object_helper).filter_by( + model_type=media.__tablename__, + obj_pk=media.id + ).first() + if not collection: messages.add_message( - request, messages.ERROR, + request, + messages.ERROR, _('You have to select or add a collection')) return redirect(request, "mediagoblin.user_pages.media_collect", - user=media.get_uploader.username, + user=media.get_actor.username, media_id=media.id) - # Check whether media already exists in collection - elif CollectionItem.query.filter_by( - media_entry=media.id, - collection=collection.id).first(): - messages.add_message(request, messages.ERROR, - _('"%s" already in collection "%s"') - % (media.title, collection.title)) + elif item is not None: + messages.add_message( + request, + messages.ERROR, + _('"%s" already in collection "%s"') % + (media.title, collection.title)) else: # Add item to collection add_media_to_collection(collection, media, form.note.data) - - messages.add_message(request, messages.SUCCESS, - _('"%s" added to collection "%s"') - % (media.title, collection.title)) + create_activity("add", media, request.user, target=collection) + messages.add_message( + request, + messages.SUCCESS, + _('"%s" added to collection "%s"') % + (media.title, collection.title)) return redirect_obj(request, media) @@ -305,16 +333,24 @@ def media_confirm_delete(request, media): if request.method == 'POST' and form.validate(): if form.confirm.data is True: - username = media.get_uploader.username + username = media.get_actor.username + + # This probably is already filled but just in case it has slipped + # through the net somehow, we need to try and make sure the + # MediaEntry has a public ID so it gets properly soft-deleted. + media.get_public_id(request.urlgen) - media.get_uploader.uploaded = media.get_uploader.uploaded - \ + # Decrement the users uploaded quota. + media.get_actor.uploaded = media.get_actor.uploaded - \ media.file_size - media.get_uploader.save() + media.get_actor.save() # Delete MediaEntry and all related files, comments etc. media.delete() messages.add_message( - request, messages.SUCCESS, _('You deleted the media.')) + request, + messages.SUCCESS, + _('You deleted the media.')) location = media.url_to_next(request.urlgen) if not location: @@ -325,14 +361,17 @@ def media_confirm_delete(request, media): return redirect(request, location=location) else: messages.add_message( - request, messages.ERROR, - _("The media was not deleted because you didn't check that you were sure.")) + request, + messages.ERROR, + _("The media was not deleted because you didn't check " + "that you were sure.")) return redirect_obj(request, media) if ((request.user.has_privilege(u'admin') and - request.user.id != media.uploader)): + request.user.id != media.actor)): messages.add_message( - request, messages.WARNING, + request, + messages.WARNING, _("You are about to delete another user's media. " "Proceed with caution.")) @@ -348,7 +387,7 @@ def media_confirm_delete(request, media): def user_collection(request, page, url_user=None): """A User-defined Collection""" collection = Collection.query.filter_by( - get_creator=url_user, + get_actor=url_user, slug=request.matchdict['collection']).first() if not collection: @@ -377,7 +416,7 @@ def user_collection(request, page, url_user=None): def collection_list(request, url_user=None): """A User-defined Collection""" collections = Collection.query.filter_by( - get_creator=url_user) + get_actor=url_user) return render_to_response( request, @@ -394,30 +433,35 @@ def collection_item_confirm_remove(request, collection_item): form = user_forms.ConfirmCollectionItemRemoveForm(request.form) if request.method == 'POST' and form.validate(): - username = collection_item.in_collection.get_creator.username + username = collection_item.in_collection.get_actor.username collection = collection_item.in_collection if form.confirm.data is True: - entry = collection_item.get_media_entry - entry.save() + obj = collection_item.get_object() + obj.save() collection_item.delete() - collection.items = collection.items - 1 + collection.num_items = collection.num_items - 1 collection.save() messages.add_message( - request, messages.SUCCESS, _('You deleted the item from the collection.')) + request, + messages.SUCCESS, + _('You deleted the item from the collection.')) else: messages.add_message( - request, messages.ERROR, - _("The item was not removed because you didn't check that you were sure.")) + request, + messages.ERROR, + _("The item was not removed because you didn't check " + "that you were sure.")) return redirect_obj(request, collection) if ((request.user.has_privilege(u'admin') and - request.user.id != collection_item.in_collection.creator)): + request.user.id != collection_item.in_collection.actor)): messages.add_message( - request, messages.WARNING, + request, + messages.WARNING, _("You are about to delete an item from another user's collection. " "Proceed with caution.")) @@ -437,32 +481,41 @@ def collection_confirm_delete(request, collection): if request.method == 'POST' and form.validate(): - username = collection.get_creator.username + username = collection.get_actor.username if form.confirm.data is True: collection_title = collection.title + # Firstly like with the MediaEntry delete, lets ensure the + # public_id is populated as this is really important! + collection.get_public_id(request.urlgen) + # Delete all the associated collection items for item in collection.get_collection_items(): - entry = item.get_media_entry - entry.save() + obj = item.get_object() + obj.save() item.delete() collection.delete() - messages.add_message(request, messages.SUCCESS, - _('You deleted the collection "%s"') % collection_title) + messages.add_message( + request, + messages.SUCCESS, + _('You deleted the collection "%s"') % + collection_title) return redirect(request, "mediagoblin.user_pages.user_home", user=username) else: messages.add_message( - request, messages.ERROR, - _("The collection was not deleted because you didn't check that you were sure.")) + request, + messages.ERROR, + _("The collection was not deleted because you didn't " + "check that you were sure.")) return redirect_obj(request, collection) if ((request.user.has_privilege(u'admin') and - request.user.id != collection.creator)): + request.user.id != collection.actor)): messages.add_message( request, messages.WARNING, _("You are about to delete another user's collection. " @@ -482,27 +535,25 @@ def atom_feed(request): """ generates the atom feed with the newest images """ - user = User.query.filter_by( + user = LocalUser.query.filter_by( username = request.matchdict['user']).first() if not user or not user.has_privilege(u'active'): return render_404(request) + feed_title = "MediaGoblin Feed for user '%s'" % request.matchdict['user'] + link = request.urlgen('mediagoblin.user_pages.user_home', + qualified=True, user=request.matchdict['user']) + cursor = MediaEntry.query.filter_by(actor=user.id, state=u'processed') + cursor = cursor.order_by(MediaEntry.created.desc()) + cursor = cursor.limit(ATOM_DEFAULT_NR_OF_UPDATED_ITEMS) - cursor = MediaEntry.query.filter_by( - uploader = user.id, - state = u'processed').\ - order_by(MediaEntry.created.desc()).\ - limit(ATOM_DEFAULT_NR_OF_UPDATED_ITEMS) """ ATOM feed id is a tag URI (see http://en.wikipedia.org/wiki/Tag_URI) """ atomlinks = [{ - 'href': request.urlgen( - 'mediagoblin.user_pages.user_home', - qualified=True, user=request.matchdict['user']), - 'rel': 'alternate', - 'type': 'text/html' - }] + 'href': link, + 'rel': 'alternate', + 'type': 'text/html'}] if mg_globals.app_config["push_urls"]: for push_url in mg_globals.app_config["push_urls"]: @@ -511,24 +562,34 @@ def atom_feed(request): 'href': push_url}) feed = AtomFeed( - "MediaGoblin: Feed for user '%s'" % request.matchdict['user'], - feed_url=request.url, - id='tag:{host},{year}:gallery.user-{user}'.format( - host=request.host, - year=datetime.datetime.today().strftime('%Y'), - user=request.matchdict['user']), - links=atomlinks) + feed_title, + feed_url=request.url, + id='tag:{host},{year}:gallery.user-{user}'.format( + host=request.host, + year=datetime.datetime.today().strftime('%Y'), + user=request.matchdict['user']), + links=atomlinks) for entry in cursor: - feed.add(entry.get('title'), - entry.description_html, + # Include a thumbnail image in content. + file_urls = get_media_file_paths(entry.media_files, request.urlgen) + if 'thumb' in file_urls: + content = '<img src="{thumb}" alt='' /> {desc}'.format( + thumb=file_urls['thumb'], desc=entry.description_html) + else: + content = entry.description_html + + feed.add( + entry.get('title'), + content, id=entry.url_for_self(request.urlgen, qualified=True), content_type='html', author={ - 'name': entry.get_uploader.username, + 'name': entry.get_actor.username, 'uri': request.urlgen( 'mediagoblin.user_pages.user_home', - qualified=True, user=entry.get_uploader.username)}, + qualified=True, + user=entry.get_actor.username)}, updated=entry.get('created'), links=[{ 'href': entry.url_for_self( @@ -544,13 +605,13 @@ def collection_atom_feed(request): """ generates the atom feed with the newest images from a collection """ - user = User.query.filter_by( + user = LocalUser.query.filter_by( username = request.matchdict['user']).first() if not user or not user.has_privilege(u'active'): return render_404(request) collection = Collection.query.filter_by( - creator=user.id, + actor=user.id, slug=request.matchdict['collection']).first() if not collection: return render_404(request) @@ -588,19 +649,20 @@ def collection_atom_feed(request): links=atomlinks) for item in cursor: - entry = item.get_media_entry - feed.add(entry.get('title'), + obj = item.get_object() + feed.add( + obj.get('title'), item.note_html, - id=entry.url_for_self(request.urlgen, qualified=True), + id=obj.url_for_self(request.urlgen, qualified=True), content_type='html', author={ - 'name': entry.get_uploader.username, + 'name': obj.get_actor.username, 'uri': request.urlgen( 'mediagoblin.user_pages.user_home', - qualified=True, user=entry.get_uploader.username)}, + qualified=True, user=obj.get_actor.username)}, updated=item.get('added'), links=[{ - 'href': entry.url_for_self( + 'href': obj.url_for_self( request.urlgen, qualified=True), 'rel': 'alternate', @@ -608,13 +670,15 @@ def collection_atom_feed(request): return feed.get_response() +@active_user_from_url +@uses_pagination @require_active_login -def processing_panel(request): +def processing_panel(request, page, url_user): """ Show to the user what media is still in conversion/processing... and what failed, and why! """ - user = User.query.filter_by(username=request.matchdict['user']).first() + user = LocalUser.query.filter_by(username=request.matchdict['user']).first() # TODO: XXX: Should this be a decorator? # # Make sure we have permission to access this user's panel. Only @@ -624,33 +688,29 @@ def processing_panel(request): return redirect( request, 'mediagoblin.user_pages.user_home', user=user.username) - # Get media entries which are in-processing - processing_entries = MediaEntry.query.\ - filter_by(uploader = user.id, - state = u'processing').\ - order_by(MediaEntry.created.desc()) - - # Get media entries which have failed to process - failed_entries = MediaEntry.query.\ - filter_by(uploader = user.id, - state = u'failed').\ - order_by(MediaEntry.created.desc()) - - processed_entries = MediaEntry.query.\ - filter_by(uploader = user.id, - state = u'processed').\ - order_by(MediaEntry.created.desc()).\ - limit(10) + entries = (MediaEntry.query.filter_by(actor=user.id) + .order_by(MediaEntry.created.desc())) + + try: + state = request.matchdict['state'] + # no exception was thrown, filter entries by state + entries = entries.filter_by(state=state) + except KeyError: + # show all entries + pass + + pagination = Pagination(page, entries) + pagination.per_page = 30 + entries_on_a_page = pagination() # Render to response return render_to_response( request, 'mediagoblin/user_pages/processing_panel.html', {'user': user, - 'processing_entries': processing_entries, - 'failed_entries': failed_entries, - 'processed_entries': processed_entries}) + 'entries': entries_on_a_page, + 'pagination': pagination}) @allow_reporting @get_user_media_entry @@ -658,14 +718,14 @@ def processing_panel(request): @get_optional_media_comment_by_id def file_a_report(request, media, comment): """ - This view handles the filing of a MediaReport or a CommentReport. + This view handles the filing of a Report. """ if comment is not None: - if not comment.get_media_entry.id == media.id: + if not comment.target().id == media.id: return render_404(request) form = user_forms.CommentReportForm(request.form) - context = {'media': media, + context = {'media': comment.target(), 'comment':comment, 'form':form} else: @@ -676,9 +736,11 @@ def file_a_report(request, media, comment): if request.method == "POST": - report_object = build_report_object(form, + report_object = build_report_object( + form, media_entry=media, - comment=comment) + comment=comment + ) # if the object was built successfully, report_table will not be None if report_object: @@ -692,3 +754,37 @@ def file_a_report(request, media, comment): request, 'mediagoblin/user_pages/report.html', context) + +@require_active_login +def activity_view(request): + """ /<username>/activity/<id> - Display activity + + This should display a HTML presentation of the activity + this is NOT an API endpoint. + """ + # Get the user object. + username = request.matchdict["username"] + user = LocalUser.query.filter_by(username=username).first() + + activity_id = request.matchdict["id"] + + if request.user is None: + return render_404(request) + + activity = Activity.query.filter_by( + id=activity_id, + author=user.id + ).first() + + # There isn't many places to check that the public_id is filled so this + # will do, it really should be, lets try and fix that if it isn't. + activity.get_public_id(request.urlgen) + + if activity is None: + return render_404(request) + + return render_to_response( + request, + "mediagoblin/api/activity.html", + {"activity": activity} + ) |