Normalize MediaFile.name (make it a foreignkey)
[mediagoblin.git] / mediagoblin / submit / views.py
CommitLineData
e323a068 1# GNU MediaGoblin -- federated, autonomous media hosting
cf29e8a8 2# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS.
e323a068
CAW
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
2c437493 17import mediagoblin.mg_globals as mg_globals
4a477e24 18import uuid
bb49e56f 19from os.path import splitext
03afc828
CAW
20from cgi import FieldStorage
21
8e5f9746 22from celery import registry
5b1a7bae 23import urllib,urllib2
77b91efc 24import logging
8e5f9746 25
c03d13cd 26_log = logging.getLogger(__name__)
8e5f9746 27
f6f524bf 28from werkzeug.utils import secure_filename
e323a068 29
f64e5250 30from mediagoblin.db.util import ObjectId
1e72e075 31from mediagoblin.tools.text import convert_to_tag_list_of_dicts
ae3bc7fa 32from mediagoblin.tools.translate import pass_to_ugettext as _
152a3bfa 33from mediagoblin.tools.response import render_to_response, redirect
e323a068 34from mediagoblin.decorators import require_active_login
3eeadc92 35from mediagoblin.submit import forms as submit_forms, security
8e5f9746 36from mediagoblin.processing import mark_entry_failed, ProcessMedia
4dc74441 37from mediagoblin.messages import add_message, SUCCESS
4601c30c
JW
38from mediagoblin.media_types import get_media_type_and_manager, \
39 InvalidFileType, FileTypeNotSupported
e323a068
CAW
40
41
42@require_active_login
43def submit_start(request):
44 """
45 First view for submitting a file.
46 """
20439236 47 submit_form = submit_forms.SubmitStartForm(request.POST)
e323a068 48
f6f524bf 49 if request.method == 'POST' and submit_form.validate():
285ffedd 50 if not ('file' in request.POST
03afc828
CAW
51 and isinstance(request.POST['file'], FieldStorage)
52 and request.POST['file'].file):
53 submit_form.file.errors.append(
4b1adc13 54 _(u'You must provide a file.'))
03afc828 55 else:
6788b412 56 try:
0bce749b
JW
57 filename = request.POST['file'].filename
58 media_type, media_manager = get_media_type_and_manager(filename)
bb49e56f 59
0bce749b
JW
60 # create entry and save in database
61 entry = request.db.MediaEntry()
58f96a13 62 entry.id = ObjectId()
f4ee8399 63 entry.media_type = unicode(media_type)
ec82fbd8 64 entry.title = (
0bce749b
JW
65 unicode(request.POST['title'])
66 or unicode(splitext(filename)[0]))
93bdab9d 67
1d939966 68 entry.description = unicode(request.POST.get('description'))
4bf8e888 69
2788e6a1 70 entry.license = unicode(request.POST.get('license', "")) or None
99a270e9 71
1ceb4fc8 72 entry.uploader = request.user._id
03afc828 73
0bce749b 74 # Process the user's folksonomy "tags"
de917303 75 entry.tags = convert_to_tag_list_of_dicts(
0bce749b 76 request.POST.get('tags'))
03afc828 77
0bce749b
JW
78 # Generate a slug from the title
79 entry.generate_slug()
4a477e24 80
572d4f01
E
81 # We generate this ourselves so we know what the taks id is for
82 # retrieval later.
83
84 # (If we got it off the task's auto-generation, there'd be
85 # a risk of a race condition when we'd save after sending
86 # off the task)
87 task_id = unicode(uuid.uuid4())
4dc74441 88
0bce749b
JW
89 # Now store generate the queueing related filename
90 queue_filepath = request.app.queue_store.get_unique_filepath(
91 ['media_entries',
572d4f01 92 task_id,
0bce749b 93 secure_filename(filename)])
03afc828 94
0bce749b
JW
95 # queue appropriately
96 queue_file = request.app.queue_store.get_file(
97 queue_filepath, 'wb')
03afc828 98
0bce749b
JW
99 with queue_file:
100 queue_file.write(request.POST['file'].file.read())
03afc828 101
0bce749b 102 # Add queued filename to the entry
8545cfc9 103 entry.queued_media_file = queue_filepath
03afc828 104
572d4f01 105 entry.queued_task_id = task_id
07934b44 106
0bce749b
JW
107 # Save now so we have this data before kicking off processing
108 entry.save(validate=True)
fa7f9c61 109
0bce749b 110 # Pass off to processing
6788b412 111 #
0bce749b
JW
112 # (... don't change entry after this point to avoid race
113 # conditions with changes to the document via processing code)
114 process_media = registry.tasks[ProcessMedia.name]
115 try:
116 process_media.apply_async(
117 [unicode(entry._id)], {},
118 task_id=task_id)
119 except BaseException as exc:
120 # The purpose of this section is because when running in "lazy"
121 # or always-eager-with-exceptions-propagated celery mode that
122 # the failure handling won't happen on Celery end. Since we
123 # expect a lot of users to run things in this way we have to
124 # capture stuff here.
125 #
126 # ... not completely the diaper pattern because the
127 # exception is re-raised :)
128 mark_entry_failed(entry._id, exc)
129 # re-raise the exception
130 raise
131
bb025ebd 132 if mg_globals.app_config["push_urls"]:
5b1a7bae
MA
133 feed_url=request.urlgen(
134 'mediagoblin.user_pages.atom_feed',
135 qualified=True,user=request.user.username)
136 hubparameters = {
77b91efc
MA
137 'hub.mode': 'publish',
138 'hub.url': feed_url}
5b1a7bae 139 hubdata = urllib.urlencode(hubparameters)
bb025ebd
MA
140 hubheaders = {
141 "Content-type": "application/x-www-form-urlencoded",
142 "Connection": "close"}
143 for huburl in mg_globals.app_config["push_urls"]:
77b91efc
MA
144 hubrequest = urllib2.Request(huburl, hubdata, hubheaders)
145 try:
146 hubresponse = urllib2.urlopen(hubrequest)
147 except urllib2.HTTPError as exc:
148 # This is not a big issue, the item will be fetched
149 # by the PuSH server next time we hit it
c03d13cd 150 _log.warning(
77b91efc
MA
151 "push url %r gave error %r", huburl, exc.code)
152 except urllib2.URLError as exc:
c03d13cd 153 _log.warning(
77b91efc 154 "push url %r is unreachable %r", huburl, exc.reason)
5b1a7bae 155
0bce749b
JW
156 add_message(request, SUCCESS, _('Woohoo! Submitted!'))
157
158 return redirect(request, "mediagoblin.user_pages.user_home",
5a4e3ff1 159 user=request.user.username)
a246ccca
JW
160 except Exception as e:
161 '''
162 This section is intended to catch exceptions raised in
163 mediagobling.media_types
164 '''
4601c30c
JW
165
166 if isinstance(e, InvalidFileType) or \
167 isinstance(e, FileTypeNotSupported):
168 submit_form.file.errors.append(
169 e)
170 else:
171 raise
f6f524bf 172
9038c9f9
CAW
173 return render_to_response(
174 request,
c9c24934 175 'mediagoblin/submit/start.html',
2c437493
JW
176 {'submit_form': submit_form,
177 'app_config': mg_globals.app_config})