Example #1
0
def upload(request):
    """View used when support for Nginx Upload Progress module has
    been disabled.

    This view includes 3 steps:

    1. We change the "state" column in the upload table so that our
       AJAX-called 'progress' view sees that the upload has started
       and that the temporary file can be stat'ed.

    2. We copy the data from the POST request to a temporary
       file. This step is long, obviously, as we copy data as we
       receive it from the browser. While we are copying data, the
       browser will call the 'progress' view to update a progress bar.

    3. Once the file has been copied, we rename it to its final
       filename and redirect the browser to the success page.
    """
    # We pass the 'file_id' in the query string as a GET parameter. If
    # we read it from the POSTed data, WebOb would read all POSTed
    # data, which has various features and traps (like setting the
    # "Content-Length" header to 0) that we do not need since we are
    # going to read the data ourselves anyway.
    file_id = request.GET['X-Progress-ID']
    input_file, file_size, filename = get_file_from_request(request)
    session = DBSession()
    u = session.query(Upload).filter_by(id=file_id).one()
    upload_dir = request.registry.settings['poulda.upload_dir']
    user_id = authenticated_userid(request)
    # We use a temporary path to detect unfinished uploads (post
    # mortem, not in the application itself).
    path = os.path.join(upload_dir, '_'.join((user_id, file_id)))
    u.tmp_path = path
    u.started = int(time.time())
    u.size = file_size
    u.state = u'uploading'
    session.flush()
    # We need to commit the transaction so that changes to the Upload
    # object can be seen by the other threads (which will serve the
    # 'progress' JSON view called by the upload page).
    transaction.commit()
    with open(path, 'w') as output:
        # We must read only 'file_size' bytes from the 'input_file',
        # not all of it since it also contains the MIME boundary.
        copy_to_file(input_file, file_size, output)
    final_path = filename[1 + filename.rfind(os.sep):]
    final_path = os.path.join(upload_dir, final_path)
    os.rename(path, final_path)
    session = DBSession()
    u = session.query(Upload).filter_by(id=file_id).one()
    u.state = u'done'
    u.final_path = unicode(final_path, 'utf-8')
    return HTTPFound(location='success')
Example #2
0
def progress(request):
    """View used only when the Nginx Upload Progress support has been
    disabled.

    When the Nginx Upload Progress support is enabled, this view is
    never called at all, since the Nginx module takes care of
    returning progress information.
    """
    file_id = request.GET['X-Progress-ID']
    session = DBSession()
    u = session.query(Upload).filter_by(id=file_id).one()
    data = {'state': u.state}
    if u.state == 'uploading':
        if not os.path.exists(u.tmp_path):
            # The temporary file has not been created yet or it has
            # already been renamed. We return 0 in both case, the
            # front-end code will know what to do.
            received = 0
        else:
            received = os.stat(u.tmp_path).st_size
        data.update({'size': u.size, 'received': received})
    return data
Example #3
0
def upload_form(request):
    api = TemplateAPI(request, step='upload')
    settings = request.registry.settings
    if settings.get('poulda.nginx_upload_progress', 'false') != 'true':
        u = Upload()
        u.state = u'starting'
        session = DBSession()
        session.add(u)
        session.flush()  # set 'u.id'
        file_id = repr(u.id)
    else:
        file_id = repr(time.time())
    return render_to_response('templates/upload.pt',
                              {'api': api, 'file_id': file_id})