Skip to content
Snippets Groups Projects
Verified Commit 65b60848 authored by Robin Sonnabend's avatar Robin Sonnabend
Browse files

Port to python3

parent c3878fec
No related branches found
No related tags found
No related merge requests found
......@@ -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>
{% 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>
</py:with>
<a href="${ url_for('index') }">Liste der fertigen Schilder</a>
{% endif %}
{% endwith %}
<a href="{{ url_for('index') }}">Liste der fertigen Schilder</a>
<form method="post" action="${ url_for('create') }" enctype="multipart/form-data">
<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>
<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"><py:if test="defined('form')">${form.headline}</py:if></textarea>
<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" 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>
<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"><py:if test="defined('form')">${form.text}</py:if></textarea>
</div><br/>
<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" py:attrs="{'checked':'checked'} if defined('form') and form.img == '__none' else {}"/>
<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>
<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>
<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>
......@@ -64,12 +74,12 @@
</div>
<br/>
<div class="box">
<py:if test="defined('form') and len(form.filename) > 5">
<input type="hidden" name="filename" value="${form.filename}"/>
{% 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>
<label for="form:reusefilename">Überschreibe bisherige Version von {{form.filename}}.</label>
<br/>
</py:if>
{% endif %}
<input type="submit" value="Schild erstellen"/>
</div>
</form>
......
<!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>
{% 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>
</py:with>
{% 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') }">
{% if 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) }"/>
{% 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>
</py:if>
{% 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>
<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>
</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'}" />
{% 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>
{% 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>
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment