From c309c2db565fb441454de109a6e1fc5dbcf72537 Mon Sep 17 00:00:00 2001
From: Argiris Deligiannidis
\u03a4\u03bf \u03b1\u03c1\u03c7\u03b5\u03af\u03bf \u03c0\u03bf\u03c5 \u03ad\u03c7\u03bf\u03c5\u03bc\u03b5 \u03b5\u03c0\u03b9\u03bb\u03ad\u03be\u03b5\u03b9
", None)) #endif // QT_CONFIG(whatsthis) - self.label_3.setText(QCoreApplication.translate("Widget", u"\u0395\u03c0\u03b9\u03bb\u03ad\u03be\u03c4\u03b5 \u03c4\u03bf \u03b1\u03c1\u03c7\u03b5\u03af\u03bf \u03b4\u03b5\u03b4\u03bf\u03bc\u03ad\u03bd\u03c9\u03bd \u03c3\u03b5 \u03bc\u03bf\u03c1\u03c6\u03ae .csv", None)) - self.create_button.setText(QCoreApplication.translate("Widget", u"\u0394\u03b7\u03bc\u03b9\u03bf\u03c5\u03c1\u03b3\u03af\u03b1 pdf", None)) - self.file_template.setText(QCoreApplication.translate("Widget", u"\u0395\u03c0\u03b9\u03bb\u03bf\u03b3\u03ae \u0391\u03c1\u03c7\u03b5\u03af\u03bf\u03c5 PDF", None)) + self.label_3.setText(QCoreApplication.translate("Widget", u"\u0395\u03c0\u03b9\u03bb\u03ad\u03be\u03c4\u03b5 \u03c4\u03bf \u03b1\u03c1\u03c7\u03b5\u03af\u03bf \u03b4\u03b5\u03b4\u03bf\u03bc\u03ad\u03bd\u03c9\u03bd \u03c3\u03b5 \u03bc\u03bf\u03c1\u03c6\u03ae Excel", None)) + self.create_button.setText(QCoreApplication.translate("Widget", u"\u0394\u03b7\u03bc\u03b9\u03bf\u03c5\u03c1\u03b3\u03af\u03b1 \u03c0\u03b9\u03c3\u03c4\u03bf\u03c0\u03bf\u03b9\u03b7\u03c4\u03b9\u03ba\u03ce\u03bd", None)) + self.file_template.setText(QCoreApplication.translate("Widget", u"\u0395\u03c0\u03b9\u03bb\u03bf\u03b3\u03ae \u03c0\u03c1\u03bf\u03c3\u03c7\u03ad\u03b4\u03b9\u03bf\u03c5 Word", None)) #if QT_CONFIG(whatsthis) self.label_4.setWhatsThis(QCoreApplication.translate("Widget", u"\u03a4\u03bf \u03b1\u03c1\u03c7\u03b5\u03af\u03bf \u03c0\u03bf\u03c5 \u03ad\u03c7\u03bf\u03c5\u03bc\u03b5 \u03b5\u03c0\u03b9\u03bb\u03ad\u03be\u03b5\u03b9
", None)) #endif // QT_CONFIG(whatsthis) - self.label_4.setText(QCoreApplication.translate("Widget", u"\u0395\u03c0\u03b9\u03bb\u03ad\u03be\u03c4\u03b5 \u03c4\u03bf PDF \u03b1\u03c1\u03c7\u03b5\u03af\u03bf \u03c4\u03bf\u03c5 \u03c0\u03c1\u03bf\u03c4\u03cd\u03c0\u03bf\u03c5", None)) + self.label_4.setText(QCoreApplication.translate("Widget", u"\u0395\u03c0\u03b9\u03bb\u03ad\u03be\u03c4\u03b5 \u03c4\u03bf \u03b1\u03c1\u03c7\u03b5\u03af\u03bf \u03c4\u03bf\u03c5 \u03c0\u03c1\u03bf\u03c4\u03cd\u03c0\u03bf\u03c5 (Word)", None)) + self.enable_email.setText(QCoreApplication.translate("Widget", u"\u0391\u03c0\u03bf\u03c3\u03c4\u03bf\u03bb\u03ae email", None)) +#if QT_CONFIG(whatsthis) + self.label_5.setWhatsThis(QCoreApplication.translate("Widget", u"\u03a4\u03bf \u03b1\u03c1\u03c7\u03b5\u03af\u03bf \u03c0\u03bf\u03c5 \u03ad\u03c7\u03bf\u03c5\u03bc\u03b5 \u03b5\u03c0\u03b9\u03bb\u03ad\u03be\u03b5\u03b9
", None)) +#endif // QT_CONFIG(whatsthis) + self.label_5.setText(QCoreApplication.translate("Widget", u"Microsoft OAuth2 Token", None)) # retranslateUi diff --git a/widget.py b/widget.py index c560408..cf7bf35 100644 --- a/widget.py +++ b/widget.py @@ -2,13 +2,12 @@ import os import io import sys -import csv import shutil -from PyPDF2 import PdfReader, PdfWriter -from reportlab.pdfgen import canvas -from reportlab.lib.pagesizes import A4 -from reportlab.pdfbase import pdfmetrics -from reportlab.pdfbase.ttfonts import TTFont +import base64 +from docx import Document +from msoffice2pdf import convert +import pandas as pd +import requests from PySide6.QtWidgets import QApplication, QWidget, QFileDialog from PySide6.QtCore import QFile, QIODevice @@ -18,7 +17,7 @@ from PySide6.QtCore import QFile, QIODevice # pyside2-uic form.ui -o ui_form.py from ui_form import Ui_Widget -import rc_resources +import resources_rc class Widget(QWidget): @@ -30,6 +29,7 @@ class Widget(QWidget): self.ui.file_selector.clicked.connect(self.file_selector) self.ui.file_template.clicked.connect(self.file_template) self.ui.create_button.clicked.connect(self.create_button) + self.ui.enable_email.clicked.connect(self.enable_token) self.selected_file = False self.selected_template = False self.filepath_template = "" @@ -49,90 +49,141 @@ class Widget(QWidget): if self.selected_file and self.selected_template: self.ui.create_button.setEnabled(True) + def enable_token(self): + print(self.ui.oauth2_token.isEnabled()) + if self.ui.oauth2_token.isEnabled(): + self.ui.oauth2_token.setEnabled(False) + else: + self.ui.oauth2_token.setEnabled(True) + def file_selector(self): self.filepath = QFileDialog.getOpenFileName(self, "Επιλογή Αρχείου") if self.filepath[0]: ext = os.path.splitext(self.filepath[0])[-1].lower() - if ext != ".csv": - self.ui.label_3.setText("Το αρχείο πρέπει να είναι της μορφής .csv") - self.selected_file = False - else: + if ext in [".xlsx", ".xls"]: + self.ui.log_output.appendPlainText("Επιλέχθηκε το αρχείο δεδομενων: {}".format(self.filepath[0])) self.ui.label_3.setText("{}".format(self.filepath[0])) self.selected_file = True self.in_file = self.filepath[0] self.file_path = os.path.dirname(self.filepath[0]) + else: + self.ui.label_3.setText("Το αρχείο πρέπει να είναι της μορφής .xlsx ή .xls") + self.selected_file = False self.enable_create() def file_template(self): self.filepath_template = QFileDialog.getOpenFileName(self, "Επιλογή Αρχείου") if self.filepath_template[0]: ext = os.path.splitext(self.filepath_template[0])[-1].lower() - if ext != ".pdf": - self.ui.label_4.setText("Το αρχείο πρέπει να είναι της μορφής .pdf") - self.selected_template = False - else: + if ext in [".docx", ".doc"]: + self.ui.log_output.appendPlainText("Επιλέχθηκε το προσχέδιο: {}".format(self.filepath_template[0])) self.ui.label_4.setText("{}".format(self.filepath_template[0])) self.selected_template = True self.in_template = self.filepath_template[0] self.template_path = os.path.dirname(self.filepath_template[0]) + else: + self.ui.label_4.setText("Το αρχείο πρέπει να είναι της μορφής .docx ή .doc") + self.selected_template = False + self.enable_create() def create_button(self): - with open(self.in_file, encoding='utf-8') as fin: - csvin = csv.DictReader(fin) - self.create_certificates(csvin) + df = pd.read_excel("{}".format(self.filepath[0])) + doc = Document("{}".format(self.filepath_template[0])) + self.create_certificates(df, doc) - def create_certificates(self, csv_dict): - count = 0 - shutil.copyfile( - "{}".format(self.filepath_template[0]), - "{}/RESULT.pdf".format(self.file_path), - ) - for in_row in csv_dict: - count += 1 - packet = io.BytesIO() - pdfmetrics.registerFont( - TTFont("NotoMedium", self.qrc_to_bytes(":/FONTS/NotoSans-Medium.ttf")) - ) - pdfmetrics.registerFont( - TTFont( - "NotoSemiMedium", - self.qrc_to_bytes(":/FONTS/NotoSans-SemiCondensedMedium.ttf"), - ) - ) - # pdfmetrics.registerFont(TTFont('NotoRegular', '{}/NotoSans-Regular.ttf'.format(self.font_dir))) - # pdfmetrics.registerFont(TTFont('NotoBold', '{}/NotoSans-Bold.ttf'.format(self.font_dir))) - # pdfmetrics.registerFont(TTFont('NotoSemi', '{}/NotoSans-SemiCondensed.ttf'.format(self.font_dir))) - # pdfmetrics.registerFont(TTFont('NotoSemiMedium', '{}/NotoSans-SemiCondensedMedium.ttf'.format(self.font_dir))) + def replace_text_styled(self, paragraph, key, value): + if key in paragraph.text: + inline = paragraph.runs + for i in range(len(inline)): + if key in inline[i].text: + text = inline[i].text.replace(key, value) + inline[i].text = text - can = canvas.Canvas(packet, pagesize=A4) - can.setFont("NotoMedium", 22) - x = can._pagesize[0] / 2 - can.drawString(x, 315, "{} {}".format(in_row["SURNAME"], in_row["NAME"])) - can.setFont("NotoSemiMedium", 18) - can.drawString(x, 250, "{}".format(in_row["DEPARTMENT"])) - can.save() + def send_email(self, data_row, attachement): + endpoint = "https://graph.microsoft.com/v1.0/me/sendMail" + headers = { + "Authorization": "{}".format(self.ui.oauth2_token.toPlainText()), + "Content-Type": "application/json" + } + + cert_file = open("./OUTPUT/{}".format(attachement), "rb") + data = cert_file.read() + + email_data = { + "message": { + "subject": "ΠΙΣΤΟΠΟΙΗΤΙΚΟ ΠΑΡΑΚΟΛΟΥΘΗΣΗΣ ΣΕΜΙΝΑΡΙΟΥ: {}".format(data_row['ΘΕΜΑ ΣΕΜΙΝΑΡΙΟΥ']), + "body": { + "contentType": "Text", + "content": "Χαίρετε,\nΣτο παρόν email επισυνάπτεται το πιστοποιητικό παρακολούθησης του σεμιναρίου {} που παρακολουθήσατε στη δομή {} το μήνα {}".format(data_row['ΘΕΜΑ ΣΕΜΙΝΑΡΙΟΥ'], data_row['CAMPUS'], data_row['DATE']) + }, + "toRecipients": [ + { + "emailAddress": { + "address": "{}".format(data_row['EMAIL']) + } + } + ], + "attachments": [ + { + "@odata.type": "#microsoft.graph.fileAttachment", + "name": "{}".format(attachement), + "contentType": "application/pdf", + "contentBytes": base64.b64encode(data).decode('utf-8') + } + ] + }, + "saveToSentItems": "true" + } - packet.seek(0) - new_pdf = PdfReader(packet) + response = requests.post(endpoint, headers=headers, json=email_data) + cert_file.close() - existing_pdf = PdfReader(open("{}/RESULT.pdf".format(self.file_path), "rb")) - output = PdfWriter() + if response.status_code == 202: + self.ui.log_output.appendPlainText("Email στάλθηκε: {}".format(data_row['EMAIL'])) + else: + self.ui.log_output.appendPlainText(f"Αποτυχία αποστολής. Status code: {response.status_code}, Error: {response.text}") + + def create_certificates(self, in_df, in_doc): + if not os.path.exists("./OUTPUT"): + os.makedirs("./OUTPUT") + + for index, row in in_df.iterrows(): + if row['ΟΝΟΜΑΤΕΠΩΝΥΜΟ'] in ['EMPTY', None] or pd.isna(row['ΟΝΟΜΑΤΕΠΩΝΥΜΟ']): + student_name = "{} {} του {}".format(row['ΕΠΩΝΥΜΟ'],row['ΟΝΟΜΑ'], row['ΠΑΤΡΩΝΥΜΟ']) + else: + student_name = "{} {} του {}".format(row['ΟΝΟΜΑΤΕΠΩΝΥΜΟ'], row['ΠΑΤΡΩΝΥΜΟ']) - for page in existing_pdf.pages: - output.add_page(page) - page = existing_pdf.pages[0] - page.merge_page(new_pdf.pages[0]) - output.add_page(page) + mock_data = { + 'ΟΝΟΜΑΤΕΠΩΝΥΜΟ': student_name, + 'ΘΕΜΑ_ΣΕΜΙΝΑΡΙΟΥ': row['ΘΕΜΑ ΣΕΜΙΝΑΡΙΟΥ'], + 'DATE': row['DATE'], + 'CAMPUS': row['CAMPUS'], + 'EMAIL': row['EMAIL'] + } - outputStream = open("{}/RESULT.pdf".format(self.file_path), "wb") - output.write(outputStream) - outputStream.close() + for paragraph in in_doc.paragraphs: + for key in mock_data: + self.replace_text_styled(paragraph, key, mock_data[key]) + + if os.path.exists("./edit.docx"): + os.remove("./edit.docx") + in_doc.save('edit.docx') + + output = convert(source="edit.docx", output_dir="./", soft=0) + fname = output.rsplit('/')[-1] + shutil.move("./{}".format(fname), "./OUTPUT/{}.pdf".format(student_name.replace(" ", "_"))) + + print("PDF created: {}.pdf".format(student_name.replace(" ", "_"))) + if self.ui.enable_email.isChecked(): + self.send_email(row, attachement="{}.pdf".format(student_name.replace(" ", "_"))) self.ui.label_4.setText( - "Το αρχείο PDF δημιουργήθηκε εντός του φακέλου του .csv" + "Τα αρχείο PDF δημιουργήθηκαν εντός του φακέλου OUTPUT." ) self.ui.create_button.setEnabled(False) - + + if os.path.exists("./edit.docx"): + os.remove("./edit.docx") if __name__ == "__main__": app = QApplication(sys.argv)