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