diff options
author | jaseg <git@jaseg.net> | 2019-09-28 13:53:02 +0200 |
---|---|---|
committer | jaseg <git@jaseg.net> | 2019-09-28 13:53:02 +0200 |
commit | 031b6f736187efdc64c525a40c687698701e73e1 (patch) | |
tree | 140a96a98822effda864d77720a227aae928f5f9 /webapp/pogojig.py | |
parent | 6002d409143a6726899a4de15c3a6b279a6b1d71 (diff) | |
download | pogojig-031b6f736187efdc64c525a40c687698701e73e1.tar.gz pogojig-031b6f736187efdc64c525a40c687698701e73e1.tar.bz2 pogojig-031b6f736187efdc64c525a40c687698701e73e1.zip |
Initial webapp design
Diffstat (limited to 'webapp/pogojig.py')
-rw-r--r-- | webapp/pogojig.py | 111 |
1 files changed, 111 insertions, 0 deletions
diff --git a/webapp/pogojig.py b/webapp/pogojig.py new file mode 100644 index 0000000..a7201d0 --- /dev/null +++ b/webapp/pogojig.py @@ -0,0 +1,111 @@ +#!/usr/bin/env python3 + +# TODO setup webserver user disk quota + +import tempfile +import uuid +from functools import wraps +from os import path +import os +import sqlite3 + +from flask import Flask, url_for, redirect, session, make_response, render_template, request, send_file, abort, flash +from flask_wtf import FlaskForm +from flask_wtf.file import FileField, FileRequired +from wtforms.fields import RadioField +from wtforms.validators import DataRequired +from werkzeug.utils import secure_filename + +from job_queue import JobQueue + +app = Flask(__name__, static_url_path='/static') +app.config.from_envvar('POGOJIG_SETTINGS') + +class UploadForm(FlaskForm): + upload_file = FileField(validators=[DataRequired()]) + +class ResetForm(FlaskForm): + pass + +job_queue = JobQueue(app.config['JOB_QUEUE_DB']) + +def tempfile_path(namespace): + """ Return a path for a per-session temporary file identified by the given namespace. Create the session tempfile + dir if necessary. The application tempfile dir is controlled via the upload_path config value and not managed by + this function. """ + sess_tmp = path.join(app.config['UPLOAD_PATH'], session['session_id']) + os.makedirs(sess_tmp, exist_ok=True) + return path.join(sess_tmp, namespace) + +def require_session_id(fun): + @wraps(fun) + def wrapper(*args, **kwargs): + if 'session_id' not in session: + session['session_id'] = str(uuid.uuid4()) + return fun(*args, **kwargs) + return wrapper + +@app.route('/') +def index(): + return app.send_static_file('index.html') + +@app.route('/jigerator') +@require_session_id +def jigerator(): + forms = { + 'svg_form': UploadForm(), + 'reset_form': ResetForm() } + + if 'render_job' in session: + job = job_queue[session['render_job']] + if job.finished: + if job.result != 0: + flash(f'Error processing SVG file', 'success') # FIXME make this an error, add CSS + del session['render_job'] + + r = make_response(render_template('jigerator.html', has_renders=path.isfile(tempfile_path('output.zip')), **forms)) + if 'render_job' in session: + r.headers.set('refresh', '10') + return r + +# NOTES about the SVG file upload routines +# * The maximum upload size is limited by the MAX_CONTENT_LENGTH config setting. +# * The uploaded files are deleted after a while by systemd tmpfiles.d +# TODO: validate this setting applies *after* gzip transport compression + +def render(): + if 'render_job' in session: + job_queue[session['render_job']].abort() + session['render_job'] = job_queue.enqueue('render', + session_id=session['session_id'], + client=request.remote_addr) + +@app.route('/upload/svg', methods=['POST']) +@require_session_id +def upload_svg(): + upload_form = UploadForm() + if upload_form.validate_on_submit(): + f = upload_form.upload_file.data + f.save(tempfile_path('input.svg')) + session['filename'] = secure_filename(f.filename) # Cache filename for later download + + render() + flash(f'SVG file successfully uploaded.', 'success') + return redirect(url_for('jigerator')) + +@app.route('/render/download') +def render_download(): + return send_file(tempfile_path(f'renders.zip'), + mimetype='application/zip', + as_attachment=True, + attachment_filename=f'{path.splitext(session["filename"])[0]}_pogojig.zip') + +@app.route('/session_reset', methods=['POST']) +@require_session_id +def session_reset(): + if 'render_job' in session: + job_queue[session['render_job']].abort() + session.clear() + flash('Session reset', 'success'); + return redirect(url_for('jigerator')) + |