Exemple #1
0
def add_job():
    """
    Adding a job to the processing queue either by fetching data from
    a known source or by using a previously created bucket full off
    resources (see ..)::

        {
            "payload": "bucket://1234afdsafdsfdsa232", 

            // for the moment you also need to specify the filename you want 
            "payload_filename: "herkules.ply"
            
            // alternatively, to load from a URI use this instead:
            "payload": "http://someplace.zip", 

            // all the following are optional:
            "email_to": "*****@*****.**",

            // array of strings representing meshlab filters. leave out
            // "meshlab" entry at all if no meshalb pre-processing is desired
            "meshlab": [
                "Remove Duplicate Faces",
                "Remove Duplicated Vertex",
                "Remove Zero Area Faces",
                "Remove Isolated pieces (wrt Face Num.)",
                "Remove Unreferenced Vertex",
                "Extract Information"
            ]

            // one out of the list of names you get with /bundles
            // always use the "name" field you get from GET /bundles as the name
            // might change. You can cache the names locally but be sure to expire
            // once in a while.
            "template": "basic",

            // the bundle name to be used for this job
            // in the future its also possible to override templte specific settings and options (shown but noop)
            //"bundle": {
            //    "name": "modelconvert.bundles.pop",   // this can also contain a bundle spec and related data
            //    "settings": {
            //        "aopt.pop": true,
            //        "aopt.command": "{command} {input} {output} -what -ever={0} -is -required",
            //        "meshlab.enabled": false,
            //   }
            // }
        }

    For exmaple a simple payload to convert a single model without meshalb
    sourced from a URL could look like this::

        {
            "payload": "http://domain.tld/model.obj",
            "template": "basic"
        }

    In return you will get a json response with various data about
    your request::

        {
            // clear text informational message, HTTP status code serves as numeric indicator
            "message": "Job accepted with ID 123", 

            // the task ID the job is running on
            "task_id": "123",

            // poll URI for checking less frequently for results
            "job_url":   "full.host/v1/jobs/123",       

            // URI for status updates through push protocl. This implements
            // the W3C EventSource specification. So your client needs to
            // support this in order to reciece push updates.
            "progress_url": "full.host/v1/stream/123",  
        }
    """
    
    options = dict() # options passted to task
    data = request.json

    if not data or not 'payload' in data:
        resp = jsonify(message="No payload provided. You need to specify what to convert.")
        resp.status_code = 400 # bad resquest
        return resp


    url = urlparse.urlparse(data['payload'])
    current_app.logger.info("Found {0} payload".format(url.scheme))

    if url.scheme == 'http':
        #
        #  FIXME BIGTIME
        #  THE URL DOWNLOADING SHOULD OCCUR IN THE TASK AND NOT BLOCK
        #  THE INTERFACE
        #
        if not security.is_allowed_host(data['payload']):
            resp = jsonify(message="Tried to download from a insecure source ({0}). Only the following hosts are allowed: {1}".format(url.netloc, ", ".join(current_app.config['ALLOWED_DOWNLOAD_HOSTS'])))
            resp.status_code = 403 #forbidden
            return resp

        # download file to disk
        r = requests.get(data['payload'], stream=True, verify=False)
        filename = werkzeug.secure_filename(os.path.split(data['payload'])[-1].split("?")[0])

        # FIXME: this should check the mimetype in the http response header
        # as well
        if not security.is_allowed_file(filename):
            resp = jsonify(message="Please upload a file of the following type: %s" %
            ", ".join(current_app.config['ALLOWED_EXTENSIONS']))
            resp.status_code = 403 #forbidden
            return resp


        if r.status_code == requests.codes.ok:

            if int(r.headers['content-length']) > current_app.config['MAX_CONTENT_LENGTH']:
                resp = jsonify(message="File too big. Please don't try to use files greater than {0}".format(humanize.bytes(current_app.config['MAX_CONTENT_LENGTH'])))
                resp.status_code = 416 # request range unsatifieable
                return resp
            else:
                
                # create a UUID like hash for temporary file storage
                hash = uuid.uuid4().hex

                upload_directory = os.path.join(current_app.config['UPLOAD_PATH'], hash)
                os.mkdir(upload_directory)
                filename = os.path.join(upload_directory, filename)

                with open(filename, "wb") as fdata:
                    fdata.write(r.content)

                options.update(hash=hash)
        else:
            resp = jsonify(message="Could not download file {0} Status code: {1}".format(data['payload'], r.status_code))
            resp.status_code = 416 # request range unsatifieable
            return resp


    elif url.scheme == 'bucket':

        if not 'payload_filename' in data:
            resp = jsonify(message="Please specify the payload_filename attribute in your request.")
            resp.status_code = 400 # bad
            return resp
			
        current_app.logger.debug("Using Bucket ID: {0} with entry point filename".format(url.netloc, filename))
        options.update(hash=url.netloc)
		upload_directory = os.path.join(current_app.config['UPLOAD_PATH'], url.netloc)
		filename = os.path.join(upload_directory, data['payload_filename'])
