From 72e8a88214c3ba21e7a3f17d6b62c0fc80cdbfb7 Mon Sep 17 00:00:00 2001
From: Robin Sonnabend <robin@fsmpi.rwth-aachen.de>
Date: Thu, 23 Feb 2017 00:14:40 +0100
Subject: [PATCH] Compiling the latex version works

---
 parser.py                                 |   2 +-
 static/tex/protokoll2.cls                 | 175 ++++++++++++++++++++++
 tasks.py                                  |  95 ++++++------
 templates/{protokoll.tex => protocol.tex} |   6 +-
 4 files changed, 229 insertions(+), 49 deletions(-)
 create mode 100644 static/tex/protokoll2.cls
 rename templates/{protokoll.tex => protocol.tex} (89%)

diff --git a/parser.py b/parser.py
index 5ded4da..f5cf680 100644
--- a/parser.py
+++ b/parser.py
@@ -243,7 +243,7 @@ class Remark(Element):
 class Fork(Element):
     def __init__(self, environment, name, parent, linenumber, children=None):
         self.environment = environment if environment is None or len(environment) > 0 else None
-        self.name = name if name is None or len(name) > 0 else None
+        self.name = name.strip() if (name is not None and len(name) > 0) else None
         self.parent = parent
         self.linenumber = linenumber
         self.children = [] if children is None else children
