119 lines
3.2 KiB
Python
119 lines
3.2 KiB
Python
|
# Copyright Sage Vaillancourt 2021
|
||
|
|
||
|
import os
|
||
|
import subprocess
|
||
|
from dataclasses import dataclass
|
||
|
|
||
|
from flask import send_from_directory, Response
|
||
|
|
||
|
|
||
|
root_dir = os.path.dirname(os.getcwd())
|
||
|
proj_dir = root_dir + '/undercover/'
|
||
|
output_dir = proj_dir + 'outputs/'
|
||
|
|
||
|
base_tex_text = open(proj_dir + '/letter_templates/base.tex', 'r').read()
|
||
|
|
||
|
|
||
|
@dataclass
|
||
|
class CLData:
|
||
|
# Metadata:
|
||
|
selectedLetter: int
|
||
|
|
||
|
# Form Data:
|
||
|
username: str
|
||
|
company: str
|
||
|
jobAndPronoun: str
|
||
|
skillTypes: str
|
||
|
mySkills: str
|
||
|
closingText: str
|
||
|
body: str
|
||
|
|
||
|
def get_pairs(self) -> list[(str, str)]:
|
||
|
return [
|
||
|
('username', self.username),
|
||
|
('company', self.company),
|
||
|
('jobAndPronoun', self.jobAndPronoun),
|
||
|
('skillTypes', self.skillTypes),
|
||
|
('mySkills', self.mySkills),
|
||
|
('closingText', self.closingText),
|
||
|
('body', self.body),
|
||
|
]
|
||
|
|
||
|
def generate_pdf(self) -> Response:
|
||
|
"""
|
||
|
:return: Response with the pdf attached as a download when successful
|
||
|
:raise ValueError: e.args[0] is a list of error strings, if generation fails
|
||
|
"""
|
||
|
import threading
|
||
|
unique_id = get_unique()
|
||
|
unique_file = output_dir + unique_id + '.tex'
|
||
|
f = open(unique_file, 'w')
|
||
|
for pair in self.get_pairs():
|
||
|
f.write('\\def \\' + pair[0] + '{' + pair[1] + '}\n')
|
||
|
f.write(base_tex_text)
|
||
|
f.close()
|
||
|
|
||
|
com = f'pdflatex -halt-on-error -jobname=outputs/{unique_id} {unique_file}'
|
||
|
result = subprocess.run(
|
||
|
['bash', '-c', com],
|
||
|
stdout=subprocess.PIPE,
|
||
|
text=True
|
||
|
)
|
||
|
|
||
|
build_text = f'[{get_datetime()}] Building for {unique_id} '
|
||
|
if result.returncode != 0:
|
||
|
print(build_text + '[FAIL]')
|
||
|
# Collect output but delete boilerplate text
|
||
|
errors = list(map(str.strip, result.stdout.split('\n')))
|
||
|
del errors[:13]
|
||
|
del errors[-2:]
|
||
|
raise ValueError(errors)
|
||
|
|
||
|
print(build_text + '[SUCCESS]')
|
||
|
|
||
|
result = subprocess.run(
|
||
|
[
|
||
|
'gs',
|
||
|
'-sDEVICE=pdfwrite',
|
||
|
'-dCompatibilityLevel=1.5',
|
||
|
'-dNOPAUSE',
|
||
|
'-dQUIET',
|
||
|
'-dBATCH',
|
||
|
'-dPrinted=false',
|
||
|
'-sOutputFile=outputs/' + unique_id + '.compressed.pdf',
|
||
|
'outputs/' + unique_id + '.pdf'
|
||
|
],
|
||
|
stdout=subprocess.PIPE,
|
||
|
text=True
|
||
|
)
|
||
|
|
||
|
threading.Timer(60 * 5, cleanup, [output_dir + unique_id]).start()
|
||
|
|
||
|
extension = 'compressed.pdf' if result.returncode == 0 else 'pdf'
|
||
|
output_file = f'{unique_id}.{extension}'
|
||
|
|
||
|
return send_from_directory(
|
||
|
output_dir,
|
||
|
output_file,
|
||
|
download_name=self.username.replace(' ', '') + '_CoverLetter.pdf',
|
||
|
as_attachment=True
|
||
|
)
|
||
|
|
||
|
|
||
|
def cleanup(unique) -> None:
|
||
|
subprocess.run(['bash', '-c', 'rm ' + unique + '.*'])
|
||
|
|
||
|
|
||
|
def get_unique() -> str:
|
||
|
import uuid
|
||
|
unique = str(uuid.uuid1().hex)
|
||
|
return unique
|
||
|
|
||
|
|
||
|
def get_datetime() -> str:
|
||
|
from datetime import datetime
|
||
|
now = datetime.now()
|
||
|
return now.strftime('%Y-%m-%d %H:%M:%S')
|
||
|
|
||
|
|