1 # GNU MediaGoblin -- federated, autonomous media hosting
2 # Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS.
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.
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.
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/>.
21 from os
.path
import splitext
22 from werkzeug
.datastructures
import FileStorage
23 from werkzeug
.exceptions
import BadRequest
, Forbidden
24 from werkzeug
.utils
import secure_filename
25 from werkzeug
.wrappers
import Response
26 from celery
import registry
28 from mediagoblin
.decorators
import require_active_login
29 from mediagoblin
.processing
import mark_entry_failed
30 from mediagoblin
.processing
.task
import ProcessMedia
31 from mediagoblin
.meddleware
.csrf
import csrf_exempt
32 from mediagoblin
.media_types
import sniff_media
33 from mediagoblin
.plugins
.api
.tools
import api_auth
, get_entry_serializable
, \
36 _log
= logging
.getLogger(__name__
)
42 def post_entry(request
):
43 _log
.debug('Posting entry')
45 if request
.method
== 'OPTIONS':
46 return json_response({'status': 200})
48 if request
.method
!= 'POST':
49 _log
.debug('Must POST against post_entry')
52 if not 'file' in request
.files \
53 or not isinstance(request
.files
['file'], FileStorage
) \
54 or not request
.files
['file'].stream
:
55 _log
.debug('File field not found')
58 media_file
= request
.files
['file']
60 media_type
, media_manager
= sniff_media(media_file
)
62 entry
= request
.db
.MediaEntry()
63 entry
.media_type
= unicode(media_type
)
64 entry
.title
= unicode(request
.form
.get('title')
65 or splitext(media_file
.filename
)[0])
67 entry
.description
= unicode(request
.form
.get('description'))
68 entry
.license
= unicode(request
.form
.get('license', ''))
70 entry
.uploader
= request
.user
.id
74 task_id
= unicode(uuid
.uuid4())
76 # Now store generate the queueing related filename
77 queue_filepath
= request
.app
.queue_store
.get_unique_filepath(
80 secure_filename(media_file
.filename
)])
83 queue_file
= request
.app
.queue_store
.get_file(
87 queue_file
.write(request
.files
['file'].stream
.read())
89 # Add queued filename to the entry
90 entry
.queued_media_file
= queue_filepath
92 entry
.queued_task_id
= task_id
94 # Save now so we have this data before kicking off processing
97 if request
.form
.get('callback_url'):
98 metadata
= request
.db
.ProcessingMetaData()
99 metadata
.media_entry
= entry
100 metadata
.callback_url
= unicode(request
.form
['callback_url'])
103 # Pass off to processing
105 # (... don't change entry after this point to avoid race
106 # conditions with changes to the document via processing code)
107 process_media
= registry
.tasks
[ProcessMedia
.name
]
109 process_media
.apply_async(
110 [unicode(entry
.id)], {},
112 except BaseException
as e
:
113 # The purpose of this section is because when running in "lazy"
114 # or always-eager-with-exceptions-propagated celery mode that
115 # the failure handling won't happen on Celery end. Since we
116 # expect a lot of users to run things in this way we have to
117 # capture stuff here.
119 # ... not completely the diaper pattern because the
120 # exception is re-raised :)
121 mark_entry_failed(entry
.id, e
)
122 # re-raise the exception
125 return json_response(get_entry_serializable(entry
, request
.urlgen
))
129 def api_test(request
):
134 'username': request
.user
.username
,
135 'email': request
.user
.email
}
137 # TODO: This is the *only* thing using Response() here, should that
138 # not simply use json_response()?
139 return Response(json
.dumps(user_data
))
142 def get_entries(request
):
143 entries
= request
.db
.MediaEntry
.query
145 # TODO: Make it possible to fetch unprocessed media, or media in-processing
146 entries
= entries
.filter_by(state
=u
'processed')
148 # TODO: Add sort order customization
149 entries
= entries
.order_by(request
.db
.MediaEntry
.created
.desc())
151 # TODO: Fetch default and upper limit from config
152 entries
= entries
.limit(int(request
.GET
.get('limit') or 10))
154 entries_serializable
= []
156 for entry
in entries
:
157 entries_serializable
.append(get_entry_serializable(entry
, request
.urlgen
))
159 return json_response(entries_serializable
)