Exemple #2
0
def upload():
    logger = current_app.logger
    """
    The upload method takes a uploaded file and puts it into
    the celery processing queue using the Redis backend. Filename
    integrity is enforced by renaming the uploaded file to a unique
    name and deleting it after successfull processing.

    """
    if request.method == 'POST':
        # FIXME: convert this to WTForms
        meshlab = request.form.getlist('meshlab')
        template = request.form['template']

        if 'email_to' in request.form:
            email_to = request.form['email_to']
        else:
            email_to=None

        file = request.files['file']
        metadata = request.files['metadata']
        url = request.form['url']

        # options to pass to convertion task
        options = dict()

        # create a UUID like hash for temporary file storage
        hash = uuid.uuid4().hex
        options.update(hash=hash)



        # This whole section is kind of flimsy. 
        # - code more idiomatic
        # - download should be performed asynchrounously, though some checks
        #   should be performed here (allowed hosts, filenames, etc.)
        # - downloading a url triggered via public web form is a HUGE security
        #   risk. Basically anyone can kill our sever by pasting a url to be
        #   downloaded. Therefore, at the  moment, the ULRs are restricted to 
        #   the ALLOWED_DOWNLOAD_HOSTS settings.

        # error handling can be done smarter
        # URL instead of file
        if url:

            # basic security
            if not security.is_allowed_host(url):
                flash("Tried to download from a insecure source ({0}). Only the following hosts are allowed: {1}".format(url, ", ".join(current_app.config['ALLOWED_DOWNLOAD_HOSTS'])), 'error')
                return render_template('frontend/index.html')

            # download file to disk
            r = requests.get(url, stream=True, verify=False)
            filename = secure_filename(os.path.split(url)[-1].split("?")[0])

            # FIXME: this should check the mimetype in the http response header
            # as well
            if not security.is_allowed_file(filename):
                flash("Please upload a file of the following type: %s" %
                ", ".join(current_app.config['ALLOWED_EXTENSIONS']), 'error')
                return render_template('frontend/index.html')

            if r.status_code == requests.codes.ok:

                if int(r.headers['content-length']) > current_app.config['MAX_CONTENT_LENGTH']:
                    flash("File too big. Please don't upload files greater than {0}".format(humanize.bytes(current_app.config['MAX_CONTENT_LENGTH'])), 'error')
                    return render_template('frontend/index.html')
                else:
                    
                    upload_directory = os.path.join(current_app.config['UPLOAD_PATH'], hash)
                    os.mkdir(upload_directory)
                    filename = os.path.join(upload_directory, filename)

                    with open(filename, "wb") as data:
                        data.write(r.content)

            else:
                flash("Could not download file {0} Status code: {1}".format(url, r.status_code), 'error')
                return render_template('frontend/index.html')

        else:
            # in case of file upload place the uploaded file in a folder
            # named <uuid>
            if file and security.is_allowed_file(file.filename):
                filename = secure_filename(file.filename)
                upload_directory = os.path.join(current_app.config['UPLOAD_PATH'], hash)
                os.mkdir(upload_directory)
                filename = os.path.join(upload_directory, file.filename)
                file.save(filename)

                # in case the user uploaded a meta file, store this as well
                # FIXME make sure only processed when valid template selection
                if metadata and not compression.is_archive(filename):
                    meta_filename = os.path.join(upload_directory, 'metadata' + os.path.splitext(metadata.filename)[1])
                    metadata.save(meta_filename)
                    # options for task
                    options.update(meta_filename=meta_filename)

            else:
                flash("Please upload a file of the following type: %s" %
                    ", ".join(current_app.config['ALLOWED_EXTENSIONS']), 'error')
                return render_template('frontend/index.html')


        if email_to:
            # we need to add at least captcha system to protect from 
            # spammers, for now setting the sender env var enables the
            # email system, use with care behind pw protected 
            if current_app.config['DEFAULT_MAIL_SENDER'] == 'noreply@localhost':
                options.update(email_to=None)
            else:
                options.update(email_to=email_to)

       
        if meshlab:
            options.update(meshlab=meshlab)

        
        options.update(
            template=template
        )

        retval = tasks.convert_model.apply_async((filename, options))
        
        return redirect(url_for('frontend.status', task_id=retval.task_id))


    return render_template('frontend/index.html')
