From 7b67e9b5357c06c899e7d6a2b7db2506ec0b1d65 Mon Sep 17 00:00:00 2001 From: Yannik Enss Date: Sat, 27 Jun 2020 15:29:16 +0200 Subject: [PATCH] init --- generate.py | 169 ++++++++++++++++++++++++++++++ generator.conf.example | 60 +++++++++++ templates/fsr_einladung.j2 | 41 ++++++++ templates/fsr_presentation.tex.j2 | 40 +++++++ templates/fsr_protokoll.j2 | 26 +++++ 5 files changed, 336 insertions(+) create mode 100644 generate.py create mode 100644 generator.conf.example create mode 100644 templates/fsr_einladung.j2 create mode 100644 templates/fsr_presentation.tex.j2 create mode 100644 templates/fsr_protokoll.j2 diff --git a/generate.py b/generate.py new file mode 100644 index 0000000..81d15aa --- /dev/null +++ b/generate.py @@ -0,0 +1,169 @@ +#!/usr/bin/python3 +import mailbox +import jinja2 +import email.header +import email.utils +import yaml +import datetime +import sys +import pypandoc +import argparse +from pprint import pprint + +CONFIG_FILE = "generator.conf" + +WEEKDAYS = { 0: "Montag", + 1: "Dienstag", + 2: "Mittwoch", + 3: "Donnerstag", + 4: "Freitag", + 5: "Samstag", + 6: "Sonntag" } + +def decode_header(header): + return "".join([ x[0].decode(x[1] or "ascii") if isinstance(x[0], bytes) else x[0] for x in email.header.decode_header(header) ]) + +class Top: + def __init__(self, title=None, sender=None, body=None, protostub=None, message=None): + if message: + self.title = decode_header(message["Subject"])[6:] + real_name, address = email.utils.parseaddr(message["From"]) + self.sender = real_name or address + self.body = message.get_payload().rpartition("\n--")[0] + elif title: + self.title = title + self.sender = sender + self.body = body + self.protostub = protostub + else: + raise ValueError("One of title or message is needed") + + def __repr__(self): + return "" + +# from https://stackoverflow.com/questions/6558535/find-the-date-for-the-first-monday-after-a-given-a-date +def next_weekday(d, weekday): + days_ahead = weekday - d.weekday() + if days_ahead < 0: # Target day already happened this week + days_ahead += 7 + return d + datetime.timedelta(days_ahead) + +def last_weekday(d, weekday): + days_ahead = weekday - d.weekday() + if days_ahead >= 0: # Target day already happened this week + days_ahead -= 7 + return d + datetime.timedelta(days_ahead) + +def wiki2latex(intext): + intext = intext.replace(":\n", ":\n\n") + return pypandoc.convert_text(intext, 'latex', format='md') + +def j2replace(intext): + return j2env.from_string(intext).render(context) + +def date(indate): + return indate.strftime("%d.%m.%Y") + +def time(intime): + return intime.strftime("%H:%M") + +def weekday(indate): + return WEEKDAYS[indate.weekday()] + +def conf2top(top): + sender = None + body = None + protostub = None + try: + sender = top["sender"] + except KeyError: + pass + try: + body = top["body"] + except KeyError: + pass + try: + protostub = top["protostub"] + except KeyError: + pass + + return Top(top["title"], sender, body, protostub) + +if __name__ == "__main__": + parser = argparse.ArgumentParser() + parser.add_argument("--config", default=CONFIG_FILE) + mode = parser.add_mutually_exclusive_group(required=True) + mode.add_argument("--invite", action="store_true") + mode.add_argument("--presentation", action="store_true") + mode.add_argument("--protocol", action="store_true") + parser.add_argument("--write-mbox", action="store_true") + args = parser.parse_args() + + config = yaml.full_load(open(args.config)) + + if args.invite: + template_file = config["invite_template_file"] + elif args.presentation: + template_file = config["presentation_template_file"] + elif args.protocol: + template_file = config["protocol_template_file"] + else: + raise Exception("Should never happen") + + j2env = jinja2.Environment() + j2env.filters["wiki2latex"] = wiki2latex + j2env.filters["j2replace"] = j2replace + j2env.filters["date"] = date + j2env.filters["time"] = time + j2env.filters["weekday"] = weekday + template = j2env.from_string(open(template_file).read()) + + mbox = mailbox.mbox(config["top_mbox_file"]) + + current_date = next_weekday(datetime.date.today(), config["default_weekday"]) + next_date = next_weekday(current_date, config["default_weekday"]) + last_date = last_weekday(current_date, config["default_weekday"]) + + time = datetime.time.fromisoformat(config["default_time"]) + + pre_tops = [] + post_tops = [] + + for top in config["pre_tops"]: + pre_tops.append(conf2top(top)) + + for top in config["post_tops"]: + post_tops.append(conf2top(top)) + + email_tops = [] + + for message in mbox: + top = Top(message=message) + email_tops.append(top) + + to = pre_tops + email_tops + post_tops + + context = {"to": to, + "redeleitung": config["redeleitung"], + "protokoll": config["protokoll"], + "date": current_date, + "time": time, + "place": config["place"], + "next_date": next_date, + "last_date": last_date, + "meeting_link": config["meeting_link"], + "email_tops": email_tops, + "WEEKDAYS": WEEKDAYS} + + if args.write_mbox: + msg = email.message.EmailMessage() + msg.set_content(template.render(context)) + msg["Subject"] = j2env.from_string(config["invite_subject"]).render(context) + msg["From"] = config["redeleitung"]["email"] + msg["To"] = config["invite_mail"] + mbox = mailbox.mbox(config["mbox_out"]) + mbox.add(msg) + mbox.close() + print(mbox) + else: + print(template.render(context)) diff --git a/generator.conf.example b/generator.conf.example new file mode 100644 index 0000000..797e414 --- /dev/null +++ b/generator.conf.example @@ -0,0 +1,60 @@ +redeleitung: + name: Rede Leitung + email: rede.leitung@fsmi.uni-karlsruhe.de + +protokoll: + name: Protokoll Ant + +pre_tops: + - title: Begrüßung + protostub: Der FSR wird begrüßt + - title: Feststellung der Beschlussfähigkeit + protostub: Der FSR ist beschlussfähig + - title: Tagesordnung + body: '\tableofcontents' + protostub: '{% for top in to %}# {{top.title}} + +{% endfor %}' + - title: Unbeantwortete E-Mails + protostub: 'Die E-Mails wurden verteilt' + - title: Unveröffentlichte Protokolle + body: "* FSR-Protokoll vom {{last_date|date}}" + - title: Berichte + protostub: + +post_tops: + - title: Nächster FSR + body: 'Wann: {{next_date.strftime("%d.%m.%Y")}} {{time.strftime("%H:%M")}} \linebreak + Wo: {{place}} \linebreak + Redeleitung: ? \linebreak + Protokoll: ?' + protostub: '* Termin: {{next_date.strftime("%d.%m.%Y")}} + +* Ort: {{place}} + +* nächste Redeleitung: XXXXXXXX + +* nächstes Protokoll: XXXXXXXX' + - title: Termine + protostub: '{| +{{"{{"}}Termin|was=AAAAAAAAAA|wann=XX.YY.{{"}}"}} +|}' + - title: Sonstiges + +invite_template_file: templates/fsr_einladung.j2 +presentation_template_file: templates/fsr_presentation.tex.j2 +protocol_template_file: templates/fsr_protokoll.j2 + +top_mbox_file: fsr_tops.mbox + +default_weekday: 2 #Mittwoch +default_time: "17:30" +meeting_link: https://meet.vs.kit.edu/b/abc-def-ghi +place: BigBlueButton + +invite_mail: alle@fsmi.uni-karlsruhe.de +invite_subject: 'Einladung zum Fachschaftsrat am {{date|weekday}}, dem {{date|date}}' + +mbox_out: invitemail.mbox + +# vim: filetype=yaml diff --git a/templates/fsr_einladung.j2 b/templates/fsr_einladung.j2 new file mode 100644 index 0000000..87adab6 --- /dev/null +++ b/templates/fsr_einladung.j2 @@ -0,0 +1,41 @@ +Hallo, + +hiermit lade ich euch zum nächsten Fachschaftsrat ein. Er findet statt +am: + +{{date|weekday}}, den {{date|date}} um {{time|time}} Uhr + +via Microsoft Teams (App, Chrome, Edge oder Safari; nicht Firefox) [0] +Es ist keine Anmeldung über das KIT notwendig, +mehr Informationen unter [1] + +Bitte auch die Nettiquette beachten [2]: +- Rechtzeitig da sein +- Mikro aus machen wenn man nicht redet +- Video aus wg. Bandbreite +- Wenn möglich Headset verwendet + +Die Antragstexte für die eingereichten TOPs sind unten angehangen. +Die vorläufige Tagesordnung lautet: + +{% for top in to %}{{ "%02d" % loop.index}} {{top.title}} +{% endfor %} + +Bitte sendet vorher die Berichte an das Protokollamt[3] zu. + +[0] {{meeting_link}} +[1] https://www.scc.kit.edu/dienste/ms-teams.php +[2] Auszug vom SCC https://www.scc.kit.edu/dienste/ms-teams.php +[3] protokollant@fsmi.uni-karlsruhe.de + +Viele Grüße, +{{redeleitung.name}} + + +Eingereichte TOPs: +{% for top in email_tops %} += {{top.title}} = +Eingereicht von: {{top.sender}} + +{{top.body}} +{% endfor %} diff --git a/templates/fsr_presentation.tex.j2 b/templates/fsr_presentation.tex.j2 new file mode 100644 index 0000000..5531157 --- /dev/null +++ b/templates/fsr_presentation.tex.j2 @@ -0,0 +1,40 @@ +\documentclass[aspectratio=169, smaller]{beamer} +\mode { + %\setbeameroption{show notes on second screen=right} + %\setbeameroption{show only notes} +} + +{% raw %} +\providecommand{\tightlist}{% + \setlength{\itemsep}{0pt}\setlength{\parskip}{0pt}} +{% endraw %} + +\usepackage{pgfpages} +\usepackage[ngerman]{babel} +\usepackage[utf8]{inputenc} +\usepackage{graphicx} +\usepackage{fancyvrb} + +\usetheme[width=3cm]{Berkeley} +\usecolortheme{sidebartab} +\setbeamertemplate{navigation symbols}{} + +\title{Fachschaftsrat Mathe/Info} +\author{Redeleitung: {{redeleitung.name}} \\Protokoll: {{protokoll.name}} } +\date{ {{date.strftime("%d.%m.%Y")}} } +\logo{\includegraphics[width=17mm]{fslogo}} + +\begin{document} +\begin{frame} + \maketitle +\end{frame} + +{% for top in to %} +\section{ {{top.title}} } +\begin{frame}{% if top.body and top.body|length > 500 %}[allowframebreaks]{%endif%} + \frametitle{ {{top.title}} } +{{top.body|j2replace|wiki2latex if top.body}} +\end{frame} +{% endfor %} + +\end{document} diff --git a/templates/fsr_protokoll.j2 b/templates/fsr_protokoll.j2 new file mode 100644 index 0000000..5ded502 --- /dev/null +++ b/templates/fsr_protokoll.j2 @@ -0,0 +1,26 @@ +{{ '{{' }}Protokollkopf +|was=Fachschaftsrat +|datum={{date.strftime("%d.%m.%Y")}} +|ort={{place}} +|anfang={{time.strftime("%H:%M")}} +|ende=XX:YY +|redeleitung={{redeleitung.name}} +|protokollant={{protokoll.name}} +|anwesende= + +* {{redeleitung.name}} (Fak) +* {{protokoll.name}} (Fak) +* Weitere + +|veröffentlicht=Unveröffentlicht{{ '}}' }} + +{% for top in to %} += {{top.title}} = +{%if top.sender%}Eingereicht von: {{top.sender}} + +{%endif%}{%if top.protostub%}{{top.protostub|j2replace}} +{% elif top.body %}{{top.body|j2replace}} +{% endif %} +{% endfor %} + +[[Kategorie:Protokoll]]