Compare commits

...

22 Commits
0.8 ... main

Author SHA1 Message Date
9b1f0b911b Update .drone.yml
Some checks failed
continuous-integration/drone/push Build is failing
2025-04-15 17:44:34 +00:00
a86ba80bce Update .drone.yml
Some checks reported errors
continuous-integration/drone/push Build encountered an error
2025-04-15 17:42:55 +00:00
062d07ed23 update drone ci
Some checks failed
continuous-integration/drone/push Build is failing
2025-01-08 16:08:19 +02:00
5b4bb54495 update drone ci
Some checks reported errors
continuous-integration/drone/push Build was killed
continuous-integration/drone/tag Build is failing
2025-01-08 12:28:47 +02:00
8dc25f5ca6 update drone ci
Some checks reported errors
continuous-integration/drone/push Build was killed
continuous-integration/drone/tag Build is failing
2025-01-08 12:17:49 +02:00
18b5c06b17 office version
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/tag Build is passing
2025-01-08 11:56:23 +02:00
8c4067f34a Update .drone.yml
Some checks failed
continuous-integration/drone/push Build is passing
continuous-integration/drone Build is failing
continuous-integration/drone/tag Build is passing
2025-01-08 09:20:33 +00:00
ce63907fcd Update .drone.yml
Some checks reported errors
continuous-integration/drone/push Build was killed
2025-01-08 09:17:29 +00:00
ffc3f0e2b7 Update .drone.yml
Some checks failed
continuous-integration/drone/push Build is failing
2025-01-08 09:12:07 +00:00
211629202c Update requirements.txt
Some checks reported errors
continuous-integration/drone/push Build was killed
2025-01-08 09:02:38 +00:00
12be98d1a1 Update requirements.txt
Some checks failed
continuous-integration/drone/push Build is failing
2025-01-08 08:08:30 +00:00
a41aed4f0b Update requirements.txt
Some checks failed
continuous-integration/drone/push Build is failing
2025-01-08 08:02:12 +00:00
675facb6f7 Update requirements.txt
Some checks reported errors
continuous-integration/drone Build was killed
continuous-integration/drone/push Build is failing
2025-01-08 07:53:04 +00:00
6cad1e9408 Update requirements.txt
Some checks reported errors
continuous-integration/drone/push Build was killed
continuous-integration/drone Build was killed
2025-01-08 00:34:26 +00:00
98f8dce109 revert 4a4c8d8c538dfa58630fa5b3d85255b8358f7c9a
Some checks reported errors
continuous-integration/drone/push Build was killed
revert Update requirements.txt
2025-01-08 00:33:05 +00:00
4a4c8d8c53 Update requirements.txt
Some checks failed
continuous-integration/drone/push Build is failing
2025-01-08 00:30:11 +00:00
3b114a9622 Update requirements.txt
Some checks reported errors
continuous-integration/drone/push Build was killed
continuous-integration/drone Build is failing
2025-01-08 00:11:49 +00:00
c13535ec56 Update requirements.txt
Some checks reported errors
continuous-integration/drone/push Build was killed
continuous-integration/drone Build is failing
2025-01-07 23:32:59 +00:00
64b4c90e46 v1.1
Some checks reported errors
continuous-integration/drone/push Build was killed
continuous-integration/drone Build is failing
2025-01-08 01:29:44 +02:00
2dff534f61 pyinstaller bump 6.10.0
Some checks reported errors
continuous-integration/drone/push Build was killed
2025-01-08 01:27:34 +02:00
c309c2db56 v1.0
Some checks failed
continuous-integration/drone Build is failing
2025-01-08 00:57:05 +02:00
Argiris Deligiannidis
e1d238c321 open with utf-8 encoding
All checks were successful
continuous-integration/drone/tag Build is passing
continuous-integration/drone/push Build is passing
2024-07-12 01:47:41 +03:00
8 changed files with 268 additions and 106 deletions

View File

