diff options
Diffstat (limited to 'mediagoblin/submit')
-rw-r--r-- | mediagoblin/submit/forms.py | 11 | ||||
-rw-r--r-- | mediagoblin/submit/lib.py | 83 | ||||
-rwxr-xr-x | mediagoblin/submit/task.py | 38 | ||||
-rw-r--r-- | mediagoblin/submit/views.py | 78 |
4 files changed, 161 insertions, 49 deletions
diff --git a/mediagoblin/submit/forms.py b/mediagoblin/submit/forms.py index 6c0e8e9c..69d211e6 100644 --- a/mediagoblin/submit/forms.py +++ b/mediagoblin/submit/forms.py @@ -16,7 +16,7 @@ import wtforms - +from wtforms.ext.sqlalchemy.fields import QuerySelectField from mediagoblin import mg_globals from mediagoblin.tools.text import tag_length_validator from mediagoblin.tools.translate import lazy_pass_to_ugettext as _ @@ -33,7 +33,7 @@ def get_submit_start_form(form, **kwargs): file = wtforms.FileField( _('File'), description=desc) - title = wtforms.TextField( + title = wtforms.StringField( _('Title'), [wtforms.validators.Length(min=0, max=500)]) description = wtforms.TextAreaField( @@ -41,7 +41,7 @@ def get_submit_start_form(form, **kwargs): description=_("""You can use <a href="http://daringfireball.net/projects/markdown/basics"> Markdown</a> for formatting.""")) - tags = wtforms.TextField( + tags = wtforms.StringField( _('Tags'), [tag_length_validator], description=_( @@ -50,6 +50,9 @@ def get_submit_start_form(form, **kwargs): _('License'), [wtforms.validators.Optional(),], choices=licenses_as_choices()) + collection = QuerySelectField( + _('Collection'), + allow_blank=True, blank_text=_('-- Select --'), get_label='title',) max_file_size = wtforms.HiddenField('') upload_limit = wtforms.HiddenField('') uploaded = wtforms.HiddenField('') @@ -57,7 +60,7 @@ def get_submit_start_form(form, **kwargs): return SubmitStartForm(form, **kwargs) class AddCollectionForm(wtforms.Form): - title = wtforms.TextField( + title = wtforms.StringField( _('Title'), [wtforms.validators.Length(min=0, max=500), wtforms.validators.InputRequired()]) description = wtforms.TextAreaField( diff --git a/mediagoblin/submit/lib.py b/mediagoblin/submit/lib.py index d54591d6..08a603e9 100644 --- a/mediagoblin/submit/lib.py +++ b/mediagoblin/submit/lib.py @@ -18,11 +18,15 @@ import logging import uuid from os.path import splitext +import six + from werkzeug.utils import secure_filename from werkzeug.datastructures import FileStorage from mediagoblin import mg_globals +from mediagoblin.tools.response import json_response from mediagoblin.tools.text import convert_to_tag_list_of_dicts +from mediagoblin.tools.federation import create_activity, create_generator from mediagoblin.db.models import Collection, MediaEntry, ProcessingMetaData from mediagoblin.processing import mark_entry_failed from mediagoblin.processing.task import ProcessMedia @@ -49,7 +53,7 @@ def new_upload_entry(user): Create a new MediaEntry for uploading """ entry = MediaEntry() - entry.uploader = user.id + entry.actor = user.id entry.license = user.license_preference return entry @@ -58,7 +62,7 @@ def get_upload_file_limits(user): """ Get the upload_limit and max_file_size for this user """ - if user.upload_limit >= 0: + if user.upload_limit is not None and user.upload_limit >= 0: # TODO: debug this upload_limit = user.upload_limit else: upload_limit = mg_globals.app_config.get('upload_limit', None) @@ -100,10 +104,7 @@ class UserPastUploadLimit(UploadLimitError): def submit_media(mg_app, user, submitted_file, filename, title=None, description=None, collection_slug=None, license=None, metadata=None, tags_string=u"", - upload_limit=None, max_file_size=None, - callback_url=None, - # If provided we'll do the feed_url update, otherwise ignore - urlgen=None,): + callback_url=None, urlgen=None,): """ Args: - mg_app: The MediaGoblinApp instantiated for this process @@ -119,17 +120,17 @@ def submit_media(mg_app, user, submitted_file, filename, - license: license for this media entry - tags_string: comma separated string of tags to be associated with this entry - - upload_limit: size in megabytes that's the per-user upload limit - - max_file_size: maximum size each file can be that's uploaded - callback_url: possible post-hook to call after submission - - urlgen: if provided, used to do the feed_url update + - urlgen: if provided, used to do the feed_url update and assign a public + ID used in the API (very important). """ + upload_limit, max_file_size = get_upload_file_limits(user) if upload_limit and user.uploaded >= upload_limit: raise UserPastUploadLimit() # If the filename contains non ascii generate a unique name if not all(ord(c) < 128 for c in filename): - filename = unicode(uuid.uuid4()) + splitext(filename)[-1] + filename = six.text_type(uuid.uuid4()) + splitext(filename)[-1] # Sniff the submitted media to determine which # media plugin should handle processing @@ -138,7 +139,7 @@ def submit_media(mg_app, user, submitted_file, filename, # create entry and save in database entry = new_upload_entry(user) entry.media_type = media_type - entry.title = (title or unicode(splitext(filename)[0])) + entry.title = (title or six.text_type(splitext(filename)[0])) entry.description = description or u"" @@ -155,7 +156,7 @@ def submit_media(mg_app, user, submitted_file, filename, queue_file = prepare_queue_task(mg_app, entry, filename) with queue_file: - queue_file.write(submitted_file.read()) + queue_file.write(submitted_file) # Get file size and round to 2 decimal places file_size = mg_app.queue_store.get_file_size( @@ -187,15 +188,27 @@ def submit_media(mg_app, user, submitted_file, filename, metadata.save() if urlgen: + # Generate the public_id, this is very importent, especially relating + # to deletion, it allows the shell to be accessable post-delete! + entry.get_public_id(urlgen) + + # Generate the feed URL feed_url = urlgen( 'mediagoblin.user_pages.atom_feed', qualified=True, user=user.username) else: feed_url = None + add_comment_subscription(user, entry) + + # Create activity + create_activity("post", entry, entry.actor) + entry.save() + # add to collection if collection_slug: - collection = Collection.query.filter_by(slug=collection_slug, creator=user.id).first() + collection = Collection.query.filter_by(slug=collection_slug, + actor=user.id).first() if collection: add_media_to_collection(collection, entry) @@ -205,8 +218,6 @@ def submit_media(mg_app, user, submitted_file, filename, # conditions with changes to the document via processing code) run_process_media(entry, feed_url) - add_comment_subscription(user, entry) - return entry @@ -220,7 +231,7 @@ def prepare_queue_task(app, entry, filename): # (If we got it off the task's auto-generation, there'd be # a risk of a race condition when we'd save after sending # off the task) - task_id = unicode(uuid.uuid4()) + task_id = six.text_type(uuid.uuid4()) entry.queued_task_id = task_id # Now store generate the queueing related filename @@ -267,3 +278,43 @@ def run_process_media(entry, feed_url=None, mark_entry_failed(entry.id, exc) # re-raise the exception raise + + +def api_upload_request(request, file_data, entry): + """ This handles a image upload request """ + # Use the same kind of method from mediagoblin/submit/views:submit_start + entry.title = file_data.filename + + # This will be set later but currently we just don't have enough information + entry.slug = None + + # This is a MUST. + entry.get_public_id(request.urlgen) + + queue_file = prepare_queue_task(request.app, entry, file_data.filename) + with queue_file: + queue_file.write(request.data) + + entry.save() + return json_response(entry.serialize(request)) + +def api_add_to_feed(request, entry): + """ Add media to Feed """ + feed_url = request.urlgen( + 'mediagoblin.user_pages.atom_feed', + qualified=True, user=request.user.username + ) + + add_comment_subscription(request.user, entry) + + # Create activity + activity = create_activity( + verb="post", + obj=entry, + actor=entry.actor, + generator=create_generator(request) + ) + entry.save() + run_process_media(entry, feed_url) + + return activity diff --git a/mediagoblin/submit/task.py b/mediagoblin/submit/task.py new file mode 100755 index 00000000..4ebde502 --- /dev/null +++ b/mediagoblin/submit/task.py @@ -0,0 +1,38 @@ +# GNU MediaGoblin -- federated, autonomous media hosting +# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +import celery +import datetime +import pytz + +from mediagoblin.db.models import MediaEntry + +@celery.task() +def collect_garbage(): + """ + Garbage collection to clean up media + + This will look for all critera on models to clean + up. This is primerally written to clean up media that's + entered a erroneous state. + """ + cuttoff = datetime.datetime.now(pytz.UTC) - datetime.timedelta(days=1) + + garbage = MediaEntry.query.filter(MediaEntry.created < cuttoff) + garbage = garbage.filter(MediaEntry.state == "unprocessed") + + for entry in garbage.all(): + entry.delete() diff --git a/mediagoblin/submit/views.py b/mediagoblin/submit/views.py index 42c378a8..7bbfb645 100644 --- a/mediagoblin/submit/views.py +++ b/mediagoblin/submit/views.py @@ -14,6 +14,8 @@ # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see <http://www.gnu.org/licenses/>. +import six + from mediagoblin import messages import mediagoblin.mg_globals as mg_globals @@ -21,17 +23,17 @@ import logging _log = logging.getLogger(__name__) - +from mediagoblin.db.models import Collection +from mediagoblin.tools.federation import create_activity from mediagoblin.tools.translate import pass_to_ugettext as _ from mediagoblin.tools.response import render_to_response, redirect from mediagoblin.decorators import require_active_login, user_has_privilege from mediagoblin.submit import forms as submit_forms -from mediagoblin.messages import add_message, SUCCESS -from mediagoblin.media_types import \ - InvalidFileType, FileTypeNotSupported +from mediagoblin.media_types import FileTypeNotSupported from mediagoblin.submit.lib import \ check_file_field, submit_media, get_upload_file_limits, \ FileUploadLimit, UserUploadLimit, UserPastUploadLimit +from mediagoblin.user_pages.lib import add_media_to_collection @require_active_login @@ -48,6 +50,17 @@ def submit_start(request): max_file_size=max_file_size, upload_limit=upload_limit, uploaded=request.user.uploaded) + users_collections = Collection.query.filter_by( + actor=request.user.id, + type=Collection.USER_DEFINED_TYPE + ).order_by(Collection.title) + + # Only show the Collections dropdown if the user has some + # collections set up + if users_collections.count() > 0: + submit_form.collection.query = users_collections + else: + del submit_form.collection if request.method == 'POST' and submit_form.validate(): if not check_file_field(request, 'file'): @@ -55,18 +68,27 @@ def submit_start(request): _(u'You must provide a file.')) else: try: - submit_media( + media = submit_media( mg_app=request.app, user=request.user, submitted_file=request.files['file'], filename=request.files['file'].filename, - title=unicode(submit_form.title.data), - description=unicode(submit_form.description.data), - license=unicode(submit_form.license.data) or None, + title=six.text_type(submit_form.title.data), + description=six.text_type(submit_form.description.data), + license=six.text_type(submit_form.license.data) or None, tags_string=submit_form.tags.data, - upload_limit=upload_limit, max_file_size=max_file_size, urlgen=request.urlgen) - add_message(request, SUCCESS, _('Woohoo! Submitted!')) + if submit_form.collection and submit_form.collection.data: + add_media_to_collection( + submit_form.collection.data, media) + create_activity( + "add", media, request.user, + target=submit_form.collection.data) + + messages.add_message( + request, + messages.SUCCESS, + _('Woohoo! Submitted!')) return redirect(request, "mediagoblin.user_pages.user_home", user=request.user.username) @@ -87,18 +109,10 @@ def submit_start(request): _('Sorry, you have reached your upload limit.')) return redirect(request, "mediagoblin.user_pages.user_home", user=request.user.username) - + except FileTypeNotSupported as e: + submit_form.file.errors.append(e) except Exception as e: - ''' - This section is intended to catch exceptions raised in - mediagoblin.media_types - ''' - if isinstance(e, InvalidFileType) or \ - isinstance(e, FileTypeNotSupported): - submit_form.file.errors.append( - e) - else: - raise + raise return render_to_response( request, @@ -117,24 +131,30 @@ def add_collection(request, media=None): if request.method == 'POST' and submit_form.validate(): collection = request.db.Collection() - collection.title = unicode(submit_form.title.data) - collection.description = unicode(submit_form.description.data) - collection.creator = request.user.id + collection.title = six.text_type(submit_form.title.data) + collection.description = six.text_type(submit_form.description.data) + collection.actor = request.user.id + collection.type = request.db.Collection.USER_DEFINED_TYPE collection.generate_slug() # Make sure this user isn't duplicating an existing collection existing_collection = request.db.Collection.query.filter_by( - creator=request.user.id, + actor=request.user.id, + type=request.db.Collection.USER_DEFINED_TYPE, title=collection.title).first() if existing_collection: - add_message(request, messages.ERROR, - _('You already have a collection called "%s"!') \ - % collection.title) + messages.add_message( + request, + messages.ERROR, + _('You already have a collection called "%s"!') % + collection.title) else: collection.save() - add_message(request, SUCCESS, + messages.add_message( + request, + messages.SUCCESS, _('Collection "%s" added!') % collection.title) return redirect(request, "mediagoblin.user_pages.user_home", |