diff --git a/.gitignore b/.gitignore index 40cb5fc..d91c3ff 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ .venv test.pdf -.idea \ No newline at end of file +.idea +files \ No newline at end of file diff --git a/ezgg_badge_generator.py b/ezgg_badge_generator.py new file mode 100644 index 0000000..ef70003 --- /dev/null +++ b/ezgg_badge_generator.py @@ -0,0 +1,27 @@ +import asyncio + +from services.DatabaseService import DatabaseService +from services.BadgeGeneratorService import BadgeGeneratorService +from pathlib import Path + + +async def main(): + db = DatabaseService("sql_config.toml") + await db.init_db_pool() + + badges = await db.get_user_badges() + + badge_generator = BadgeGeneratorService( + svg_template=Path("template/template_dynamic_name_size.svg"), + chrome_path=Path(r"C:\Program Files\Google\Chrome\Application\chrome.exe") + ) + for user_badge in badges: + badge_generator.generate_badge( + name=user_badge["user_name"], + seat_id=user_badge["seat_id"], + picture=user_badge["picture"] + ) + + +if __name__ == "__main__": + asyncio.run(main()) diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..643d45d --- /dev/null +++ b/requirements.txt @@ -0,0 +1,3 @@ +mysql-connector-python~=9.6.0 +aiomysql~=0.3.2 +Jinja2~=3.1.6 \ No newline at end of file diff --git a/services/BadgeGeneratorService.py b/services/BadgeGeneratorService.py new file mode 100644 index 0000000..c746268 --- /dev/null +++ b/services/BadgeGeneratorService.py @@ -0,0 +1,68 @@ +import logging +import os +import re +import base64 +import subprocess +import tempfile +from pathlib import Path +from jinja2 import Environment, FileSystemLoader + +logging.basicConfig( + level=logging.INFO, + format="%(asctime)s [%(levelname)s] %(name)s: %(message)s" +) + +logger = logging.getLogger(__name__.split(".")[-1]) + + +class BadgeGeneratorService: + + def __init__(self, svg_template: Path, chrome_path: Path): + self.svg_template = svg_template + self.chrome_path = chrome_path + + def generate_badge(self, name, seat_id, picture) -> None: + svg = self.generate_svg(name, seat_id, picture) + self.svg_to_pdf(svg, f"files/{name}.pdf") + + def generate_svg(self, username: str, seat: str, image_base64: bytes) -> str: + with open(self.svg_template, "r", encoding="utf-8") as f: + svg = f.read() + # ToDo: Select font size for long names + svg = svg.replace(">test_username", f">{username}") + svg = svg.replace(">Platz: XYZ<", f">Platz: {seat}<") + if image_base64: + encoded = base64.b64encode(image_base64).decode("utf-8") + svg = svg.replace('xlink:href="data:image/jpeg;base64,"', f'xlink:href="data:image/jpeg;base64,{encoded}"') + logger.info(f"Generate svg string: Username: {username}, Seat: {seat}, Picture: {str(image_base64)[:15]}") + return svg + + def svg_to_pdf(self, svg_string: str, pdf_path: str): + + width = re.search(r'width="([^"]+)"', svg_string).group(1) + height = re.search(r'height="([^"]+)"', svg_string).group(1) + + env = Environment(loader=FileSystemLoader("template")) + template = env.get_template("badge_pdf.html") + + html = template.render( + width=width, + height=height, + svg_string=svg_string + ) + + with tempfile.NamedTemporaryFile(delete=False, suffix=".html", mode="w", encoding="utf-8") as f: + f.write(html) + html_path = f.name + + try: + subprocess.run([ + self.chrome_path, + "--headless", + "--disable-gpu", + f"--print-to-pdf={os.path.abspath(pdf_path)}", + html_path + ], check=True) + finally: + os.remove(html_path) + logger.info(f"Created: {pdf_path}") diff --git a/services/DatabaseService.py b/services/DatabaseService.py new file mode 100644 index 0000000..0236a13 --- /dev/null +++ b/services/DatabaseService.py @@ -0,0 +1,38 @@ +import tomllib +import aiomysql +from typing import Optional + + +class DatabaseService: + + def __init__(self, sql_config: str): + with open(sql_config, "rb") as f: + config = tomllib.load(f) + + self.db_config = config["database"] + self._pool: Optional[aiomysql.Pool] = None + + async def init_db_pool(self): + self._pool = await aiomysql.create_pool( + host=self.db_config["db_host"], + port=self.db_config["db_port"], + user=self.db_config["db_user"], + password=self.db_config["db_password"], + db=self.db_config["db_name"], + minsize=1, + maxsize=40, + autocommit=True + ) + + async def get_user_badges(self) -> list: + async with self._pool.acquire() as conn: + async with conn.cursor(aiomysql.DictCursor) as cursor: + await cursor.execute( + """SELECT u.user_id, u.user_name, s.seat_id, upp.picture + FROM users AS u + LEFT JOIN seats AS s + ON u.user_id = s.`user` + LEFT JOIN user_profile_picture AS upp + ON u.user_id = upp.user_id;""" + ) + return await cursor.fetchall() diff --git a/services/__init__.py b/services/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/sql_config.toml b/sql_config.toml new file mode 100644 index 0000000..8411c13 --- /dev/null +++ b/sql_config.toml @@ -0,0 +1,6 @@ +[database] + db_user="demo_user" + db_password="demo_password" + db_host="127.0.0.1" + db_port=3306 + db_name="ezgg_lan_manager" \ No newline at end of file diff --git a/template/Vorlage_LAN_Ausweis_mit_Daten.svg b/template/Vorlage_LAN_Ausweis_mit_Daten.svg deleted file mode 100644 index 3a6466c..0000000 --- a/template/Vorlage_LAN_Ausweis_mit_Daten.svg +++ /dev/null @@ -1,200 +0,0 @@ - - - - diff --git a/template/badge_pdf.html b/template/badge_pdf.html new file mode 100644 index 0000000..58093f0 --- /dev/null +++ b/template/badge_pdf.html @@ -0,0 +1,39 @@ + +
+ + + + +