@ -7,7 +7,7 @@ workspace:
steps:
- name: build
image: git.argideli.com/quertex/docker-win-pyinstaller64:latest
image: git.quertex.com/quertex/docker-win-pyinstaller64:latest
pull: always
commands:
# prepare output directory
@ -16,7 +16,7 @@ steps:
# add dependancies
- pacman -Syu --noconfirm
#- pacman -Sy --noconfirm --needed wget lib32-gnutls libunwind lib32-expat python3 python-pip python-pipenv gcc-fortran base-devel python-numpy python-pandas gcc-libs gnutls wine-staging
- pacman -Sy --noconfirm at-spi2-core gtk3 lib32-gdk-pixbuf2 qt6-base qt6-declarative shiboken6 qt6-3d qt6-charts qt6-connectivity qt6-datavis3d qt6-graphs qt6-httpserver qt6-location qt6-multimedia qt6-networkauth qt6-positioning qt6-quick3d qt6-remoteobjects qt6-scxml qt6-sensors qt6-serialbus qt6-serialport qt6-speech qt6-svg qt6-tools qt6-webchannel qt6-webengine qt6-websockets libxkbcommon lib32-libxkbcommon python-xkbcommon python-cryptography python-pillow python-pycryptodome python-typing_extensions python-build python-flit-core python-installer python-setuptools python-wheel wget lib32-gnutls libunwind lib32-expat python3 python-pip gcc-fortran base-devel gcc-libs gnutls wine-staging
- pacman -Sy --noconfirm at-spi2-core gtk3 lib32-gdk-pixbuf2 qt6-base qt6-declarative shiboken6 qt6-3d qt6-charts qt6-connectivity qt6-datavis3d qt6-graphs qt6-httpserver qt6-location qt6-multimedia qt6-networkauth qt6-positioning qt6-quick3d qt6-remoteobjects qt6-scxml qt6-sensors qt6-serialbus qt6-serialport qt6-speech qt6-svg qt6-tools qt6-webchannel qt6-webengine qt6-websockets libxkbcommon lib32-libxkbcommon python-xkbcommon python-cryptography python-pillow python-pycryptodome python-typing_extensions python-build python-flit-core python-installer python-setuptools python-wheel wget lib32-gnutls libunwind lib32-expat python3 python-pip gcc-fortran base-devel gcc-libs gnutls
# linux build
- cd /drone/src/
- python --version
@ -29,7 +29,7 @@ steps:
- pip3 config set global.trusted-host "pypi.org files.pythonhosted.org pypi.python.org" --trusted-host=pypi.python.org --trusted-host=pypi.org --trusted-host=files.pythonhosted.org
- pip3 install --trusted-host pypi.org --trusted-host pypi.python.org --trusted-host files.pythonhosted.org pip setuptools
- pip3 install --trusted-host pypi.org --trusted-host pypi.python.org --trusted-host files.pythonhosted.org --ignore-installed -r requirements.txt
- pyinstaller --onefile --name akmi-utils.bin -y --distpath /drone/src/out/ /drone/src/widget.py
- pyinstaller --onefile --copy-metadata msoffice2pdf --collect-submodules --name akmi-utils.bin -y --distpath /drone/src/out/ /drone/src/widget.py
- deactivate
- cp -v out/akmi-utils.bin dist/
# clean up
@ -37,15 +37,15 @@ steps:
- rm -rf /drone/src/out
- mkdir -p /drone/src/out/
# windows build
- wine c:/python/python.exe -m pip config --user set global.progress_bar off
- wine c:/python/python.exe -m pip install --prefer-binary -r z:/drone/src/requirements.txt
- wine c:/python/Scripts/pyinstaller.exe --onefile --name akmi-utils -y --distpath z:/drone/src/out z:/drone/src/widget.py
- wine64 c:/python/python.exe -m pip config --user set global.progress_bar off
- wine64 c:/python/python.exe -m pip install --prefer-binary -r z:/drone/src/requirements.txt
- wine64 c:/python/Scripts/pyinstaller.exe --onefile --copy-metadata msoffice2pdf --collect-submodules --name akmi-utils -y --distpath z:/drone/src/out z:/drone/src/widget.py
- cp -v out/akmi-utils.exe dist/
- name: gitea_release
image: plugins/gitea-release
settings:
base_url: https://git.argideli.com
base_url: https://git.quertex.com
api_key:
from_secret: gitea_token
files: /drone/src/dist/*

View File

84
form.ui
View File

@ -9,8 +9,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>742</width>
<height>336</height>
<width>706</width>
<height>534</height>
</rect>
</property>
<property name="windowTitle">
@ -26,13 +26,13 @@
</rect>
</property>
<property name="text">
<string>Επιλογή Αρχείου CSV</string>
<string>Επιλογή δεδομένων Excel</string>
</property>
</widget>
<widget class="QLabel" name="label">
<property name="geometry">
<rect>
<x>150</x>
<x>140</x>
<y>20</y>
<width>61</width>
<height>61</height>
@ -51,7 +51,7 @@
<widget class="QLabel" name="label_2">
<property name="geometry">
<rect>
<x>240</x>
<x>230</x>
<y>10</y>
<width>431</width>
<height>81</height>
@ -83,7 +83,7 @@
<bool>false</bool>
</property>
<property name="text">
<string>Επιλέξτε το αρχείο δεδομένων σε μορφή .csv</string>
<string>Επιλέξτε το αρχείο δεδομένων σε μορφή Excel</string>
</property>
</widget>
<widget class="QPushButton" name="create_button">
@ -92,14 +92,14 @@
</property>
<property name="geometry">
<rect>
<x>310</x>
<y>290</y>
<width>111</width>
<height>34</height>
<x>480</x>
<y>250</y>
<width>211</width>
<height>61</height>
</rect>
</property>
<property name="text">
<string>Δημιουργία pdf</string>
<string>Δημιουργία πιστοποιητικών</string>
</property>
</widget>
<widget class="QPushButton" name="file_template">
@ -112,7 +112,7 @@
</rect>
</property>
<property name="text">
<string>Επιλογή Αρχείου PDF</string>
<string>Επιλογή προσχέδιου Word</string>
</property>
</widget>
<widget class="QLabel" name="label_4">
@ -131,7 +131,65 @@
<bool>false</bool>
</property>
<property name="text">
<string>Επιλέξτε το PDF αρχείο του προτύπου</string>
<string>Επιλέξτε το αρχείο του προτύπου (Word)</string>
</property>
</widget>
<widget class="QPlainTextEdit" name="oauth2_token">
<property name="enabled">
<bool>false</bool>
</property>
<property name="geometry">
<rect>
<x>20</x>
<y>320</y>
<width>341</width>
<height>41</height>
</rect>
</property>
</widget>
<widget class="QCheckBox" name="enable_email">
<property name="geometry">
<rect>
<x>20</x>
<y>260</y>
<width>131</width>
<height>20</height>
</rect>
</property>
<property name="text">
<string>Αποστολή email</string>
</property>
</widget>
<widget class="QLabel" name="label_5">
<property name="geometry">
<rect>
<x>120</x>
<y>290</y>
<width>131</width>
<height>31</height>
</rect>
</property>
<property name="whatsThis">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Το αρχείο που έχουμε επιλέξει&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="autoFillBackground">
<bool>false</bool>
</property>
<property name="text">
<string>Microsoft OAuth2 Token</string>
</property>
</widget>
<widget class="QPlainTextEdit" name="log_output">
<property name="enabled">
<bool>false</bool>
</property>
<property name="geometry">
<rect>
<x>10</x>
<y>390</y>
<width>681</width>
<height>131</height>
</rect>
</property>
</widget>
</widget>

20
requirements.bk Normal file
View File

@ -0,0 +1,20 @@
chardet==5.2.0
pillow==10.4.0
PyPDF2==3.0.1
PySide6>=6.7.2
PySide6_Addons>=6.7.2
PySide6_Essentials>=6.7.2
python-dateutil==2.9.0.post0
pytz==2024.1
reportlab==4.2.2
shiboken6>=6.7.2
six==1.16.0
tzdata==2024.1
altgraph==0.17.4
packaging==24.1
pyinstaller==6.9.0
pyinstaller-hooks-contrib==2024.7
setuptools==70.3.0
python-docx==1.1.2
python-docx==1.1.2
msoffice2pdf==1.0.0

View File

@ -1,17 +1,30 @@
altgraph==0.17.4
certifi==2024.12.14
chardet==5.2.0
charset-normalizer==3.4.1
et_xmlfile==2.0.0
idna==3.10
lxml==5.3.0
msoffice2pdf>=0.9.0
numpy==2.2.1
openpyxl==3.1.5
packaging==24.1
pandas==2.2.3
pillow==10.4.0
pyinstaller==6.10.0
pyinstaller-hooks-contrib==2024.11
PyPDF2==3.0.1
PySide6>=6.7.2
PySide6_Addons>=6.7.2
PySide6_Essentials>=6.7.2
PySide6==6.8.1
PySide6_Addons==6.8.1
PySide6_Essentials==6.8.1
python-dateutil==2.9.0.post0
python-docx==1.1.2
pytz==2024.1
reportlab==4.2.2
shiboken6>=6.7.2
six==1.16.0
tzdata==2024.1
altgraph==0.17.4
packaging==24.1
pyinstaller==6.9.0
pyinstaller-hooks-contrib==2024.7
requests==2.32.3
setuptools==70.3.0
shiboken6==6.8.1
six==1.16.0
typing_extensions==4.12.2
tzdata==2024.1
urllib3==2.3.0

View File

@ -1,9 +1,9 @@
# -*- coding: utf-8 -*-
################################################################################
## Form generated from reading UI file 'form.ui'
## Form generated from reading UI file 'formrmZXPO.ui'
##
## Created by: Qt User Interface Compiler version 6.7.2
## Created by: Qt User Interface Compiler version 6.8.1
##
## WARNING! All changes made in this file will be lost when recompiling UI file!
################################################################################
@ -15,27 +15,27 @@ from PySide6.QtGui import (QBrush, QColor, QConicalGradient, QCursor,
QFont, QFontDatabase, QGradient, QIcon,
QImage, QKeySequence, QLinearGradient, QPainter,
QPalette, QPixmap, QRadialGradient, QTransform)
from PySide6.QtWidgets import (QApplication, QLabel, QPushButton, QSizePolicy,
QWidget)
import rc_resources
from PySide6.QtWidgets import (QApplication, QCheckBox, QLabel, QPlainTextEdit,
QPushButton, QSizePolicy, QWidget)
import resources_rc
class Ui_Widget(object):
def setupUi(self, Widget):
if not Widget.objectName():
Widget.setObjectName(u"Widget")
Widget.setEnabled(True)
Widget.resize(742, 336)
Widget.resize(706, 534)
self.file_selector = QPushButton(Widget)
self.file_selector.setObjectName(u"file_selector")
self.file_selector.setGeometry(QRect(20, 140, 151, 34))
self.label = QLabel(Widget)
self.label.setObjectName(u"label")
self.label.setGeometry(QRect(150, 20, 61, 61))
self.label.setGeometry(QRect(140, 20, 61, 61))
self.label.setPixmap(QPixmap(u":/images/logo.png"))
self.label.setScaledContents(True)
self.label_2 = QLabel(Widget)
self.label_2.setObjectName(u"label_2")
self.label_2.setGeometry(QRect(240, 10, 431, 81))
self.label_2.setGeometry(QRect(230, 10, 431, 81))
font = QFont()
font.setPointSize(26)
font.setBold(True)
@ -47,7 +47,7 @@ class Ui_Widget(object):
self.create_button = QPushButton(Widget)
self.create_button.setObjectName(u"create_button")
self.create_button.setEnabled(False)
self.create_button.setGeometry(QRect(310, 290, 111, 34))
self.create_button.setGeometry(QRect(480, 250, 211, 61))
self.file_template = QPushButton(Widget)
self.file_template.setObjectName(u"file_template")
self.file_template.setGeometry(QRect(20, 190, 151, 34))
@ -55,6 +55,21 @@ class Ui_Widget(object):
self.label_4.setObjectName(u"label_4")
self.label_4.setGeometry(QRect(180, 190, 561, 31))
self.label_4.setAutoFillBackground(False)
self.oauth2_token = QPlainTextEdit(Widget)
self.oauth2_token.setObjectName(u"oauth2_token")
self.oauth2_token.setEnabled(False)
self.oauth2_token.setGeometry(QRect(20, 320, 341, 41))
self.enable_email = QCheckBox(Widget)
self.enable_email.setObjectName(u"enable_email")
self.enable_email.setGeometry(QRect(20, 260, 131, 20))
self.label_5 = QLabel(Widget)
self.label_5.setObjectName(u"label_5")
self.label_5.setGeometry(QRect(120, 290, 131, 31))
self.label_5.setAutoFillBackground(False)
self.log_output = QPlainTextEdit(Widget)
self.log_output.setObjectName(u"log_output")
self.log_output.setEnabled(False)
self.log_output.setGeometry(QRect(10, 390, 681, 131))
self.retranslateUi(Widget)
@ -63,18 +78,23 @@ class Ui_Widget(object):
def retranslateUi(self, Widget):
Widget.setWindowTitle(QCoreApplication.translate("Widget", u"Widget", None))
self.file_selector.setText(QCoreApplication.translate("Widget", u"\u0395\u03c0\u03b9\u03bb\u03bf\u03b3\u03ae \u0391\u03c1\u03c7\u03b5\u03af\u03bf\u03c5 CSV", None))
self.file_selector.setText(QCoreApplication.translate("Widget", u"\u0395\u03c0\u03b9\u03bb\u03bf\u03b3\u03ae \u03b4\u03b5\u03b4\u03bf\u03bc\u03ad\u03bd\u03c9\u03bd Excel", None))
self.label.setText("")
self.label_2.setText(QCoreApplication.translate("Widget", u"AKMI Certificate creator", None))
#if QT_CONFIG(whatsthis)
self.label_3.setWhatsThis(QCoreApplication.translate("Widget", u"<html><head/><body><p>\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</p></body></html>", 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"<html><head/><body><p>\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</p></body></html>", 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"<html><head/><body><p>\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</p></body></html>", None))
#endif // QT_CONFIG(whatsthis)
self.label_5.setText(QCoreApplication.translate("Widget", u"Microsoft OAuth2 Token", None))
# retranslateUi

175
widget.py
View File

@ -2,23 +2,22 @@
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
# Important:
# NOTE:
# You need to run the following command to generate the ui_form.py file
# pyside6-uic form.ui -o ui_form.py, or
# 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) 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)