UI: refactor mail template dialog for plaintext handling, improve logging, and update UI elements
This commit is contained in:
@@ -1,23 +1,18 @@
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
|
||||
from PySide6 import QtGui, QtWidgets, QtCore
|
||||
from loguru import logger as log
|
||||
from PySide6 import QtCore, QtWidgets
|
||||
|
||||
from src import Icon
|
||||
|
||||
from .dialog_sources import NewMailTemplateDesignerDialog
|
||||
|
||||
import sys
|
||||
from loguru import logger as log
|
||||
|
||||
logger = log
|
||||
logger.remove()
|
||||
logger.add("logs/application.log", rotation="1 week", retention="1 month", enqueue=True)
|
||||
log.add(
|
||||
f"logs/mail.log",
|
||||
enqueue=True,
|
||||
)
|
||||
|
||||
# logger.add(sys.stderr, format="{time} {level} {message}", level="INFO")
|
||||
log.add("logs/mail.log", enqueue=True)
|
||||
logger.add(sys.stdout)
|
||||
|
||||
|
||||
@@ -28,35 +23,34 @@ class MailTemplateDialog(QtWidgets.QDialog, NewMailTemplateDesignerDialog):
|
||||
super().__init__(parent)
|
||||
self.setupUi(self)
|
||||
self.setWindowIcon(Icon("edit_note").icon)
|
||||
self.setWindowTitle("Mailvorlage erstellen")
|
||||
self.setWindowTitle("Mailvorlage erstellen (Text)")
|
||||
|
||||
# placeholders UI
|
||||
self.placeholder_list.addItem("")
|
||||
self.placeholder_list.setCurrentText("")
|
||||
self.insertPlaceholder.clicked.connect(self.insert_placeholder)
|
||||
self.placeholder_list.currentTextChanged.connect(self.updateDescription)
|
||||
self.bold.clicked.connect(self.setFontBold)
|
||||
self.italic.clicked.connect(self.setTextFontItalic)
|
||||
self.underlined.clicked.connect(self.setTextFontUnderline)
|
||||
self.testTemplate.clicked.connect(self.test_template)
|
||||
self.fontBox.currentFontChanged.connect(self.setCurrentFont)
|
||||
self.fontSize.currentTextChanged.connect(self.setFontSize)
|
||||
# buttonbox
|
||||
# save button
|
||||
|
||||
# formatting buttons (kept enabled for UX, but saving uses plain text)
|
||||
|
||||
# buttons
|
||||
self.buttonBox.button(
|
||||
QtWidgets.QDialogButtonBox.StandardButton.Save
|
||||
).clicked.connect(self.save_template)
|
||||
# discard button
|
||||
self.buttonBox.button(
|
||||
QtWidgets.QDialogButtonBox.StandardButton.Discard
|
||||
).clicked.connect(self.discard_changes)
|
||||
# cancel button
|
||||
self.buttonBox.button(
|
||||
QtWidgets.QDialogButtonBox.StandardButton.Cancel
|
||||
).clicked.connect(self.closeNow)
|
||||
log.info("Mail template dialog setup complete")
|
||||
log.info("Mail template dialog (plaintext) setup complete")
|
||||
|
||||
def _normalize_newlines(self, s: str) -> str:
|
||||
# Convert any CRLF/CR to LF then back to CRLF for .eml
|
||||
s = s.replace("\\r\\n", "\\n").replace("\\r", "\\n")
|
||||
return s
|
||||
|
||||
def save_template(self):
|
||||
# print("save triggered")
|
||||
# create a dialog to ask for the name of the template
|
||||
dialog = QtWidgets.QInputDialog()
|
||||
dialog.setInputMode(QtWidgets.QInputDialog.InputMode.TextInput)
|
||||
dialog.setLabelText("Bitte geben Sie den Namen des Templates ein:")
|
||||
@@ -66,12 +60,11 @@ class MailTemplateDialog(QtWidgets.QDialog, NewMailTemplateDesignerDialog):
|
||||
dialog.setWindowIcon(Icon("save").icon)
|
||||
save = dialog.exec()
|
||||
template_name = dialog.textValue()
|
||||
log.info("Saving template")
|
||||
log.info("Saving plaintext template")
|
||||
if template_name != "" and save == 1:
|
||||
template = template_name + ".eml"
|
||||
if template in os.listdir("mail_vorlagen"):
|
||||
log.error("Template already exists")
|
||||
# warning dialog
|
||||
dialog = QtWidgets.QMessageBox()
|
||||
dialog.setIcon(QtWidgets.QMessageBox.Icon.Warning)
|
||||
Icon("warning", dialog)
|
||||
@@ -87,36 +80,34 @@ class MailTemplateDialog(QtWidgets.QDialog, NewMailTemplateDesignerDialog):
|
||||
ret = dialog.exec()
|
||||
if ret == QtWidgets.QMessageBox.StandardButton.No:
|
||||
return
|
||||
mail = f"""Subject: {self.subject.text()}
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/html; charset="UTF-8"
|
||||
Content-Transfer-Encoding: 8bit
|
||||
{self.templateEdit.toHtml()}"""
|
||||
html_head = """<html>
|
||||
<head>
|
||||
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
|
||||
</head>
|
||||
"""
|
||||
mail_base = mail.split("<html>")[0]
|
||||
mail_body = mail.split("</head>")[1]
|
||||
mail = mail_base + html_head + mail_body
|
||||
mail = (
|
||||
mail.replace("<", "<")
|
||||
.replace(">", ">")
|
||||
.replace(""", '"')
|
||||
.replace("&", "&")
|
||||
)
|
||||
with open(f"mail_vorlagen/{template}", "w", encoding="utf-8") as f:
|
||||
f.write(mail)
|
||||
|
||||
# Build plaintext from editor
|
||||
body_text = self.templateEdit.toPlainText()
|
||||
body_text = self._normalize_newlines(body_text)
|
||||
|
||||
# Build EML headers and payload (headers, then one blank line, then body)
|
||||
mail_headers = f"""
|
||||
Subject: {self.subject.text()}
|
||||
"""
|
||||
mail_body = body_text
|
||||
|
||||
eml = mail_headers + "\n\n" + mail_body
|
||||
eml = re.sub(r" +", " ", eml) # remove multiple spaces
|
||||
eml = re.sub(r"\n +", "\n", eml) #
|
||||
print(eml)
|
||||
|
||||
with open(
|
||||
f"mail_vorlagen/{template}", "w", encoding="utf-8", newline=""
|
||||
) as f:
|
||||
f.write(eml)
|
||||
|
||||
self.updateSignal.emit()
|
||||
self.close()
|
||||
log.success(f"Template {template} saved successfully")
|
||||
# log.success(f"Template {template} saved successfully (plaintext)")
|
||||
else:
|
||||
# warning dialog
|
||||
dialog = QtWidgets.QMessageBox()
|
||||
dialog.setIcon(QtWidgets.QMessageBox.Icon.Warning)
|
||||
dialog.setWindowIcon(Icon("warning").icon)
|
||||
|
||||
dialog.setText("Bitte geben Sie einen Namen für das Template ein.")
|
||||
dialog.setWindowTitle("Fehler beim Speichern")
|
||||
dialog.exec()
|
||||
@@ -145,52 +136,20 @@ Content-Transfer-Encoding: 8bit
|
||||
self.close()
|
||||
|
||||
def updateDescription(self):
|
||||
# print("update triggered")
|
||||
# print(self.placeholder_list.currentText())
|
||||
placeholders = {
|
||||
"anrede": "Die Anrede beinhaltet sowohl Person als auch Sehr geehrte/r; dargestellt als: {greeting}",
|
||||
"anrede": "Die Anrede inkl. 'Sehr geehrte/r' oder neutral; dargestellt als: {greeting}",
|
||||
"apparatsfach": "Das Fach, in welchem der Apparat angelegt wurde; dargestellt als: {AppSubject}",
|
||||
"apparatsname": "Der Name des Apparats; dargestellt als: {Appname}",
|
||||
"apparatsnummer": "Die Nummer des Apparats; dargestellt als: {AppNr}",
|
||||
"dozentname": "Der Name des Dozenten / der Dozentin; dargestellt als: {Profname}",
|
||||
"signatur": "Die persönliche / allgemeine Signatur am ende der Mail; dargestellt als: {signature}",
|
||||
"signatur": "Ihre Signatur; dargestellt als: {signature}",
|
||||
"": " ",
|
||||
}
|
||||
for (
|
||||
key,
|
||||
item,
|
||||
) in placeholders.items():
|
||||
for key, item in placeholders.items():
|
||||
if key in self.placeholder_list.currentText().lower():
|
||||
self.lineEdit.setText(item)
|
||||
break
|
||||
|
||||
def setCurrentFont(self):
|
||||
font = self.fontBox.currentFont()
|
||||
font.setPointSize(int(self.fontSize.currentText()))
|
||||
self.templateEdit.setFont(font)
|
||||
|
||||
def setFontSize(self):
|
||||
size = self.fontSize.currentText()
|
||||
self.templateEdit.setFontPointSize(int(size))
|
||||
|
||||
def setFontBold(self):
|
||||
if self.bold.isChecked():
|
||||
self.templateEdit.setFontWeight(QtGui.QFont.Weight.Bold)
|
||||
else:
|
||||
self.templateEdit.setFontWeight(QtGui.QFont.Weight.Normal)
|
||||
|
||||
def setTextFontItalic(self):
|
||||
if self.italic.isChecked():
|
||||
self.templateEdit.setFontItalic(True)
|
||||
else:
|
||||
self.templateEdit.setFontItalic(False)
|
||||
|
||||
def setTextFontUnderline(self):
|
||||
if self.underlined.isChecked():
|
||||
self.templateEdit.setFontUnderline(True)
|
||||
else:
|
||||
self.templateEdit.setFontUnderline(False)
|
||||
|
||||
def test_template(self):
|
||||
placeholders = [
|
||||
"{greeting}",
|
||||
@@ -201,35 +160,29 @@ Content-Transfer-Encoding: 8bit
|
||||
"{signature}",
|
||||
]
|
||||
mail_subject = self.subject.text()
|
||||
mail_body = self.templateEdit.toHtml()
|
||||
mail_body = self.templateEdit.toPlainText()
|
||||
missing_body = []
|
||||
missing_subject = []
|
||||
try:
|
||||
assert placeholders[2] in mail_subject
|
||||
assert "{Appname}" in mail_subject or "{AppName}" in mail_subject
|
||||
except AssertionError:
|
||||
missing_subject.append(placeholders[2])
|
||||
# check if all placeholders are in the mail body
|
||||
missing_subject.append("{Appname}")
|
||||
for placeholder in placeholders:
|
||||
try:
|
||||
assert placeholder in mail_body
|
||||
except AssertionError:
|
||||
missing_body.append(placeholder)
|
||||
if missing_body != []:
|
||||
# warning dialog
|
||||
Icon("template_fail", self.testTemplate)
|
||||
if missing_body:
|
||||
dialog = QtWidgets.QMessageBox()
|
||||
dialog.setWindowIcon(Icon("warning").icon)
|
||||
|
||||
dialog.setText("Folgende Platzhalter fehlen im Template:")
|
||||
|
||||
missing = (
|
||||
"Betreff:\n"
|
||||
+ "\n".join(missing_subject)
|
||||
+ "\n\n"
|
||||
+ "\\n".join(missing_subject)
|
||||
+ "\\n\\n"
|
||||
+ "Mailtext:\n"
|
||||
+ "\n".join(missing_body)
|
||||
+ "\\n".join(missing_body)
|
||||
)
|
||||
|
||||
dialog.setInformativeText(f"{missing}")
|
||||
dialog.setWindowTitle("Fehlende Platzhalter")
|
||||
dialog.exec()
|
||||
@@ -238,21 +191,16 @@ Content-Transfer-Encoding: 8bit
|
||||
self.testTemplate.setText("✔")
|
||||
|
||||
def insert_placeholder(self):
|
||||
placeholder = {
|
||||
placeholder_map = {
|
||||
"anrede": "{greeting}",
|
||||
"apparatsfach": "{AppSubject}",
|
||||
"apparatsname": "{Appname}",
|
||||
"apparatsnummer": "{AppNr}",
|
||||
"dozentname": "{Profname}",
|
||||
"signatur": """<pre class="moz-signature" cols="72">--
|
||||
{signature}
|
||||
</pre>""",
|
||||
"signatur": "{signature}",
|
||||
}
|
||||
cursor = self.templateEdit.textCursor()
|
||||
for (
|
||||
key,
|
||||
item,
|
||||
) in placeholder.items():
|
||||
for key, item in placeholder_map.items():
|
||||
if key in self.placeholder_list.currentText().lower():
|
||||
cursor.insertText(item)
|
||||
break
|
||||
|
||||
113
src/ui/dialogs/newEdition.py
Normal file
113
src/ui/dialogs/newEdition.py
Normal file
@@ -0,0 +1,113 @@
|
||||
import sys
|
||||
|
||||
import loguru
|
||||
from PySide6 import QtCore, QtWidgets
|
||||
|
||||
from src import LOG_DIR
|
||||
from src.backend.database import Database
|
||||
from src.backend.catalogue import Catalogue
|
||||
|
||||
from src.ui.dialogs.mail import Mail_Dialog
|
||||
|
||||
from .dialog_sources.order_neweditions_ui import Ui_Dialog
|
||||
|
||||
log = loguru.logger
|
||||
log.remove()
|
||||
log.add(sys.stdout, level="INFO")
|
||||
log.add(f"{LOG_DIR}/application.log", rotation="1 MB", retention="10 days")
|
||||
|
||||
|
||||
class NewEditionDialog(QtWidgets.QDialog, Ui_Dialog):
|
||||
def __init__(self, app_id, mail_data):
|
||||
super().__init__()
|
||||
self.setupUi(self)
|
||||
self.setWindowTitle("Neuauflagen bestellen")
|
||||
self.db = Database()
|
||||
self.catalogue = Catalogue()
|
||||
self.app_id = app_id
|
||||
self.mail_data = mail_data
|
||||
self.books = self.db.getNewEditionsByApparat(app_id)
|
||||
self.pushButton.clicked.connect(self.orderBooks)
|
||||
self.populateTable()
|
||||
|
||||
def populateTable(self):
|
||||
for book in self.books:
|
||||
signature = book.signature
|
||||
if signature is None or signature == "None":
|
||||
signature = self.catalogue.get_signature(book.ppn)
|
||||
link_label = QtWidgets.QLabel()
|
||||
link = (
|
||||
book.link
|
||||
if book.link != "SWB"
|
||||
else f"https://www.lehmanns.de/search/quick?mediatype_id=&q={book.isbn[0]}"
|
||||
)
|
||||
|
||||
link_label.setText(f'<a href="{link}">Lehmanns.de</a>')
|
||||
link_label.setOpenExternalLinks(True)
|
||||
link_label.setTextFormat(QtCore.Qt.TextFormat.RichText)
|
||||
link_label.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter)
|
||||
link_label.setTextInteractionFlags(
|
||||
QtCore.Qt.TextInteractionFlag.TextBrowserInteraction
|
||||
)
|
||||
self.tableWidget.insertRow(0)
|
||||
# first column is checkbox for ordering
|
||||
checkbox = QtWidgets.QCheckBox()
|
||||
|
||||
checkbox.setChecked(False)
|
||||
self.tableWidget.setCellWidget(0, 0, checkbox)
|
||||
self.tableWidget.setItem(
|
||||
0,
|
||||
1,
|
||||
QtWidgets.QTableWidgetItem(
|
||||
str(book.signature if book.signature else "")
|
||||
),
|
||||
)
|
||||
self.tableWidget.setItem(0, 2, QtWidgets.QTableWidgetItem(book.title))
|
||||
self.tableWidget.setItem(
|
||||
0, 3, QtWidgets.QTableWidgetItem(",".join(book.isbn))
|
||||
)
|
||||
self.tableWidget.setItem(0, 4, QtWidgets.QTableWidgetItem(book.author))
|
||||
self.tableWidget.setItem(0, 5, QtWidgets.QTableWidgetItem(book.edition))
|
||||
self.tableWidget.setItem(0, 6, QtWidgets.QTableWidgetItem(book.library_location))
|
||||
self.tableWidget.setCellWidget(0, 7, link_label)
|
||||
|
||||
def orderBooks(self):
|
||||
ordered_books = []
|
||||
for row in range(self.tableWidget.rowCount()):
|
||||
checkbox = self.tableWidget.cellWidget(row, 0)
|
||||
if checkbox.isChecked():
|
||||
book = self.books[row]
|
||||
book.link = (
|
||||
book.link
|
||||
if book.link != "SWB"
|
||||
else f"https://www.lehmanns.de/search/quick?mediatype_id=&q={book.isbn[0]}"
|
||||
)
|
||||
print(f"Bestelle Neuauflage für {book.title} ({book.edition})")
|
||||
ordered_books.append(book)
|
||||
# Process ordered_books as needed
|
||||
# editionId = self.db.getNewEditionId(book)
|
||||
# self.db.setOrdered(editionId)
|
||||
|
||||
self.mail = Mail_Dialog(
|
||||
app_id=self.mail_data.get("app_nr"),
|
||||
prof_name=self.mail_data.get("prof_name"),
|
||||
prof_mail=self.mail_data.get("prof_mail"),
|
||||
app_name=self.mail_data.get("app_name"),
|
||||
default_mail="Bitte um Bestellung",
|
||||
ordered_books=ordered_books,
|
||||
)
|
||||
self.mail.exec()
|
||||
|
||||
|
||||
def launch():
|
||||
app = QtWidgets.QApplication.instance()
|
||||
if app is None:
|
||||
app = QtWidgets.QApplication([])
|
||||
mail_data = {
|
||||
"prof_name": "Erwerbung",
|
||||
"prof_mail": "carola.wiestler@ph-freiburg.de",
|
||||
"app_nr": 131,
|
||||
"app_name": "Beratung und Teamarbeit",
|
||||
}
|
||||
dialog = NewEditionDialog(app_id=18, mail_data=mail_data)
|
||||
dialog.exec()
|
||||
Reference in New Issue
Block a user