| 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 json |
| 18 | import logging |
| 19 | |
| 20 | from os.path import splitext |
| 21 | from werkzeug.datastructures import FileStorage |
| 22 | from werkzeug.exceptions import BadRequest, Forbidden |
| 23 | from werkzeug.wrappers import Response |
| 24 | |
| 25 | from mediagoblin.decorators import require_active_login |
| 26 | from mediagoblin.meddleware.csrf import csrf_exempt |
| 27 | from mediagoblin.media_types import sniff_media |
| 28 | from mediagoblin.plugins.api.tools import api_auth, get_entry_serializable, \ |
| 29 | json_response |
| 30 | from mediagoblin.submit.lib import prepare_queue_task, run_process_media |
| 31 | |
| 32 | _log = logging.getLogger(__name__) |
| 33 | |
| 34 | |
| 35 | @csrf_exempt |
| 36 | @api_auth |
| 37 | @require_active_login |
| 38 | def post_entry(request): |
| 39 | _log.debug('Posting entry') |
| 40 | |
| 41 | if request.method == 'OPTIONS': |
| 42 | return json_response({'status': 200}) |
| 43 | |
| 44 | if request.method != 'POST': |
| 45 | _log.debug('Must POST against post_entry') |
| 46 | raise BadRequest() |
| 47 | |
| 48 | if not 'file' in request.files \ |
| 49 | or not isinstance(request.files['file'], FileStorage) \ |
| 50 | or not request.files['file'].stream: |
| 51 | _log.debug('File field not found') |
| 52 | raise BadRequest() |
| 53 | |
| 54 | media_file = request.files['file'] |
| 55 | |
| 56 | media_type, media_manager = sniff_media(media_file) |
| 57 | |
| 58 | entry = request.db.MediaEntry() |
| 59 | entry.media_type = unicode(media_type) |
| 60 | entry.title = unicode(request.form.get('title') |
| 61 | or splitext(media_file.filename)[0]) |
| 62 | |
| 63 | entry.description = unicode(request.form.get('description')) |
| 64 | entry.license = unicode(request.form.get('license', '')) |
| 65 | |
| 66 | entry.uploader = request.user.id |
| 67 | |
| 68 | entry.generate_slug() |
| 69 | |
| 70 | # queue appropriately |
| 71 | queue_file = prepare_queue_task(request.app, entry, media_file.filename) |
| 72 | |
| 73 | with queue_file: |
| 74 | queue_file.write(request.files['file'].stream.read()) |
| 75 | |
| 76 | # Save now so we have this data before kicking off processing |
| 77 | entry.save() |
| 78 | |
| 79 | if request.form.get('callback_url'): |
| 80 | metadata = request.db.ProcessingMetaData() |
| 81 | metadata.media_entry = entry |
| 82 | metadata.callback_url = unicode(request.form['callback_url']) |
| 83 | metadata.save() |
| 84 | |
| 85 | # Pass off to processing |
| 86 | # |
| 87 | # (... don't change entry after this point to avoid race |
| 88 | # conditions with changes to the document via processing code) |
| 89 | feed_url = request.urlgen( |
| 90 | 'mediagoblin.user_pages.atom_feed', |
| 91 | qualified=True, user=request.user.username) |
| 92 | run_process_media(entry, feed_url) |
| 93 | |
| 94 | return json_response(get_entry_serializable(entry, request.urlgen)) |
| 95 | |
| 96 | |
| 97 | @api_auth |
| 98 | @require_active_login |
| 99 | def api_test(request): |
| 100 | user_data = { |
| 101 | 'username': request.user.username, |
| 102 | 'email': request.user.email} |
| 103 | |
| 104 | # TODO: This is the *only* thing using Response() here, should that |
| 105 | # not simply use json_response()? |
| 106 | return Response(json.dumps(user_data)) |
| 107 | |
| 108 | |
| 109 | def get_entries(request): |
| 110 | entries = request.db.MediaEntry.query |
| 111 | |
| 112 | # TODO: Make it possible to fetch unprocessed media, or media in-processing |
| 113 | entries = entries.filter_by(state=u'processed') |
| 114 | |
| 115 | # TODO: Add sort order customization |
| 116 | entries = entries.order_by(request.db.MediaEntry.created.desc()) |
| 117 | |
| 118 | # TODO: Fetch default and upper limit from config |
| 119 | entries = entries.limit(int(request.GET.get('limit') or 10)) |
| 120 | |
| 121 | entries_serializable = [] |
| 122 | |
| 123 | for entry in entries: |
| 124 | entries_serializable.append(get_entry_serializable(entry, request.urlgen)) |
| 125 | |
| 126 | return json_response(entries_serializable) |