diff --git a/static/tex/protokoll2.cls b/static/tex/protokoll2.cls
new file mode 100644
index 0000000..d12c78f
--- /dev/null
+++ b/static/tex/protokoll2.cls
@@ -0,0 +1,175 @@
+% protokoll.cls -- version 0.1 -- last changed: see mtime of the file ;)
+%
+%
+% Author: Sebastian G�nther <samson@asta.rwth-aachen.de>
+
+% zuerst mal LaTeX's formalzeug
+\NeedsTeXFormat{LaTeX2e}
+\ProvidesClass{protokoll2}[2004/06/04 protokoll.cls v0.1 macht Protokolle (VV)]
+\DeclareOption*{\PassOptionsToClass{\CurrentOption}{article}}
+%\ExecuteOptions{draft}
+\ProcessOptions\relax
+
+% die restlichen optionen geben wir an article weiter
+\LoadClass[a4paper]{article}
+
+% so ein paar sachen die wir eh immer brauchen
+\RequirePackage{ngerman}
+\RequirePackage[T1]{fontenc}
+\RequirePackage[utf8]{inputenc}
+\RequirePackage[vmargin=1.5cm,hmargin={1.5cm,1.2cm},bindingoffset=8mm]{geometry}
+%\RequirePackage{lineno}
+\RequirePackage{longtable}
+\RequirePackage{framed}
+\RequirePackage{eurosym}
+\RequirePackage{csquotes}
+
+
+% nicht einr�cken und benutzerinnendefinierte kopfzeile
+\setlength{\parindent}{0cm}
+\setlength{\parskip}{1ex}
+\pagestyle{myheadings}
+
+\renewcommand*{\rmdefault}{phv}
+\renewcommand*{\sfdefault}{phv}
+
+% Titel
+\newcommand{\Kopf}[1]{\markboth{#1}{#1}}
+\newcommand{\Titel}[2]{
+  \markboth{#2}{#2}
+  \markright{#2}
+  \thispagestyle{plain}
+  \begin{center}
+    \textbf{#1}
+  \end{center}
+}
+
+% Tops
+\renewcommand{\thesection}{TOP~\arabic{section}}
+\renewcommand{\thesubsection}{TOP~\arabic{section}~(\alph{subsection})}
+\newcommand{\TOP}[1]{\section{#1}}
+\newcommand{\unterTOP}[1]{\subsection{#1}}
+% F�rs Inhaltsverzeichnisanpassen
+\renewcommand{\l@section}{\@dottedtocline{1}{1.5em}{4em}}
+\renewcommand{\l@subsection}{\@dottedtocline{2}{5.5em}{5.2em}}
+\renewcommand{\contentsname}{Tagesordnung}
+\newcommand{\Inhalt}{\tableofcontents}
+
+% Zeilen-Numerierungen
+\newcommand{\ZeilenNummerierung}{\pagewiselinenumbers\linenumbers}
+\newcommand{\EndeZeilenNummerierung}{\nolinenumbers}
+
+% Anwesenheit
+\newenvironment{Anw}{\begin{list}{}{%
+      \renewcommand{\makelabel}[1]{\hfill ##1 }%
+      \settowidth{\labelwidth}{Anwesenheit:~}%
+      \addtolength{\labelwidth}{\labelsep}%
+      \setlength{\leftmargin}{\labelwidth}%
+      \addtolength{\leftmargin}{\labelsep}%
+      \addtolength{\leftmargin}{\labelsep}%
+      \setlength{\itemsep}{0pt}%
+      \setlength{\parsep}{0pt}%
+      \setlength{\topsep}{0pt}%
+    }%
+}%
+{\end{list}}
+
+% Abwesenheit
+\newenvironment{Abw}{\begin{list}{}{%
+      \renewcommand{\makelabel}[1]{\hfill ##1 }%
+      \settowidth{\labelwidth}{Anwesenheit:~}%
+      \addtolength{\labelwidth}{\labelsep}%
+      \setlength{\leftmargin}{\labelwidth}%
+      \addtolength{\leftmargin}{\labelsep}%
+      \addtolength{\leftmargin}{\labelsep}%
+      \setlength{\itemsep}{0pt}%
+      \setlength{\parsep}{0pt}%
+      \setlength{\topsep}{0pt}%
+    }%
+}%
+{\end{list}}
+
+% Abk�rzungen
+\newenvironment{Abk}{%
+  \begin{list}{}{%
+	Abkürzungen:
+      \renewcommand{\makelabel}[1]{\hfill ##1 }%
+      \setlength{\labelwidth}{2cm}%
+      \addtolength{\labelwidth}{\labelsep}%
+      \setlength{\leftmargin}{\labelwidth}%
+      \addtolength{\leftmargin}{\labelsep}%
+      \addtolength{\leftmargin}{\labelsep}%
+      \setlength{\itemsep}{0pt}%
+      \setlength{\parsep}{0pt}%
+      \setlength{\topsep}{0pt}%
+    }%
+}%
+{\end{list}}
+
+% Unterschriften f�r eine und zwei Personen
+\newcommand{\Unterschrift}[2]{
+  \vspace*{1.4cm}
+  \begin{center}
+    \rule{.4\linewidth}{.15mm} \\
+    #1 \\
+    \footnotesize{(#2)}
+  \end{center}
+}
+\newcommand{\ZweiUnterschrift}[4]{
+  \vspace*{1.4cm}
+  \begin{center}
+    \parbox[t]{.4\linewidth}{
+      \rule{\linewidth}{.15mm} \\
+      \vspace*{-.4cm}\begin{center}
+        #1 \\
+	\footnotesize{(#2)}
+      \end{center}
+    }
+    \hspace*{.1\linewidth}
+    \parbox[t]{.4\linewidth}{
+      \rule{\linewidth}{.15mm} \\
+      \vspace*{-.4cm}\begin{center}
+	#3 \\
+	\footnotesize{(#4)}
+      \end{center}
+    }
+  \end{center}
+}
+
+% \newcommand{\Antrag}[1]{
+% %  \setlength{\arrayrulewidth}{2mm}
+% %  \begin{longtable}{|ll}
+% %    \hspace{2mm} & \parbox[t]{17cm}{#1}
+% %  \end{longtable}
+%   \begingroup
+%   \rule{2mm}{2mm}
+%   \leftskip10cm
+% %  \rightskip\leftskip
+%   #1
+%   \par
+%   \endgroup
+% }
+
+\newcommand{\Antrag}[1]{
+  \setlength{\arrayrulewidth}{2mm}
+  \begin{longtable}{|ll}
+   % \hspace{2mm} & \parbox[t]{17cm}{#1}
+    \hspace{2mm} & \begin{minipage}{17cm} #1\end{minipage}
+  \end{longtable}
+}
+
+\newenvironment{antrag}
+{%
+  \par%
+  \begingroup%
+  \leftskip1cm%
+}
+{\par\endgroup}
+
+
+\newcommand{\Bericht}[1]{
+  \Antrag{#1}
+}
+
+\newcommand{\PE}[2]{\textbf{Persönliche Erklärung von #1:}\\\emph{\glqq{}#2\grqq{}}\\}
+
diff --git a/tasks.py b/tasks.py
index 47102ca..52dfac1 100644
--- a/tasks.py
+++ b/tasks.py
@@ -3,6 +3,7 @@ from flask import render_template
 import os
 import subprocess
 import shutil
+import tempfile
 
 from models.database import Document, Protocol, Error, Todo, Decision, TOP, DefaultTOP
 from server import celery, app
@@ -49,7 +50,8 @@ def parse_protocol_async(protocol_id, encoded_kwargs):
             protocol = Protocol.query.filter_by(id=protocol_id).first()
             if protocol is None:
                 raise Exception("No protocol given. Aborting parsing.")
-            for error in protocol.errors:
+            old_errors = list(protocol.errors)
+            for error in old_errors:
                 protocol.errors.remove(error)
             db.session.commit()
             if protocol.source is None:
@@ -158,55 +160,58 @@ def parse_protocol_async(protocol_id, encoded_kwargs):
                 top = TOP(protocol.id, fork.name, index, False)
                 db.session.add(top)
             db.session.commit()
-            protocol.done = True
-            db.session.commit()
 
+            latex_source = texenv.get_template("protocol.tex").render(protocol=protocol, tree=tree)
+            compile(latex_source, protocol)
 
-            
+            protocol.done = True
+            db.session.commit()
 
+def compile(content, protocol):
+    compile_async.delay(content, protocol.id)
 
 @celery.task
-def compile_async(name, document_id):
-    is_error = False
-    try:
-        current = os.getcwd()
-        os.chdir("latex")
-        os.makedirs("bin", exist_ok=True)
-        command = [
-            "/usr/bin/xelatex",
-            "-halt-on-error",
-            "-file-line-error",
-            "-output-directory", "bin",
-            "{}.tex".format(name)
-        ]
-        subprocess.check_call(command, universal_newlines=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
-        subprocess.check_call(command, universal_newlines=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
-        os.chdir(current)
-        os.makedirs("documents/pdf", exist_ok=True)
-        shutil.copy("latex/bin/{}.pdf".format(name), "documents/pdf/")
-        for typ in ["pdf", "log", "aux", "out"]:
-            silent_remove("latex/bin/{}.{}".format(name, typ))
-        silent_remove("latex/{}.tex".format(name))
-    except subprocess.SubprocessError:
-        is_error = True
-        with app.app_context():
-            document = Document.query.filter_by(id=document_id).first()
-            if document is not None:
-                document.ready = False
-                document.error = True
-                db.session.commit()
-    finally:
-        # TODO: activate deleting files in error case too
-        #for typ in ["pdf", "log", "aux", "out"]:
-        #    silent_remove("latex/bin/{}.{}".format(name, typ))
-        #silent_remove("latex/{}.tex".format(name))
-        os.chdir(current)
-    if not is_error:
-        with app.app_context():
-            document = Document.query.filter_by(id=document_id).first()
-            if document is not None:
-                document.ready = True
-                db.session.commit()
+def compile_async(content, protocol_id):
+    with tempfile.TemporaryDirectory() as compile_dir, app.app_context():
+        protocol = Protocol.query.filter_by(id=protocol_id).first()
+        try:
+            current = os.getcwd()
+            protocol_source_filename = "protocol.tex"
+            protocol_target_filename = "protocol.tex"
+            log_filename = "protocol.log"
+            with open(os.path.join(compile_dir, protocol_source_filename), "w") as source_file:
+                source_file.write(content)
+            shutil.copy("static/tex/protokoll2.cls", compile_dir)
+            os.chdir(compile_dir)
+            command = [
+                "/usr/bin/xelatex",
+                "-halt-on-error",
+                "-file-line-error",
+                protocol_source_filename
+            ]
+            subprocess.check_call(command, universal_newlines=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
+            subprocess.check_call(command, universal_newlines=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
+            os.chdir(current)
+            document = Document(protocol.id, name="protokoll_{}_{}.pdf".format(protocol.protocoltype.short_name, date_filter(protocol.date)), filename="", is_compiled=True)
+            db.session.add(document)
+            db.session.commit()
+            target_filename = "compiled-{}.pdf".format(document.id)
+            document.filename = target_filename
+            shutil.copy(os.path.join(compile_dir, protocol_target_filename), os.path.join("documents", target_filename))
+            db.session.commit()
+        except subprocess.SubprocessError:
+            log = ""
+            total_log_filename = os.path.join(compile_dir, log_filename)
+            if os.path.isfile(total_log_filename):
+                with open(total_log_filename, "r") as log_file:
+                    log = log_file.read()
+            else:
+                log = "Logfile not found."
+            error = protocol.create_error("Compiling", "Compiling LaTeX failed", log)
+            db.session.add(error)
+            db.session.commit()
+        finally:
+            os.chdir(current)
 
 def send_mail(mail):
     send_mail_async.delay(mail.id)
diff --git a/templates/protokoll.tex b/templates/protocol.tex
similarity index 89%
rename from templates/protokoll.tex
rename to templates/protocol.tex
index 5616e1b..1bf29fd 100644
--- a/templates/protokoll.tex
+++ b/templates/protocol.tex
@@ -33,7 +33,7 @@
 \begin{itemize}
 \ENV{if protocol.decisions|length > 0}
     \ENV{for decision in protocol.decisions}
-        \item \VAR{decisions.content|escape_tex}
+        \item \VAR{decision.content|escape_tex}
     \ENV{endfor}
 \ENV{else}
 	\item Keine Beschlüsse
@@ -43,8 +43,8 @@
 Beginn der Sitzung: \VAR{protocol.start_time|timify}
 
 \ENV{for top in tree.children}
-    \TOP{\VAR{top.name}} % here we probably have information doubly
-    \VAR{top.render()}
+    \TOP{\VAR{top.name|escape_tex}} % here we probably have information doubly
+    \VAR{top.render()|escape_tex}
 \ENV{endfor}
 
 Ende der Sitzung: \VAR{protocol.end_time|timify}
-- 
GitLab