import re import hashlib import time import ssl from pathlib import Path import imaplib from smtplib import SMTP_SSL import email from email import encoders from email.mime.base import MIMEBase from email.mime.multipart import MIMEMultipart from email.mime.text import MIMEText from email.mime.application import MIMEApplication import pdfkit from jinja2 import Environment, FileSystemLoader ENABLED_FILETYPES = ['txt', 'csv', 'pdf', 'doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx', 'xml', 'mxliff', 'tmx'] REGEX_EMAIL = re.compile('^[a-z0-9]+[\._]?[a-z0-9]+[@]\w+[.]\w{2,3}$') class ContractCreator: def __init__(self): template_loader = FileSystemLoader(searchpath="./") template_env = Environment(loader=template_loader) self.template = template_env.get_template('contract/template.html') self.pdfkit_options = { 'page-size': 'A4', 'margin-top': '0.75in', 'margin-right': '0.75in', 'margin-bottom': '0.75in', 'margin-left': '0.75in', 'encoding': "UTF-8", 'custom-header' : [ ('Accept-Encoding', 'gzip') ] } def fill_template(self, **kwargs): return self.template.render(**kwargs) def create_pdf(self, out_f, fields_dict): html_str = self.fill_template(**fields_dict) pdfkit.from_string(html_str, out_f, options=self.pdfkit_options) contract_creator = ContractCreator() def get_upload_metadata(corpus_name, request): upload_metadata = dict() file_hashes = create_file_hashes(request.files) file_names = file_hashes.keys() form_data = request.form.copy() upload_timestamp = int(time.time()) upload_id = create_upload_id(corpus_name, form_data, upload_timestamp, file_hashes) upload_metadata['corpus_name'] = corpus_name upload_metadata['form_data'] = form_data upload_metadata['upload_id'] = upload_id upload_metadata['timestamp'] = upload_timestamp upload_metadata['file_hashes'] = file_hashes upload_metadata['file_names'] = file_names return upload_metadata def check_suffixes(files): for key, f in files.items(): if key.startswith('file'): suffix = f.filename.split('.')[-1] if suffix not in ENABLED_FILETYPES: return 'Datoteka "{}" ni pravilnega formata.'.format(f.filename) return None def get_subdir(uploads_path, dir_name): subdir = uploads_path / dir_name if not subdir.exists(): subdir.mkdir(parents=True) return subdir def create_upload_id(corpus_name, form_data, upload_timestamp, file_hashes): ime = form_data.get('ime') podjetje = form_data.get('podjetje') naslov = form_data.get('naslov') posta = form_data.get('posta') email = form_data.get('email') telefon = form_data.get('telefon') # This hash serves as an unique identifier for the whole upload. metahash = hashlib.md5((corpus_name+ime+podjetje+naslov+posta+email+telefon).encode()) # Include file hashes to avoid metafile name collisions if they have the same form values, # but different data files. Sort hashes first so upload order doesn't matter. sorted_f_hashes = list(file_hashes.values()) sorted_f_hashes.sort() metahash.update(''.join(sorted_f_hashes).encode()) metahash = metahash.hexdigest() return metahash def check_form(form): ime = form.get('ime') podjetje = form.get('podjetje') naslov = form.get('naslov') posta = form.get('posta') email = form.get('email') telefon = form.get('telefon') if len(ime) > 100: return 'Predolgo ime.' if len(podjetje) > 100: return 'Predolgo ime institucije.' if len(email) > 100: return 'Predolgi email naslov' elif not re.search(REGEX_EMAIL, email): return 'Email napačnega formata.' if len(telefon) > 100: return 'Predolga telefonska št.' if len(naslov) > 100: return 'Predolg naslov.' if len(posta) > 100: return 'Predolga pošta' return None def create_file_hashes(files): res = dict() for key, f in files.items(): if key.startswith('file'): h = hashlib.md5(f.filename.encode()) h.update(f.stream.read()) res[f.filename] = h.hexdigest() f.seek(0) return res def store_metadata(uploads_path, upload_metadata): base = get_subdir(uploads_path, 'meta') timestamp = upload_metadata['timestamp'] upload_id = upload_metadata['upload_id'] form_data = upload_metadata['form_data'] email = form_data['email'] file_hashes = upload_metadata['file_hashes'] contract = upload_metadata['contract'] filename = str(timestamp) + '-' + email + '-' + upload_id + '.meta' sorted_f_hashes = list(file_hashes.values()) sorted_f_hashes.sort() path = base / filename with path.open('w') as f: f.write('korpus=' + upload_metadata['corpus_name']) f.write('\nime=' + form_data['ime']) f.write('\npodjetje=' + form_data['podjetje']) f.write('\nnaslov=' + form_data['naslov']) f.write('\nposta=' + form_data['posta']) f.write('\nemail=' + form_data['email']) f.write('\ndatoteke=' + str(sorted_f_hashes)) f.write('\npogodba=' + contract) def store_datafiles(uploads_path, files, upload_metadata): base = get_subdir(uploads_path, 'files') file_hashes = upload_metadata['file_hashes'] for key, f in files.items(): if key.startswith('file'): path = base / file_hashes[f.filename] if not path.exists(): path.mkdir() f.save(path / f.filename) def generate_contract_pdf(uploads_path, upload_metadata, contract_client_contact): base = get_subdir(uploads_path, 'contracts') contract_file_name = upload_metadata['upload_id'] + '.pdf' form_data = upload_metadata['form_data'] files_table_str = [] for file_name in upload_metadata['file_names']: files_table_str.append('') files_table_str.append(file_name) files_table_str.append('') files_table_str = ''.join(files_table_str) data = { 'ime_priimek': form_data['ime'], 'naslov': form_data['naslov'], 'posta': form_data['posta'], 'kontakt_narocnik': contract_client_contact, 'kontakt_imetnikpravic': form_data['ime'], 'files_table_str': files_table_str } contract_creator.create_pdf(base / contract_file_name, data) return contract_file_name def send_confirm_mail(subject, body, uploads_path, upload_metadata, mail_host, mail_login, mail_pass, imap_port=993, smtp_port=465): upload_id = upload_metadata['upload_id'] message = MIMEMultipart() message['From'] = mail_login message['To'] = upload_metadata['form_data']['email'] message['Subject'] = subject.format(upload_id=upload_id) body = body.format(upload_id=upload_id) message.attach(MIMEText(body, "plain")) contracts_dir = get_subdir(uploads_path, 'contracts') base_name = upload_metadata['contract'] contract_file = contracts_dir / base_name with open(contract_file, "rb") as f: part = MIMEApplication( f.read(), Name = base_name ) part['Content-Disposition'] = 'attachment; filename="%s"' % base_name message.attach(part) text = message.as_string() # Create a secure SSL context context = ssl.create_default_context() with SMTP_SSL(mail_host, smtp_port, context=context) as server: server.login(mail_login, mail_pass) server.sendmail(message['From'], message['To'], text) # Save copy of sent mail in Sent mailbox imap = imaplib.IMAP4_SSL(mail_host, imap_port) imap.login(mail_login, mail_pass) imap.append('Sent', '\\Seen', imaplib.Time2Internaldate(time.time()), text.encode('utf8')) imap.logout()