fix broken files after faulty update

This commit is contained in:
2025-01-14 08:51:58 +01:00
parent 598da9bfac
commit 997d618ff1
102 changed files with 2499 additions and 548 deletions

236
src/utils/richtext.py Normal file
View File

@@ -0,0 +1,236 @@
from datetime import datetime
from docx import Document
from docx.enum.text import WD_PARAGRAPH_ALIGNMENT
from docx.enum.table import WD_ROW_HEIGHT_RULE
from docx.shared import Pt, RGBColor, Cm, Inches
from docx.oxml import OxmlElement
from docx.oxml.ns import qn
from docx2pdf import convert
import win32print
import win32api
import tempfile
import os
from os.path import basename
class SemesterDocument:
def __init__(self, apparats: list[tuple[int, str]], semester: str, filename):
assert isinstance(apparats, list), "Apparats must be a list of tuples"
assert all(isinstance(apparat, tuple) for apparat in apparats), (
"Apparats must be a list of tuples"
)
assert all(isinstance(apparat[0], int) for apparat in apparats), (
"Apparat numbers must be integers"
)
assert all(isinstance(apparat[1], str) for apparat in apparats), (
"Apparat names must be strings"
)
assert isinstance(semester, str), "Semester must be a string"
assert "." not in filename and isinstance(filename, str), (
"Filename must be a string and not contain an extension"
)
self.doc = Document()
self.apparats = apparats
self.semester = semester
self.table_font = "Arial"
self.header_font = "Times New Roman"
self.header_font_size = Pt(26)
self.sub_header_font_size = Pt(18)
self.table_font_size = Pt(10)
self.color_red = RGBColor(255, 0, 0)
self.color_blue = RGBColor(0, 0, 255)
self.filename = filename
def set_table_border(self, table):
"""
Adds a full border to the table.
:param table: Table object to which the border will be applied.
"""
tbl = table._element
tbl_pr = tbl.xpath("w:tblPr")[0]
tbl_borders = OxmlElement("w:tblBorders")
# Define border styles
for border_name in ["top", "left", "bottom", "right", "insideH", "insideV"]:
border = OxmlElement(f"w:{border_name}")
border.set(qn("w:val"), "single")
border.set(qn("w:sz"), "4") # Thickness of the border
border.set(qn("w:space"), "0")
border.set(qn("w:color"), "000000") # Black color
tbl_borders.append(border)
tbl_pr.append(tbl_borders)
def create_sorted_table(self) -> None:
# Sort the apparats list by the string in the tuple (index 1)
self.apparats.sort(key=lambda x: x[1])
# Create a table with rows equal to the length of the apparats list
table = self.doc.add_table(rows=len(self.apparats), cols=2)
table.alignment = WD_PARAGRAPH_ALIGNMENT.CENTER
# Set column widths by directly modifying the cell properties
widths = [Cm(1.19), Cm(10.39)]
for col_idx, width in enumerate(widths):
for cell in table.columns[col_idx].cells:
cell_width_element = cell._element.xpath(".//w:tcPr")[0]
tcW = OxmlElement("w:tcW")
tcW.set(qn("w:w"), str(int(width.cm * 567))) # Convert cm to twips
tcW.set(qn("w:type"), "dxa")
cell_width_element.append(tcW)
# Adjust row heights
for row in table.rows:
trPr = row._tr.get_or_add_trPr() # Get or add the <w:trPr> element
trHeight = OxmlElement("w:trHeight")
trHeight.set(
qn("w:val"), str(int(Pt(15).pt * 20))
) # Convert points to twips
trHeight.set(qn("w:hRule"), "exact") # Use "exact" for fixed height
trPr.append(trHeight)
# Fill the table with sorted data
for row_idx, (number, name) in enumerate(self.apparats):
row = table.rows[row_idx]
# Set font for the first column (number)
cell_number_paragraph = row.cells[0].paragraphs[0]
cell_number_run = cell_number_paragraph.add_run(str(number))
cell_number_run.font.name = self.table_font
cell_number_run.font.size = self.table_font_size
cell_number_run.font.bold = True
cell_number_run.font.color.rgb = self.color_red
cell_number_paragraph.alignment = WD_PARAGRAPH_ALIGNMENT.CENTER
# Set font for the second column (name)
cell_name_paragraph = row.cells[1].paragraphs[0]
words = name.split()
if words:
# Add the first word in bold
bold_run = cell_name_paragraph.add_run(words[0])
bold_run.font.bold = True
bold_run.font.name = self.table_font
bold_run.font.size = self.table_font_size
# Add the rest of the words normally
if len(words) > 1:
normal_run = cell_name_paragraph.add_run(" " + " ".join(words[1:]))
normal_run.font.name = self.table_font
normal_run.font.size = self.table_font_size
cell_name_paragraph.alignment = WD_PARAGRAPH_ALIGNMENT.LEFT
self.set_table_border(table)
def make_document(self):
# Create a new Document
section = self.doc.sections[0]
section.top_margin = Cm(2.54) # Default 1 inch (can adjust as needed)
section.bottom_margin = Cm(1.5) # Set bottom margin to 1.5 cm
section.left_margin = Cm(2.54) # Default 1 inch
section.right_margin = Cm(2.54) # Default 1 inch
# Add the current date
current_date = datetime.now().strftime("%Y-%m-%d")
date_paragraph = self.doc.add_paragraph(current_date)
date_paragraph.alignment = WD_PARAGRAPH_ALIGNMENT.LEFT
# Add a header
semester = f"Semesterapparate {self.semester}"
header = self.doc.add_paragraph(semester)
header.alignment = WD_PARAGRAPH_ALIGNMENT.CENTER
header_run = header.runs[0]
header_run.font.name = self.header_font
header_run.font.size = self.header_font_size
header_run.font.bold = True
header_run.font.color.rgb = self.color_blue
sub_header = self.doc.add_paragraph("(Alphabetisch)")
sub_header.alignment = WD_PARAGRAPH_ALIGNMENT.CENTER
sub_header_run = sub_header.runs[0]
sub_header_run.font.name = self.header_font
sub_header_run.font.size = self.sub_header_font_size
sub_header_run.font.color.rgb = self.color_red
self.doc.add_paragraph("")
self.create_sorted_table()
def save_document(self, name):
# Save the document
self.doc.save(name)
print(f"Document saved as {name}")
def print_document(self):
# send document to printer as attachment of email
import smtplib
from email.mime.multipart import MIMEMultipart
from email.mime.application import MIMEApplication
from email.mime.text import MIMEText
from src import settings as config
smtp = config.mail.smtp_server
port = config.mail.port
sender_email = config.mail.sender
password = config.mail.password
receiver = "mobileprint@ph-freiburg.de"
message = MIMEMultipart()
message["From"] = sender_email
message["To"] = receiver
message["cc"] = config.mail.sender
message["Subject"] = "."
mail_body = "."
message.attach(MIMEText(mail_body, "html"))
with open(self.filename + ".pdf", "rb") as fil:
part = MIMEApplication(fil.read(), Name=basename(self.filename + "pdf"))
# After the file is closed
part["Content-Disposition"] = 'attachment; filename="%s"' % basename(
self.filename + ".pdf"
)
message.attach(part)
mail = message.as_string()
with smtplib.SMTP_SSL(smtp, port) as server:
server.connect(smtp, port)
server.login(config.mail.user_name, password)
server.sendmail(sender_email, receiver, mail)
server.quit()
print("Mail sent")
def create_pdf(self):
# Save the document
import comtypes.client
word = comtypes.client.CreateObject("Word.Application")
self.save_document(self.filename + ".docx")
docpath = os.path.abspath(self.filename + ".docx")
doc = word.Documents.Open(docpath)
curdir = os.getcwd()
doc.SaveAs(f"{curdir}/{self.filename}.pdf", FileFormat=17)
doc.Close()
word.Quit()
print("PDF saved")
def cleanup(self):
os.remove(f"{self.filename}.docx")
os.remove(f"{self.filename}.pdf")
if __name__ == "__main__":
apparat = [(i, f"Item {i}") for i in range(405, 438)]
doc = SemesterDocument(
apparat,
"WiSe 24/25",
"semap",
)
doc.make_document()
doc.create_pdf()
# doc.print_document()
# def printers():
# printers = win32print.EnumPrinters(
# win32print.PRINTER_ENUM_LOCAL | win32print.PRINTER_ENUM_CONNECTIONS
# )
# for i, printer in enumerate(printers):
# print(f"{i}: {printer[2]}")
# list printers