Backend: - path_validator.py: PathValidator-Klasse für Pfad-Validierung - file_ops.py: read_file, write_file, directory_exists, file_exists - content_types.py: get_content_type mit EXTENSION_MAP - handler.py: Handler-Klasse mit do_GET/do_PUT, nutzt above modules - serve.py: Entry-Point (main, find_free_port), setzt Handler.validator/directory Frontend: - css/variables.css: CSS-Variablen (--bg-*, --text-*, --accent, etc.) - css/styles.css: Alle CSS-Regeln (modal, card, template-grid, etc.) - js/utils.js: esc, showToast, copyContentToClipboard - js/modal.js: showModal, closeModal, closeEditModal, wasViewModalOpen - js/editor.js: editModalContent, createJsonEditUI, extractJsonFromForm - js/api.js: viewTemplate, copyContent, loadTemplates, saveEditedContent - js/templates.js: renderTemplates, applyFilters, parseTypeFromHash - js/main.js: Event-Listener, Hash-Filter, Initialisierung - index.html: Inline-CSS/JS entfernt, <link>/<script src>-Tags hinzugefügt Smoke test: SO_REUSEADDR für schnelle Port-Wiederverwendung
81 lines
1.9 KiB
Python
81 lines
1.9 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
Datei-Ein-/Ausgabe-Operationen für Template-Dateien.
|
|
|
|
Stellt sichere Lese- und Schreiboperationen mit Encoding-Handling bereit.
|
|
"""
|
|
|
|
import os
|
|
from pathlib import Path
|
|
from typing import Optional
|
|
|
|
|
|
def read_file(filepath: str) -> Optional[str]:
|
|
"""
|
|
Liest eine Datei und gibt den Inhalt als String zurück.
|
|
|
|
Args:
|
|
filepath: Absoluter Pfad zur Datei
|
|
|
|
Returns:
|
|
Dateiinhalt als UTF-8 String, oder None bei Fehler
|
|
"""
|
|
try:
|
|
with open(filepath, "r", encoding="utf-8") as f:
|
|
return f.read()
|
|
except FileNotFoundError:
|
|
return None
|
|
except Exception:
|
|
return None
|
|
|
|
|
|
def read_file_binary(filepath: str) -> Optional[bytes]:
|
|
"""
|
|
Liest eine Datei im Binärmodus.
|
|
|
|
Args:
|
|
filepath: Absoluter Pfad zur Datei
|
|
|
|
Returns:
|
|
Dateiinhalt als Bytes, oder None bei Fehler
|
|
"""
|
|
try:
|
|
with open(filepath, "rb") as f:
|
|
return f.read()
|
|
except FileNotFoundError:
|
|
return None
|
|
except Exception:
|
|
return None
|
|
|
|
|
|
def write_file(filepath: str, content: bytes) -> bool:
|
|
"""
|
|
Schreibt Bytes in eine Datei. Erstellt parent-Verzeichnis falls nötig.
|
|
|
|
Args:
|
|
filepath: Absoluter Pfad zur Zieldatei
|
|
content: Zu schreibende Bytes
|
|
|
|
Returns:
|
|
True bei Erfolg, False bei Fehler
|
|
"""
|
|
try:
|
|
file_dir = os.path.dirname(filepath)
|
|
if not os.path.exists(file_dir) or not os.path.isdir(file_dir):
|
|
return False
|
|
|
|
with open(filepath, "wb") as f:
|
|
f.write(content)
|
|
return True
|
|
except Exception:
|
|
return False
|
|
|
|
|
|
def file_exists(filepath: str) -> bool:
|
|
"""Prüft, ob eine Datei existiert."""
|
|
return os.path.isfile(filepath)
|
|
|
|
|
|
def directory_exists(dirpath: str) -> bool:
|
|
"""Prüft, ob ein Verzeichnis existiert."""
|
|
return os.path.isdir(dirpath)
|