Exemple #3
0
def upload():
    """
    The upload method takes a uploaded file and puts it into
    the celery processing queue using the Redis backend. Filename
    integrity is enforced by renaming the uploaded file to a unique
    name and deleting it after successfull processing.

    """
    if request.method == 'POST':
        # FIXME: convert this to WTForms
        meshlab = request.form.getlist('meshlab')
        aopt = request.form['aopt']
        template = request.form['template']

        file = request.files['file']
        url = request.form['url']

        # options to pass to convertion task
        options = dict()

        # create a UUID like hash for temporary file storage
        #hash = "%032x" % random.getrandbits(128)
        hash = uuid.uuid4().hex
        options.update(hash=hash)



        # This whole section is kind of flimsy. 
        # - download should be performed asynchrounously, though some checks
        #   should be performed here (allowed hosts, filenames, etc.)
        # - downloading a url triggered via public web form is a HUGE security
        #   risk. Basically anyone can kill our sever by pasting a url to be
        #   downloaded. Therefore, at the  moment, the ULRs are restricted to 
        #   the ALLOWED_DOWNLOAD_HOSTS settings.

        # error handling can be done smarter
        # URL instead of file
        if url:

            # basic security
            if not security.is_allowed_host(url):
                flash("Tried to download from a insecure source ({0}). Only the following hosts are allowed: {1}".format(url, ", ".join(current_app.config['ALLOWED_DOWNLOAD_HOSTS'])), 'error')
                return render_template('frontend/index.html')

            # download file to disk
            r = requests.get(url, stream=True, verify=False)
            filename = secure_filename(os.path.split(url)[-1].split("?")[0])
            filename = os.path.join(current_app.config['UPLOAD_PATH'], filename)

            if not security.is_allowed_file(filename):
                flash("Please upload a file of the following type: %s" %
                ", ".join(current_app.config['ALLOWED_EXTENSIONS']), 'error')
                return render_template('frontend/index.html')

            if r.status_code == requests.codes.ok:

                if int(r.headers['content-length']) > current_app.config['MAX_CONTENT_LENGTH']:
                    flash("File too big. Please don't upload files greater than {0}".format(humanize.bytes(current_app.config['MAX_CONTENT_LENGTH'])), 'error')
                    return render_template('frontend/index.html')
                else:

                    with open(filename, "wb") as data:
                        data.write(r.content)

            else:
                flash("Could not download file {0} Status code: {1}".format(url, r.status_code), 'error')
                return render_template('frontend/index.html')

        else:
            # in case of file upload
            if file and security.is_allowed_file(file.filename):
                filename = secure_filename(file.filename)
                
                # anonymize filename, keep extension and save
                filename = os.path.join(current_app.config['UPLOAD_PATH'], 
                                        hash + os.path.splitext(file.filename)[1])
                file.save(filename)
            else:
                flash("Please upload a file of the following type: %s" %
                    ", ".join(current_app.config['ALLOWED_EXTENSIONS']), 'error')
                return render_template('frontend/index.html')


        if meshlab:
            options.update(meshlab=meshlab)

        # in case the user uploaded a meta file, store this as well
        # FIXME make sure only processed when valid template selection
        # (DoS)
        metadata = request.files['metadata']
        if metadata:
            meta_filename = os.path.join(current_app.config['UPLOAD_PATH'], hash, 'metadata' + os.path.splitext(metadata.filename)[1])
            metadata.save(meta_filename)
            options.update(meta_filename=meta_filename)
        options.update(
            aopt=aopt, 
            template=template
        )

        retval = tasks.convert_model.apply_async((filename, options))
        
        return redirect(url_for('frontend.status', task_id=retval.task_id))


    return render_template('frontend/index.html')