Verified Commit 65b60848 authored by Robin Sonnabend's avatar Robin Sonnabend
Browse files

Port to python3

parent c3878fec
......@@ -38,7 +38,9 @@ savegames
config.py
schilder.wsgi
*.png.*
*.schild.*
*.png_*
*.schild_*
venv/
data/cache/
data/pdf/
#!/usr/bin/env python3
# -*- encoding: utf8 -*-
from flask import Flask, flash, session, redirect, url_for, escape, request, Response, Markup
from flask import Flask, flash, session, redirect, url_for, escape, request, Response, Markup, render_template
from jinja2 import Environment, PackageLoader
import sys
import os
import os.path
import glob
import werkzeug
# genshi expects old location, fix
werkzeug.cached_property = werkzeug.utils.cached_property
from genshi.template import TemplateLoader
from genshi.template.text import NewTextTemplate
from flaskext.genshi import Genshi, render_response
from werkzeug.utils import secure_filename
from collections import defaultdict
from docutils.core import publish_parts
from PIL import Image
from pdf2image import convert_from_path
import warnings
import shutil
import subprocess
from subprocess import CalledProcessError, STDOUT
import PythonMagick
import subprocess as sp
import json
import tempfile
import config
......@@ -31,43 +26,7 @@ app.config.update(
MAX_CONTENT_LENGTH = 8388608
)
app.secret_key = config.app_secret
genshi = Genshi(app)
genshi.extensions['html'] = 'html5'
def check_output(*popenargs, **kwargs):
# Copied from py2.7s subprocess module
r"""Run command with arguments and return its output as a byte string.
If the exit code was non-zero it raises a CalledProcessError. The
CalledProcessError object will have the return code in the returncode
attribute and output in the output attribute.
The arguments are the same as for the Popen constructor. Example:
>>> check_output(["ls", "-l", "/dev/null"])
'crw-rw-rw- 1 root root 1, 3 Oct 18 2007 /dev/null\n'
The stdout argument is not allowed as it is used internally.
To capture standard error in the result, use stderr=STDOUT.
>>> check_output(["/bin/sh", "-c",
... "ls -l non_existent_file ; exit 0"],
... stderr=STDOUT)
'ls: non_existent_file: No such file or directory\n'
"""
if 'stdout' in kwargs:
raise ValueError('stdout argument not allowed, it will be overridden.')
process = subprocess.Popen(stdout=subprocess.PIPE, *popenargs, **kwargs)
output, unused_err = process.communicate()
retcode = process.poll()
if retcode != 0:
cmd = kwargs.get("args")
if cmd is None:
cmd = popenargs[0]
raise CalledProcessError(retcode, cmd, output=output)
#raise Exception(output)
return output
def allowed_file(filename):
return '.' in filename and filename.rsplit('.', 1)[1] in config.allowed_extensions
......@@ -87,11 +46,14 @@ def save_data(formdata, outfilename):
def run_pdflatex(context, outputfilename, overwrite=True):
if 'textemplate' not in context:
context['textemplate'] = "text-image-quer.tex"
genshitex = TemplateLoader([config.textemplatedir])
template = genshitex.load(
context['textemplate'], cls=NewTextTemplate, encoding='utf8')
if not overwrite and os.path.isfile(outputfilename) and os.path.getmtime(template.filepath) < os.path.getmtime(outputfilename):
return
texenv = Environment(loader=PackageLoader("schilder", config.textemplatedir))
texenv.variable_start_string = "${"
texenv.variable_end_string = "}"
texenv.block_start_string = "${{{{{"
texenv.block_end_string = "}}}}}"
template = texenv.get_template(context['textemplate'])
#if not overwrite and os.path.isfile(outputfilename) and os.path.getmtime(template.filepath) < os.path.getmtime(outputfilename):
# return
if context['markup'] == 'rst':
context['text'] = publish_parts(context['text'], writer_name='latex')['body']
#context['headline'] = publish_parts(context['headline'], writer_name='latex')['body']
......@@ -108,22 +70,17 @@ def run_pdflatex(context, outputfilename, overwrite=True):
tmptexfile = os.path.join(tmpdir, 'output.tex')
tmppdffile = os.path.join(tmpdir, 'output.pdf')
with open(tmptexfile, 'w') as texfile:
texfile.write(template.generate(form=context).render(encoding='utf8'))
cwd = os.getcwd()
os.chdir(tmpdir)
texfile.write(template.render(form=context))
os.symlink(config.texsupportdir, os.path.join(tmpdir, 'support'))
try:
texlog = check_output(
['pdflatex', '--halt-on-error', tmptexfile], stderr=STDOUT)
except CalledProcessError as e:
texlog = sp.check_output(['pdflatex', '--halt-on-error', tmptexfile], stderr=sp.STDOUT, cwd=tmpdir, universal_newlines=True)
except sp.CalledProcessError as e:
if overwrite:
try:
flash(Markup("<p>PDFLaTeX Output:</p><pre>%s</pre>" % e.output), 'log')
except:
print((e.output))
raise SyntaxWarning("PDFLaTeX bailed out")
finally:
os.chdir(cwd)
if overwrite:
try:
flash(Markup("<p>PDFLaTeX Output:</p><pre>%s</pre>" % texlog), 'log')
......@@ -141,22 +98,21 @@ def save_and_convert_image_upload(inputname):
filename = os.path.join(
config.uploaddir, secure_filename(imgfile.filename))
imgfile.save(filename)
img = PythonMagick.Image(filename)
img = Image.open(filename)
imgname = os.path.splitext(secure_filename(imgfile.filename))[
0].replace('.', '_') + '.png'
savedfilename = os.path.join(config.imagedir, imgname)
img.write(savedfilename)
img.save(savedfilename)
os.remove(filename)
return imgname
return None
def make_thumb(filename, maxgeometry):
thumbpath = filename + '.' + str(maxgeometry)
thumbpath = (filename.replace(config.imagedir, config.cachedir) + '_' + str(maxgeometry)).replace(".", "_") + ".png"
if not os.path.exists(thumbpath) or os.path.getmtime(filename) > os.path.getmtime(thumbpath):
img = PythonMagick.Image(str(filename))
img.transform("%sx%s" % (maxgeometry, maxgeometry))
img.quality(90)
img.write(str("png:%s" % thumbpath))
img = Image.open(str(filename))
img = img.resize((maxgeometry, maxgeometry))
img.save(thumbpath)
return thumbpath
......@@ -167,7 +123,7 @@ def index(**kwargs):
data.update(**kwargs)
filelist = glob.glob(config.datadir + '/*.schild')
data['files'] = [str(os.path.basename(f)) for f in sorted(filelist)]
return render_response('index.html', data)
return render_template('index.html', **data)
@app.route('/edit')
......@@ -180,7 +136,7 @@ def edit(**kwargs):
data['templates'] = [str(os.path.basename(f))
for f in sorted(templatelist)]
data['imageextensions'] = config.allowed_extensions
return render_response('edit.html', data)
return render_template('edit.html', **data)
@app.route('/edit/<filename>')
......@@ -239,7 +195,7 @@ def create():
@app.route('/schild/<filename>')
def schild(filename):
return render_response('schild.html', {'filename': filename, 'printer': [str(f) for f in sorted(config.printers.keys())]})
return render_template('schild.html', filename=filename, printer=[str(f) for f in sorted(config.printers.keys())])
@app.route('/printout', methods=['POST'])
......@@ -250,10 +206,10 @@ def printout():
copies = int(request.form['copies']) or 0
if copies > 0 and copies <= 6:
try:
lprout = check_output(['lpr', '-H', str(config.printserver), '-P', str(
printer), '-#', str(copies)] + config.lproptions + [filename], stderr=STDOUT)
lprout = sp.check_output(['lpr', '-H', str(config.printserver), '-P', str(
printer), '-#', str(copies)] + config.lproptions + [filename], stderr=sp.STDOUT)
flash('Schild wurde zum Drucker geschickt!')
except CalledProcessError as e:
except sp.CalledProcessError as e:
flash(Markup("<p>Could not print:</p><pre>%s</pre>" % e.output), 'error')
else:
flash('Ungültige Anzahl Kopien!')
......@@ -286,7 +242,7 @@ def image(imgname):
imgpath = os.path.join(config.imagedir, secure_filename(imgname))
# print(imgpath)
if os.path.exists(imgpath):
with open(imgpath, 'r') as imgfile:
with open(imgpath, 'rb') as imgfile:
return Response(imgfile.read(), mimetype="image/png")
else:
return "Meh" # redirect(url_for('index'))
......@@ -296,15 +252,18 @@ def image(imgname):
def thumbnail(imgname, maxgeometry):
imgpath = os.path.join(config.imagedir, secure_filename(imgname))
thumbpath = make_thumb(imgpath, maxgeometry)
with open(thumbpath, 'r') as imgfile:
with open(thumbpath, 'rb') as imgfile:
return Response(imgfile.read(), mimetype="image/png")
@app.route('/pdfthumb/<pdfname>/<int:maxgeometry>')
def pdfthumbnail(pdfname, maxgeometry):
pdfpath = os.path.join(config.pdfdir, secure_filename(pdfname))
thumbpath = make_thumb(pdfpath, maxgeometry)
with open(thumbpath, 'r') as imgfile:
pngpath = pdfpath.replace(".", "_") + ".png"
img = convert_from_path(pdfpath)[0]
img.save(pngpath)
thumbpath = make_thumb(pngpath, maxgeometry)
with open(thumbpath, 'rb') as imgfile:
return Response(imgfile.read(), mimetype="image/png")
......@@ -321,17 +280,21 @@ def tplthumbnail(tplname, maxgeometry):
}, pdfpath, overwrite=False
)
except Exception as e:
raise e
return str(e)
else:
thumbpath = make_thumb(pdfpath, maxgeometry)
with open(thumbpath, 'r') as imgfile:
pngpath = pdfpath.replace(".", "_") + ".png"
img = convert_from_path(pdfpath)[0]
img.save(pngpath)
thumbpath = make_thumb(pngpath, maxgeometry)
with open(thumbpath, 'rb') as imgfile:
return Response(imgfile.read(), mimetype="image/png")
@app.route('/pdfdownload/<pdfname>')
def pdfdownload(pdfname):
pdfpath = os.path.join(config.pdfdir, secure_filename(pdfname))
with open(pdfpath, 'r') as pdffile:
with open(pdfpath, 'rb') as pdffile:
return Response(pdffile.read(), mimetype="application/pdf")
......
<!DOCTYPE html>
<!-- <html xmlns="http://www.w3.org/1999/xhtml" > -->
<html xmlns:py="http://genshi.edgewall.org/">
<html>
<head>
<link rel='stylesheet' type='text/css' href="${ url_for('static', filename='main.css') }"/>
<link rel='stylesheet' type='text/css' href="{{ url_for('static', filename='main.css') }}"/>
<meta name="viewport" content="width=device-width, initial-scale=1"/>
<title>Schildergenerator</title>
</head>
<body>
<py:with vars="messages = get_flashed_messages(with_categories=True)">
<ul class="flashes" py:if="messages">
<li class="${ category }" py:for="category,message in messages" tabindex="0">${ message }</li>
</ul>
</py:with>
<a href="${ url_for('index') }">Liste der fertigen Schilder</a>
<form method="post" action="${ url_for('create') }" enctype="multipart/form-data">
<div class="box">
<label for="form:template">Wähle eine TeX-Vorlage:</label>
<ul py:attrs="{'class':'collapsed'} if defined('form') else {}">
<li py:for="textemplate in templates">
<input type="radio" name="textemplate" id="tpl:${textemplate}" value="${textemplate}" py:attrs="{'checked':'checked', 'onfocus':'this.parentElement.parentElement.className=\'\';'} if defined('form') and textemplate == form.textemplate else {}"/>
<label for="tpl:${textemplate}"><img src="${ url_for('tplthumbnail', tplname=textemplate, maxgeometry=80) }" alt="${textemplate}" title="${textemplate}"/></label>
</li>
<li class="onlywhencollapsed">
<button onclick="this.parentElement.parentElement.className=''; return false;" >Auswahl anzeigen</button>
</li>
</ul>
</div><br/>
<div class="box">
<label for="form:headline">Überschrift</label>
<textarea name="headline" id="form:headline" cols="35" rows="5"><py:if test="defined('form')">${form.headline}</py:if></textarea>
</div>
<div class="box">
<label for="form:text">Text</label>
<select name="markup">
<option value="latex" py:attrs="{'selected':'True'} if defined('form') and form.markup == 'latex' else {}">LaTeX</option>
<option value="rst" py:attrs="{'selected':'True'} if not defined('form') or form.markup == 'rst' or form.markup == '' else {}">Wiki (reStructuredText)</option>
</select>
<textarea name="text" id="form:text" cols="35" rows="5"><py:if test="defined('form')">${form.text}</py:if></textarea>
</div><br/>
<div class="box imageselect">
<label for="form:img">Wähle ein Bild (falls auf Vorlage anwendbar):</label>
<ul>
<li>
<input type="radio" name="img" id="img--none" value="__none" py:attrs="{'checked':'checked'} if defined('form') and form.img == '__none' else {}"/>
<label for="img--none">Kein Bild</label>
</li>
<li>
<input type="radio" name="img" id="img--upload" value="__upload"/>
<input type="file" name="imgupload"/>
<label for="img--upload">Bild hochladen (${', '.join(imageextensions)})</label>
</li>
</ul>
<ul py:attrs="{'class':'collapsed'} if defined('form') else {}">
<li py:for="img in images">
<input type="radio" name="img" id="img:${img}" value="${img}" py:attrs="{'checked':'checked', 'onfocus':'this.parentElement.parentElement.className=\'\';'} if defined('form') and form.img == img else {}"/>
<label for="img:${img}"><img src="${ url_for('thumbnail', imgname=img, maxgeometry=100) }" alt="${img}" title="${img}"/></label>
</li>
<li class="onlywhencollapsed">
<button onclick="this.parentElement.parentElement.className=''; return false;" >Auswahl anzeigen</button>
</li>
</ul>
</div>
{% with messages = get_flashed_messages(with_categories=True) %}
{% if messages %}
<ul class="flashes">
{% for category, message in messages %}
<li class="{{ category }}" tabindex="0">{{ message }}</li>
{% endfor %}
</ul>
{% endif %}
{% endwith %}
<a href="{{ url_for('index') }}">Liste der fertigen Schilder</a>
<form method="post" action="{{ url_for('create') }}" enctype="multipart/form-data">
<div class="box">
<label for="form:template">Wähle eine TeX-Vorlage:</label>
<ul class="{% if form %}collapsed{% endif %}">
{% for textemplate in templates %}
<li>
<input type="radio" name="textemplate" id="tpl:{{textemplate}}" value="{{textemplate}}" {% if form and textemplate == form.textemplate %} checked="checked" onfocus="this.parentElement.parentElement.className='';" {% endif %} />
<label for="tpl:{{textemplate}}"><img src="{{ url_for('tplthumbnail', tplname=textemplate, maxgeometry=80) }}" alt="{{textemplate}}" title="{{textemplate}}"/></label>
</li>
<li class="onlywhencollapsed">
<button onclick="this.parentElement.parentElement.className=''; return false;" >Auswahl anzeigen</button>
</li>
{% endfor %}
</ul>
</div><br/>
<div class="box">
<label for="form:headline">Überschrift</label>
<textarea name="headline" id="form:headline" cols="35" rows="5">{% if form %}{{form.headline}}{% endif %}</textarea>
</div>
<div class="box">
<label for="form:text">Text</label>
<select name="markup">
<option value="latex" {% if form and form.markup == "latex" %}selected{% endif %}>LaTeX</option>
<option value="rst" {% if form and (form.markup == "rst" or form.markup == "") %}selected{% endif %}>Wiki (reStructuredText)</option>
</select>
<textarea name="text" id="form:text" cols="35" rows="5">{% if form %}{{form.text}}{% endif %}</textarea>
</div>
<br/>
<div class="box imageselect">
<label for="form:img">Wähle ein Bild (falls auf Vorlage anwendbar):</label>
<ul>
<li>
<input type="radio" name="img" id="img--none" value="__none" {% if form and form.img == "__none" %}checked{% endif %}/>
<label for="img--none">Kein Bild</label>
</li>
<li>
<input type="radio" name="img" id="img--upload" value="__upload"/>
<input type="file" name="imgupload"/>
<label for="img--upload">Bild hochladen ({{', '.join(imageextensions)}})</label>
</li>
</ul>
<ul {% if form %}class="collapsed"{% endif %}>
{% for img in images %}
<li>
<input type="radio" name="img" id="img:{{img}}" value="{{img}}" {% if form and form.img == img %}checked="checked" onfocus="this.parentElement.parentElement.className='';"{% endif %} />
<label for="img:{{img}}">
<img src="{{ url_for('thumbnail', imgname=img, maxgeometry=100) }}" alt="{{img}}" title="{{img}}"/>
</label>
</li>
{% endfor %}
<li class="onlywhencollapsed">
<button onclick="this.parentElement.parentElement.className=''; return false;" >Auswahl anzeigen</button>
</li>
</ul>
</div>
<br/>
<div class="box">
{% if form and form.filename|length > 5 %}
<input type="hidden" name="filename" value="{{form.filename}}"/>
<input id="form:reusefilename" type="checkbox" name="reusefilename"/>
<label for="form:reusefilename">Überschreibe bisherige Version von {{form.filename}}.</label>
<br/>
<div class="box">
<py:if test="defined('form') and len(form.filename) > 5">
<input type="hidden" name="filename" value="${form.filename}"/>
<input id="form:reusefilename" type="checkbox" name="reusefilename"/>
<label for="form:reusefilename">Überschreibe bisherige Version von ${form.filename}.</label>
<br/>
</py:if>
<input type="submit" value="Schild erstellen"/>
</div>
</form>
{% endif %}
<input type="submit" value="Schild erstellen"/>
</div>
</form>
</body>
</html>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:py="http://genshi.edgewall.org/">
<html>
<head>
<link rel='stylesheet' type='text/css' href="${ url_for('static', filename='main.css') }"/>
<link rel='stylesheet' type='text/css' href="{{ url_for('static', filename='main.css') }}"/>
<meta name="viewport" content="width=device-width, initial-scale=1"/>
<title>Schildergenerator</title>
</head>
<body>
<py:with vars="messages = get_flashed_messages(with_categories=True)">
<ul class="flashes" py:if="messages">
<li class="${ category }" py:for="category,message in messages" tabindex="0">${ message }</li>
</ul>
</py:with>
{% with messages = get_flashed_messages(with_categories=True) %}
{% if messages %}
<ul class="flashes">
{% for category, message in messages %}
<li class="{{ category }}" tabindex="0">{{ message }}</li>
{% endfor %}
</ul>
{% endif %}
{% endwith %}
<a href="${ url_for('edit') }">Neues Schild</a>
<a href="{{ url_for('edit') }}">Neues Schild</a>
<py:if test="defined('files')">
<form method="POST" action="${ url_for('deletelist') }">
<ul>
<li py:for="file in files">
<input id="form:${file}" type="checkbox" name="filenames" value="${file}"/>
<a href="${ url_for('schild', filename=file) }" title="${file}">
<img src="${ url_for('pdfthumbnail', pdfname=file+'.pdf', maxgeometry=150) }"/>
</a>
</li>
</ul>
<input type="submit" value="Ausgewählte Schilder löschen"/>
</form>
</py:if>
{% if files %}
<form method="POST" action="{{ url_for('deletelist') }}">
<ul>
{% for file in files %}
<li>
<input id="form:{{file}}" type="checkbox" name="filenames" value="{{file}}"/>
<a href="{{ url_for('schild', filename=file) }}" title="{{file}}">
<img src="{{ url_for('pdfthumbnail', pdfname=file+'.pdf', maxgeometry=150) }}"/>
</a>
</li>
{% endfor %}
</ul>
<input type="submit" value="Ausgewählte Schilder löschen"/>
</form>
{% endif %}
</body>
</html>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:py="http://genshi.edgewall.org/">
<html>
<head>
<link rel='stylesheet' type='text/css' href="${ url_for('static', filename='main.css') }"/>
<link rel='stylesheet' type='text/css' href="{{ url_for('static', filename='main.css') }}"/>
<meta name="viewport" content="width=device-width, initial-scale=1"/>
<title>Schildergenerator</title>
</head>
<body>
<a href="${ url_for('index') }">Liste der Schilder</a>
<a href="${ url_for('edit') }">Neues Schild</a>
<py:with vars="messages = get_flashed_messages(with_categories=True)">
<ul class="flashes" py:if="messages">
<li class="${ category }" py:for="category,message in messages">${ message }</li>
</ul>
</py:with>
<img class="bigpreview" src="${ url_for('pdfthumbnail', pdfname=filename+'.pdf', maxgeometry=300) }"/>
<form method="post" action="${ url_for('printout') }">
<input type="hidden" name="filename" value="${filename + '.pdf'}" />
<a href="{{ url_for('index') }}">Liste der Schilder</a>
<a href="{{ url_for('edit') }}">Neues Schild</a>
{% with messages = get_flashed_messages(with_categories=True) %}
{% if messages %}
<ul class="flashes">
{% for category, message in messages %}
<li class="{{ category }}">{{ message }}</li>
{% endfor %}
</ul>
{% endif %}
{% endwith %}
<img class="bigpreview" src="{{ url_for('pdfthumbnail', pdfname=filename+'.pdf', maxgeometry=300) }}"/>
<form method="post" action="{{ url_for('printout') }}">
<input type="hidden" name="filename" value="{{filename + '.pdf'}}" />
<select name="copies">
<option py:for="x in range(1,11)" value="${x}" label="${x} Kopien">${x} Kopien</option>
{% for x in range(1, 11) %}
<option value="{{x}}" label="{{x}} Kopien">{{x}} Kopien</option>
{% endfor %}
</select>
<select name="printer">
<option py:for="pr in printer" value="${pr}" label="Drucker ${pr}">Drucker ${pr}</option>
</select>
{% for pr in printer %}
<option value="{{pr}}" label="Drucker {{pr}}">Drucker {{pr}}</option>
{% endfor %}
</select>
<input type="submit" value="Schild drucken" />
</form>
<a href="${ url_for('pdfdownload', pdfname=filename + '.pdf') }">Schild als PDF herunterladen.</a>
<a href="${ url_for('edit_one', filename=filename) }">Schild bearbeiten/als Vorlage verwenden.</a>
<form method="post" action="${ url_for('delete') }">
<input type="hidden" name="filename" value="${filename}" />
<a href="{{ url_for('pdfdownload', pdfname=filename + '.pdf') }}">Schild als PDF herunterladen.</a>
<a href="{{ url_for('edit_one', filename=filename) }}">Schild bearbeiten/als Vorlage verwenden.</a>
<form method="post" action="{{ url_for('delete') }}">
<input type="hidden" name="filename" value="{{filename}}" />
<input type="submit" value="Schild löschen" />
</form>
</body>
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment