From ff0b2028aa729c38f5195af2f954d44e0d0d1669 Mon Sep 17 00:00:00 2001
From: Nils Beyer <nilsb@fsmpi.rwth-aachen.de>
Date: Mon, 21 Mar 2022 14:56:50 +0100
Subject: [PATCH] =?UTF-8?q?Exportieren=20von=20TOP,=20erste=20lauff=C3=A4h?=
 =?UTF-8?q?ige=20Version?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 configproxy.py                                |   4 +-
 ...67242e8_append_extra_column_to_document.py |  28 +++++
 models/database.py                            |   1 +
 protoparser.py                                |  49 ++++++--
 tasks.py                                      |  41 ++++++-
 templates/documentation-syntax-top.html       |  15 +++
 templates/extra.tex                           | 113 ++++++++++++++++++
 7 files changed, 238 insertions(+), 13 deletions(-)
 create mode 100644 migrations/versions/7834767242e8_append_extra_column_to_document.py
 create mode 100644 templates/extra.tex

diff --git a/configproxy.py b/configproxy.py
index 7d5ce97..7488c42 100755
--- a/configproxy.py
+++ b/configproxy.py
@@ -766,8 +766,8 @@ CONFIG_SECTIONS = [
                     "files: e.g. the files for the template 'yourtemplate' "
                     "need to be in the folder named 'yourtemplate', and the "
                     "templates provides the files: 'protokoll2.cls' (class), "
-                    "'protocol.tex' (protocol), 'decision.tex' (decision) and "
-                    "'asta-logo.tex'")),
+                    "'protocol.tex' (protocol), 'decision.tex' (decision),"
+                    "'extra.tex' (exported TOP) and 'asta-logo.tex'")),
         ],
         check=check_rendering,
         description="Settings for rendering protocols to pdf, html, etc."),
diff --git a/migrations/versions/7834767242e8_append_extra_column_to_document.py b/migrations/versions/7834767242e8_append_extra_column_to_document.py
new file mode 100644
index 0000000..d63b141
--- /dev/null
+++ b/migrations/versions/7834767242e8_append_extra_column_to_document.py
@@ -0,0 +1,28 @@
+"""Append extra column to Document
+
+Revision ID: 7834767242e8
+Revises: ead59eff0835
+Create Date: 2022-03-21 11:46:20.368800
+
+"""
+from alembic import op
+import sqlalchemy as sa
+
+
+# revision identifiers, used by Alembic.
+revision = '7834767242e8'
+down_revision = 'ead59eff0835'
+branch_labels = None
+depends_on = None
+
+
+def upgrade():
+    # ### commands auto generated by Alembic - please adjust! ###
+    op.add_column('documents', sa.Column('is_extra', sa.Boolean(), default=False, nullable=True))
+    # ### end Alembic commands ###
+
+
+def downgrade():
+    # ### commands auto generated by Alembic - please adjust! ###
+    op.drop_column('documents', 'is_extra')
+    # ### end Alembic commands ###
diff --git a/models/database.py b/models/database.py
index 59e71ce..411ad1b 100644
--- a/models/database.py
+++ b/models/database.py
@@ -540,6 +540,7 @@ class Document(DatabaseModel):
     name = db.Column(db.Text)
     filename = db.Column(db.Text)
     is_compiled = db.Column(db.Boolean)
+    is_extra = db.Column(db.Boolean)
     is_private = db.Column(db.Boolean)
 
     def get_parent(self):
diff --git a/protoparser.py b/protoparser.py
index cf90277..45d55a4 100644
--- a/protoparser.py
+++ b/protoparser.py
@@ -38,6 +38,7 @@ class RenderType(Enum):
     plaintext = 2
     html = 3
     dokuwiki = 4
+    extra = 5
 
 
 def _not_implemented(self, render_type):
@@ -187,7 +188,7 @@ class Text:
         self.fork = fork
 
     def render(self, render_type, show_private, level=None, protocol=None):
-        if render_type == RenderType.latex:
+        if render_type == RenderType.latex or render_type == RenderType.extra:
             return escape_tex(self.text)
         elif render_type == RenderType.wikitext:
             return self.text
@@ -244,6 +245,22 @@ class Tag:
             return r"\textbf{{{}:}} {}".format(
                 escape_tex(self.name.capitalize()),
                 escape_tex(";".join(self.values)))
+        elif render_type == RenderType.extra:
+            if self.name == "url":
+                return r"\url{{{}}}".format(self.values[0])
+            elif self.name == "todo":
+                return ""
+            elif self.name == "beschluss":
+                return (
+                            r"\begin{tcolorbox}[breakable,title=Beschluss, colframe=red!45!yellow, colback=yellow!10, coltitle=white,]" + "\n"
+                            + r"\begin{itemize}"
+                            + r"\item[] " + self.values[0] + "\n"
+                            + r"\end{itemize} \end{tcolorbox}")
+            elif self.name == "footnote":
+                return r"\footnote{{{}}}".format(self.values[0])
+            return r"\textbf{{{}:}} {}".format(
+                escape_tex(self.name.capitalize()),
+                escape_tex(";".join(self.values)))
         elif render_type == RenderType.plaintext:
             if self.name == "url":
                 return self.values[0]
@@ -357,7 +374,7 @@ class Remark(Element):
         self.linenumber = linenumber
 
     def render(self, render_type, show_private, level=None, protocol=None):
-        if render_type == RenderType.latex:
+        if render_type == RenderType.latex or render_type == RenderType.extra:
             return r"\textbf{{{}}}: {}".format(self.name, self.value)
         elif render_type == RenderType.wikitext:
             return "{}: {}".format(self.name, self.value)
@@ -428,27 +445,39 @@ class Fork(Element):
         name_line = self.name if self.name is not None else ""
         if level == 0 and self.name == "Todos" and not show_private:
             return ""
-        if render_type == RenderType.latex:
-            if self.is_extra:
+        if render_type == RenderType.latex or render_type == RenderType.extra:
+            if render_type == RenderType.latex and self.is_extra:
                 return r"\textit{[Dieser Tagesordnungspunkt wird in einem eigenem PDF exportiert.]}"
 
             begin_line = r"\begin{itemize}"
             end_line = r"\end{itemize}"
             content_parts = []
+            parts = []
             for child in self.children:
                 part = child.render(
                     render_type, show_private, level=level + 1,
                     protocol=protocol)
+                parts.append(part)
                 if len(part.strip()) == 0:
                     continue
-                if not part.startswith(r"\item"):
-                    part = r"\item {}".format(part)
+                if render_type == RenderType.latex:
+                    if not part.startswith(r"\item"):
+                        part = r"\item {}".format(part)
+                elif render_type == RenderType.extra:
+                    if not part.startswith(r"\item") and not part.startswith(r"\footnote") and not part.startswith(
+                            r"\begin{tcolorbox}"):
+                        part = r"\item {}".format(part)
+                    elif part.startswith(r"\begin{tcolorbox}"):
+                        part = r"\item[] {}".format(part)
                 content_parts.append(part)
             content_lines = "\n".join(content_parts)
             if len(content_lines.strip()) == 0:
                 content_lines = "\\item Nichts\n"
             if level == 0:
-                return "\n".join([begin_line, content_lines, end_line])
+                if render_type == RenderType.latex:
+                    return "\n".join([begin_line, content_lines, end_line])
+                elif render_type == RenderType.extra:
+                    return "\n".join(parts)
             elif self.test_private(self.name):
                 if show_private:
                     return (r"\begin{tcolorbox}[breakable,title=Interner "
@@ -460,6 +489,12 @@ class Fork(Element):
                 else:
                     return (r"\textit{[An dieser Stelle wurde intern "
                             r"protokolliert.]}")
+            elif render_type == RenderType.extra and level == 1:
+                name_escape = escape_tex(name_line)
+                return "\n".join([
+                    f"\section{{{name_escape}}}", begin_line,
+                    content_lines, end_line
+                ])
             else:
                 return "\n".join([
                     escape_tex(name_line), begin_line,
diff --git a/tasks.py b/tasks.py
index 25b4df1..7c1e9a2 100644
--- a/tasks.py
+++ b/tasks.py
@@ -70,7 +70,8 @@ def provide_latex_template(template, documenttype):
     _DOCUMENTTYPE_FILENAME_MAP = {
         "class": "protokoll2.cls",
         "protocol": "protocol.tex",
-        "decision": "decision.tex"
+        "decision": "decision.tex",
+        "extra": "extra.tex"
     }
     _PROVIDES = "provides"
     _LOGO_TEMPLATE = "logo_template"
@@ -558,6 +559,21 @@ def parse_protocol_async_inner(protocol, ignore_old_date=False):
             latex_source, protocol, show_private=show_private,
             maxdepth=maxdepth)
 
+    # Export extra TOPs
+    extra_tops = [child for child in tree.children if isinstance(child, Fork) and child.is_extra]
+    for top in extra_tops:
+        for show_private in privacy_states:
+            latex_source = texenv.get_template(provide_latex_template(
+                protocol.protocoltype.latex_template, "extra")).render(
+                    render_type=RenderType.extra,
+                    top=top,
+                    show_private=show_private,
+                    **render_kwargs[show_private])
+            compile_extra(
+                latex_source, protocol, show_private=show_private, extra_name=top.name,
+                maxdepth=maxdepth)
+
+
     if protocol.protocoltype.use_wiki:
         wiki_type = WikiType[getattr(config, "WIKI_TYPE", "MEDIAWIKI")]
         wiki_template = {
@@ -644,10 +660,13 @@ def compile_decision(content, decision, maxdepth):
     compile_async.delay(
         content, decision.id, use_decision=True, maxdepth=maxdepth)
 
+def compile_extra(content, protocol, show_private, maxdepth, extra_name):
+    compile_async.delay(
+        content, protocol.id, use_decision=False, show_private=show_private, maxdepth=maxdepth, is_extra=True, extra_name=extra_name)
 
 @celery.task
 def compile_async(
-        content, protocol_id, show_private=False, use_decision=False,
+        content, protocol_id, show_private=False, use_decision=False, is_extra=False, extra_name="",
         maxdepth=5):
     with tempfile.TemporaryDirectory() as compile_dir, app.app_context():
         decision = None
@@ -692,7 +711,7 @@ def compile_async(
                 stderr=subprocess.DEVNULL)
             os.chdir(current)
             document = None
-            if not use_decision:
+            if not use_decision and not is_extra:
                 for old_document in [
                     document for document in protocol.documents
                     if document.is_compiled
@@ -708,7 +727,7 @@ def compile_async(
                     filename="",
                     is_compiled=True,
                     is_private=show_private)
-            else:
+            elif use_decision and not is_extra:
                 document = DecisionDocument(
                     decision_id=decision.id,
                     name="beschluss_{}_{}_{}.pdf".format(
@@ -716,6 +735,20 @@ def compile_async(
                         date_filter_short(protocol.date),
                         decision.id),
                     filename="")
+            elif is_extra and not use_decision:
+                document = Document(
+                    protocol_id=protocol.id,
+                    name="extra-{}{}_{}_{}.pdf".format(
+                        extra_name,
+                        "_intern" if show_private else "",
+                        protocol.protocoltype.short_name,
+                        date_filter_short(protocol.date)),
+                    filename="",
+                    is_compiled=True,
+                    is_extra=True,
+                    is_private=show_private)
+            else:
+                raise NotImplementedError("Unknown type.")
             db.session.add(document)
             db.session.commit()
             target_filename = "compiled-{}-{}.pdf".format(
diff --git a/templates/documentation-syntax-top.html b/templates/documentation-syntax-top.html
index 90a5a20..e3945f2 100644
--- a/templates/documentation-syntax-top.html
+++ b/templates/documentation-syntax-top.html
@@ -40,4 +40,19 @@
 			</div>
         </div>
     </div>
+    <h4>Exportieren</h4>
+    <p>
+        Außerdem kann ein Tagesordnungspunkt auch so angelegt werden, dass ein eigenes PDF für diesen angelegt wird, und im Hauptprotokoll auf dieses PDF verwiesen wird. Dies wird durch ein Hinzufügen eines Ausrufezeichens (<span class="highlight"><span class="kr">!</span></span>) vor dem Schlüsselword <span class="highlight"><span class="kr">TOP</span></span> erreicht.
+    </p>
+    <div class="panel panel-default">
+        <div class="panel-heading">
+            <h5 class="panel-title">Tagesordnungspunkt in eigenem PDF</a></h5>
+        </div>
+        <figure class="panel-body">
+            <pre class="highlight"><code>{<span class="kr">!TOP</span> <span class="sx">Titel des Tagesordnungspunkts</span>
+    <span class="c1">Hier steht der Inhalt des Tagesordnungspunkts</span>
+    <span class="c1">Dies wird in einem separaten PDF exportiert</span>
+}</code></pre>
+        </figure>
+    </div>
 {% endblock %}
diff --git a/templates/extra.tex b/templates/extra.tex
new file mode 100644
index 0000000..4ed2894
--- /dev/null
+++ b/templates/extra.tex
@@ -0,0 +1,113 @@
+% Template created by Karol Kozioł (www.karol-koziol.net) for ShareLaTeX
+% Template adapted by Nils Beyer
+
+\documentclass[a4paper,ngerman,twocolumn,9pt]{extarticle}
+\usepackage[utf8]{inputenc}
+
+\usepackage{ifthen}
+\newboolean{intern}
+\newcommand{\intern}[2]{\ifthenelse{\boolean{intern}}{#1}{#2} }
+
+\usepackage[T1]{fontenc}
+\usepackage{verbatim}
+\usepackage{graphicx}
+\usepackage{xcolor}
+\usepackage{pgf,tikz}
+\usepackage{mathrsfs}
+
+\usepackage{csquotes}
+\usepackage{tcolorbox}
+\tcbuselibrary{listings,breakable}
+\usepackage{draftwatermark}
+\SetWatermarkText{}
+\SetWatermarkScale{1}
+
+\usetikzlibrary{shapes, calc, shapes, arrows, babel}
+
+\usepackage{amsmath,amssymb,textcomp}
+\everymath{\displaystyle}
+
+\usepackage{times}
+\renewcommand\familydefault{\sfdefault}
+\usepackage{tgheros}
+
+\usepackage{multicol}
+\setlength{\columnseprule}{0.5pt}
+\setlength{\columnsep}{20.0pt}
+
+\usepackage[utf8]{inputenc}
+\usepackage[ngerman]{babel}
+\usepackage{eurosym}
+
+\usepackage{hyperref}
+
+\usepackage{geometry}
+\geometry{
+	a4paper,
+	total={210mm,297mm},
+	left=10mm,right=10mm,top=10mm,bottom=15mm}
+
+\linespread{1.2}
+
+
+% custom section titles
+\usepackage[explicit]{titlesec}
+\newcommand*\sectionlabel{}
+\titleformat{\section}
+%  {\gdef\sectionlabel{}\normalfont\sffamily\Large\bfseries\scshape}
+{\gdef\sectionlabel{}\normalfont\sffamily\bfseries}
+{\gdef\sectionlabel{\thesection }}{0pt}
+{
+	\noindent
+	\begin{tikzpicture}
+		\node[rectangle,rounded corners=1pt,inner sep=4pt,fill=red!45!black,text width=0.95\columnwidth] {\color{white}\sectionlabel #1};
+	\end{tikzpicture}
+}
+\titlespacing*{\section}{0pt}{10pt}{0pt}
+
+% Numbering style
+\renewcommand*{\thesection}{\Roman{section}~: }
+
+
+% custom footer
+\usepackage{fancyhdr}
+\makeatletter
+\pagestyle{fancy}
+\fancyhead{}
+\renewcommand{\headrulewidth}{0pt}
+\renewcommand{\footrulewidth}{0pt}
+\makeatother
+
+% href boxes
+\hypersetup{
+	colorlinks,
+	linkcolor={red!50!black},
+	citecolor={blue!50!black},
+	urlcolor={blue!80!black}
+}
+
+% Line numbers on sides
+\usepackage[switch,columnwise]{lineno}
+
+
+\setlength{\parindent}{0em}
+\usepackage{enumitem}
+\setlist{nosep}
+
+\newcommand{\Beschluss}[2][]{\textbf{Beschluss:} #2 \def\temp{#1}\ifx\temp\empty\else\textit{(#1)}\fi}
+
+
+\ENV{if show_private}\setboolean{intern}{true}\ENV{endif}
+\intern{\SetWatermarkText{INTERN} \SetWatermarkScale{1}}{}
+\begin{document}
+    \small
+    \begin{center}
+        \VAR{top.name|escape_tex} zur \textsc{\VAR{protocol.protocoltype.name|escape_tex}} am \VAR{protocol.date|datify_long|escape_tex}
+    \end{center}
+
+    \ENV{if top|class == "Fork"}
+        \VAR{top.render(render_type=render_type, level=0, show_private=show_private, protocol=protocol)}
+    \ENV{endif}
+
+    \runningpagewiselinenumbers \linenumbers
+\end{document}
\ No newline at end of file
-- 
GitLab