src/sw/allotmentclub/browser/letter.py
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from datetime import datetime
from sw.allotmentclub import Member
from io import BytesIO
import email.utils
import pkg_resources
import pybars
import pyramid.threadlocal
import pyramid_mailer
import pyramid_mailer.message
import re
import xhtml2pdf.pisa
import unicodedata
from reportlab import rl_config
rl_config.invariant = True
LOGO = pkg_resources.resource_stream(
'sw.allotmentclub.browser', 'logo_letter.txt').read().decode('utf-8')
TEMPLATE_HEADER = """
<html lang="de">
<head>
<meta charset="utf-8"/>
<style>
body { font-size: {{font_size}}; }
#content { font-style: italic; }
.txt-color-red { font-color: red; }
{{{styles}}}
</style>
</head>
<body>
<div id="header_content" style="font-size: 9pt;">
<h1 style="font-family: Helvetica; color: #1f496d;
font-size: 16pt; margin: 0px; padding: 0px;">
Leuna—Bungalowgemeinschaft Roter See e.V.</h1>
Postfach 1106<br />
06767 Gräfenhainichen<br />
vorstand@roter-see.de
</div>
<div id="logo">
<img src="{{logo}}" />
</div>
"""
TEMPLATE_FOOTER = """
<table><tbody><tr><td>
{{#if from_}}
<p>Mit freundlichen Grüßen<br />Im Auftrag des Vorstandes</p>
{{#if signature}}
<img style="height: 25pt" src="{{signature}}" />
{{else}}
<br />
{{/if}}
<p style="font-style: italic;">
{{{from_}}}
</p>
{{/if}}
</td>
<td style="vertical-align: bottom; text-align: right;">
{{#if attachments}}
<p style="font-size: {{font_size}}; padding-right: 10pt;">
<span style="font-weight: bold;">Anlagen</span>
{{#each attachments}}
<br />{{title}}
{{/each}}
</p>
{{/if}}
</td></td></tbody></table>
<div id="footer_content" style="font-size: 9pt">
<table style="margin: 0px; padding: 0px;">
<tr>
<td style="width: 35%; text-align: left;">
Amtsgericht Stendal VR 46284</td>
<td style="width: 30%; text-align: center;"></td>
<td style="width: 35%; text-align: right;">
Vorsitzende: Anne Hausding</td>
</tr>
</table>
<hr style="margin: 0px; padding: 0px;" />
<table style="margin: 0px; padding: 0px; margin-top: 3pt;">
<tr>
<td style="width: 35%; text-align: left;">Saalesparkasse</td>
<td style="width: 30%; text-align: center;">BIC: NOLADE21HAL</td>
<td style="width: 35%; text-align: right;">
IBAN: DE71 8005 3762 3440 0001 67</td>
</tr>
</table>
</div>
</body>
</html>"""
PDF_TEMPLATE = TEMPLATE_HEADER + """
{{#if address}}
<p style="font-size: 7pt; text-decoration: underline;
padding-bottom: 7pt;">
Leuna—Bungalowgemeinschaft Roter See e.V. Postfach 1106
06767 Gräfenhainichen
</p>
<div style="font-size: 11pt; line-height: 11pt; padding-top: 13pt;">
{{{address}}}
</div>
{{/if}}
{{#if address}}
<p style="text-align: right; width: 100%; padding-top: 30pt;
margin-top: 0px;">
{{city}}, den {{date}}</p>
{{/if}}
{{#if subject}}
<h2 style="font-size: {{font_size}};">
{{{subject}}}
{{#if subsubject}}
<br />
<span style="font-weight: normal">{{{subsubject}}}</span><br />
{{/if}}
</h2>
{{/if}}
<div id="content">
{{{content}}}
</div>
""" + TEMPLATE_FOOTER
PDF_STYLES = """
@page {
size: a4 portrait;
@frame header_frame {
-pdf-frame-content: header_content;
left: 50pt; width: 412pt; top: 50pt; height: 80pt;
}
@frame logo_frame {
-pdf-frame-content: logo;
left: 462pt; width: 00pt; top: 50px; height: 80pt;
}
@frame content_frame {
left: 50pt; width: 512pt; top: 145pt; height: 600pt;
}
@frame footer_frame {
-pdf-frame-content: footer_content;
left: 50pt; width: 512pt; top: 752pt; height: 40pt;
}
}
"""
MAIL_TEMPLATE = TEMPLATE_HEADER + """
<p style="text-align: right; width: 100%; padding-top: 30pt;
margin-top: 0px;">
{{city}}, den {{date}}</p>
<div id="content">
{{{content}}}
</div>
""" + TEMPLATE_FOOTER
MAIL_STYLES = """
#header_content { display: block; padding-top: 10pt; width: 80% }
#logo { display: block; position: absolute; top: 8pt; right: 8pt; }
#logo img { height: 50pt; }
#footer_content { display: block; width: 100%; }
#content { display: block; padding: 0pt 10pt 0pt 0pt; }
table { padding: 0pt 10pt 20pt 0pt; font-size: 12pt; font-style: italic; }
#footer_content table { width: 100%; font-size: 9pt; }
"""
compiler = pybars.Compiler()
pdf_template = compiler.compile(PDF_TEMPLATE)
mail_template = compiler.compile(MAIL_TEMPLATE)
def render_pdf(
to, subject, content, user, date=None,
subsubject=None, attachments=None, font_size='12pt', force_from=False):
if date is None:
date = datetime.now()
if isinstance(to, Member):
to = to.address
if not to and not force_from:
from_ = None
else:
from_ = '{} {} ({})'.format(user.vorname, user.nachname, user.position)
data = dict(
styles=PDF_STYLES,
subject=subject,
subsubject=subsubject,
content=content,
from_=from_,
city=user.ort if user else None,
signature=user.signature if user else None,
date=date.strftime('%d.%m.%Y') if date else None,
address=to if to else None, logo=LOGO,
attachments=attachments, font_size=font_size)
html = "".join(pdf_template(data))
pdf = BytesIO()
xhtml2pdf.pisa.CreatePDF(src=html, dest=pdf, encoding='utf-8')
pdf.seek(0)
return pdf
def send_mail(to, subject, content, user, date=None, attachments=[],
font_size='12pt', self_cc=False):
anschreiben = render_pdf(to, subject, content, user, date)
if date is None:
date = datetime.now()
from_ = '{} {} ({})'.format(user.vorname, user.nachname, user.position)
text = """
{}
Mit freundlichen Grüßen,
Im Auftrag des Vorstandes
{}
""".format(content, from_)
text = text.replace('</p>', '\n')
text = re.sub('<[^<]+?>', '', text)
text = text.replace(' ', ' ')
msg_tag = email.utils.make_msgid()
msg = pyramid_mailer.message.Message(
subject=subject,
recipients=[to],
cc=['vorstand@roter-see.de'] if self_cc else None,
sender=('Vorstand Leuna-Bungalowgemeinschaft Roter See '
'<vorstand@roter-see.de>'),
body=text)
msg.attach(pyramid_mailer.message.Attachment(
'Anschreiben.pdf', 'application/pdf', anschreiben))
for attachment in attachments:
filename = attachment.filename
try:
# Prevent tuple exception in repoze.sendmail if filename contains
# non-ascii characters
filename = (unicodedata
.normalize('NFKD', filename)
.encode('ASCII', 'ignore')
.decode())
except Exception:
pass
msg.attach(pyramid_mailer.message.Attachment(
filename, attachment.mimetype, attachment.data))
mailer = pyramid_mailer.get_mailer(
pyramid.threadlocal.get_current_request())
mailer.send(msg)
return msg_tag