UTF-8 (de) geht :D
Dieser Commit ist enthalten in:
@@ -9,7 +9,8 @@
|
|||||||
"Bash(docker-compose down:*)",
|
"Bash(docker-compose down:*)",
|
||||||
"Bash(docker logs:*)",
|
"Bash(docker logs:*)",
|
||||||
"Bash(docker exec:*)",
|
"Bash(docker exec:*)",
|
||||||
"Bash(python3:*)"
|
"Bash(python3:*)",
|
||||||
|
"Bash(docker-compose restart:*)"
|
||||||
],
|
],
|
||||||
"deny": []
|
"deny": []
|
||||||
}
|
}
|
||||||
|
|||||||
20
JOURNAL.md
20
JOURNAL.md
@@ -101,3 +101,23 @@ Lizenzmanagement-System für Social Media Account-Erstellungssoftware mit Docker
|
|||||||
- Initialer Projektstand dokumentiert
|
- Initialer Projektstand dokumentiert
|
||||||
- Aufgabenliste priorisiert
|
- Aufgabenliste priorisiert
|
||||||
- Technische Anforderungen festgehalten
|
- Technische Anforderungen festgehalten
|
||||||
|
|
||||||
|
### 2025-01-06 - UTF-8 Support implementiert
|
||||||
|
- Flask App Konfiguration für UTF-8 hinzugefügt (JSON_AS_ASCII=False)
|
||||||
|
- PostgreSQL Verbindung mit UTF-8 client_encoding
|
||||||
|
- HTML Forms mit accept-charset="UTF-8"
|
||||||
|
- Dockerfile mit deutschen Locale-Einstellungen (de_DE.UTF-8)
|
||||||
|
- PostgreSQL Container mit UTF-8 Initialisierung
|
||||||
|
- init.sql mit SET client_encoding = 'UTF8'
|
||||||
|
|
||||||
|
**Geänderte Dateien:**
|
||||||
|
- v2_adminpanel/app.py
|
||||||
|
- v2_adminpanel/templates/index.html
|
||||||
|
- v2_adminpanel/init.sql
|
||||||
|
- v2_adminpanel/Dockerfile
|
||||||
|
- v2/docker-compose.yaml
|
||||||
|
|
||||||
|
**Nächster Test:**
|
||||||
|
- Container neu bauen und starten
|
||||||
|
- Kundennamen mit Umlauten testen (z.B. "Müller GmbH", "Björn Schäfer")
|
||||||
|
- Email mit Umlauten testen
|
||||||
@@ -8,6 +8,9 @@ services:
|
|||||||
env_file: .env
|
env_file: .env
|
||||||
environment:
|
environment:
|
||||||
POSTGRES_HOST: postgres
|
POSTGRES_HOST: postgres
|
||||||
|
POSTGRES_INITDB_ARGS: '--encoding=UTF8 --locale=de_DE.UTF-8'
|
||||||
|
POSTGRES_COLLATE: 'de_DE.UTF-8'
|
||||||
|
POSTGRES_CTYPE: 'de_DE.UTF-8'
|
||||||
volumes:
|
volumes:
|
||||||
# Persistente Speicherung der Datenbank auf dem Windows-Host
|
# Persistente Speicherung der Datenbank auf dem Windows-Host
|
||||||
- postgres_data:/var/lib/postgresql/data
|
- postgres_data:/var/lib/postgresql/data
|
||||||
|
|||||||
@@ -1,5 +1,10 @@
|
|||||||
FROM python:3.11-slim
|
FROM python:3.11-slim
|
||||||
|
|
||||||
|
# Locale für deutsche Sprache und UTF-8 setzen
|
||||||
|
ENV LANG=de_DE.UTF-8
|
||||||
|
ENV LC_ALL=de_DE.UTF-8
|
||||||
|
ENV PYTHONIOENCODING=utf-8
|
||||||
|
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
COPY requirements.txt .
|
COPY requirements.txt .
|
||||||
|
|||||||
@@ -10,6 +10,8 @@ load_dotenv()
|
|||||||
app = Flask(__name__)
|
app = Flask(__name__)
|
||||||
app.config['SECRET_KEY'] = os.urandom(24)
|
app.config['SECRET_KEY'] = os.urandom(24)
|
||||||
app.config['SESSION_TYPE'] = 'filesystem'
|
app.config['SESSION_TYPE'] = 'filesystem'
|
||||||
|
app.config['JSON_AS_ASCII'] = False # JSON-Ausgabe mit UTF-8
|
||||||
|
app.config['JSONIFY_MIMETYPE'] = 'application/json; charset=utf-8'
|
||||||
Session(app)
|
Session(app)
|
||||||
|
|
||||||
# Login decorator
|
# Login decorator
|
||||||
@@ -21,15 +23,18 @@ def login_required(f):
|
|||||||
return f(*args, **kwargs)
|
return f(*args, **kwargs)
|
||||||
return decorated_function
|
return decorated_function
|
||||||
|
|
||||||
# DB-Verbindung
|
# DB-Verbindung mit UTF-8 Encoding
|
||||||
def get_connection():
|
def get_connection():
|
||||||
return psycopg2.connect(
|
conn = psycopg2.connect(
|
||||||
host=os.getenv("POSTGRES_HOST", "postgres"),
|
host=os.getenv("POSTGRES_HOST", "postgres"),
|
||||||
port=os.getenv("POSTGRES_PORT", "5432"),
|
port=os.getenv("POSTGRES_PORT", "5432"),
|
||||||
dbname=os.getenv("POSTGRES_DB"),
|
dbname=os.getenv("POSTGRES_DB"),
|
||||||
user=os.getenv("POSTGRES_USER"),
|
user=os.getenv("POSTGRES_USER"),
|
||||||
password=os.getenv("POSTGRES_PASSWORD")
|
password=os.getenv("POSTGRES_PASSWORD"),
|
||||||
|
options='-c client_encoding=UTF8'
|
||||||
)
|
)
|
||||||
|
conn.set_client_encoding('UTF8')
|
||||||
|
return conn
|
||||||
|
|
||||||
@app.route("/login", methods=["GET", "POST"])
|
@app.route("/login", methods=["GET", "POST"])
|
||||||
def login():
|
def login():
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
-- UTF-8 Encoding für deutsche Sonderzeichen sicherstellen
|
||||||
|
SET client_encoding = 'UTF8';
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS customers (
|
CREATE TABLE IF NOT EXISTS customers (
|
||||||
id SERIAL PRIMARY KEY,
|
id SERIAL PRIMARY KEY,
|
||||||
name TEXT NOT NULL,
|
name TEXT NOT NULL,
|
||||||
|
|||||||
@@ -19,15 +19,15 @@
|
|||||||
<div class="container py-5">
|
<div class="container py-5">
|
||||||
<h2 class="mb-4">Neue Lizenz erstellen</h2>
|
<h2 class="mb-4">Neue Lizenz erstellen</h2>
|
||||||
|
|
||||||
<form method="post" action="/">
|
<form method="post" action="/" accept-charset="UTF-8">
|
||||||
<div class="row g-3">
|
<div class="row g-3">
|
||||||
<div class="col-md-6">
|
<div class="col-md-6">
|
||||||
<label for="customerName" class="form-label">Kundenname</label>
|
<label for="customerName" class="form-label">Kundenname</label>
|
||||||
<input type="text" class="form-control" id="customerName" name="customer_name" required>
|
<input type="text" class="form-control" id="customerName" name="customer_name" accept-charset="UTF-8" required>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-6">
|
<div class="col-md-6">
|
||||||
<label for="email" class="form-label">E-Mail</label>
|
<label for="email" class="form-label">E-Mail</label>
|
||||||
<input type="email" class="form-control" id="email" name="email">
|
<input type="email" class="form-control" id="email" name="email" accept-charset="UTF-8">
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-4">
|
<div class="col-md-4">
|
||||||
<label for="licenseKey" class="form-label">Lizenzschlüssel</label>
|
<label for="licenseKey" class="form-label">Lizenzschlüssel</label>
|
||||||
|
|||||||
101
v2_testing/test_utf8_umlaute.py
Normale Datei
101
v2_testing/test_utf8_umlaute.py
Normale Datei
@@ -0,0 +1,101 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
import requests
|
||||||
|
import urllib3
|
||||||
|
from datetime import datetime, timedelta
|
||||||
|
|
||||||
|
# Disable SSL warnings for self-signed certificate
|
||||||
|
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
|
||||||
|
|
||||||
|
# Test configuration
|
||||||
|
base_url = "https://localhost:443"
|
||||||
|
admin_user = {"username": "rac00n", "password": "1248163264"}
|
||||||
|
|
||||||
|
def test_umlaut_support():
|
||||||
|
"""Test UTF-8 support with German umlauts"""
|
||||||
|
session = requests.Session()
|
||||||
|
|
||||||
|
# Login first
|
||||||
|
login_data = {
|
||||||
|
"username": admin_user["username"],
|
||||||
|
"password": admin_user["password"]
|
||||||
|
}
|
||||||
|
|
||||||
|
response = session.post(f"{base_url}/login", data=login_data, verify=False, allow_redirects=False)
|
||||||
|
if response.status_code != 302:
|
||||||
|
return "Failed to login"
|
||||||
|
|
||||||
|
# Create test data with German umlauts
|
||||||
|
test_customers = [
|
||||||
|
{
|
||||||
|
"customer_name": "Müller GmbH & Co. KG",
|
||||||
|
"email": "kontakt@müller-gmbh.de",
|
||||||
|
"license_key": "MÜLLER-2025-ÄÖÜ",
|
||||||
|
"license_type": "Premium-Größe",
|
||||||
|
"valid_from": datetime.now().strftime("%Y-%m-%d"),
|
||||||
|
"valid_until": (datetime.now() + timedelta(days=365)).strftime("%Y-%m-%d")
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"customer_name": "Schröder Süßwaren AG",
|
||||||
|
"email": "info@schröder-süßwaren.de",
|
||||||
|
"license_key": "SCHRÖDER-2025-ßÄÖÜ",
|
||||||
|
"license_type": "Geschäftskunden",
|
||||||
|
"valid_from": datetime.now().strftime("%Y-%m-%d"),
|
||||||
|
"valid_until": (datetime.now() + timedelta(days=180)).strftime("%Y-%m-%d")
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"customer_name": "Björn Köhler Einzelunternehmen",
|
||||||
|
"email": "björn.köhler@übersetzungen.de",
|
||||||
|
"license_key": "KÖHLER-2025-BJÖRN",
|
||||||
|
"license_type": "Übersetzungsbüro",
|
||||||
|
"valid_from": datetime.now().strftime("%Y-%m-%d"),
|
||||||
|
"valid_until": (datetime.now() + timedelta(days=90)).strftime("%Y-%m-%d")
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
results = []
|
||||||
|
for customer in test_customers:
|
||||||
|
response = session.post(f"{base_url}/", data=customer, verify=False, allow_redirects=False)
|
||||||
|
|
||||||
|
if response.status_code == 302 and response.headers.get('Location') == '/':
|
||||||
|
results.append(f"✓ Created: {customer['customer_name']}")
|
||||||
|
else:
|
||||||
|
results.append(f"✗ Failed: {customer['customer_name']} - Status: {response.status_code}")
|
||||||
|
|
||||||
|
return results
|
||||||
|
|
||||||
|
print("Testing UTF-8 German Umlaut Support")
|
||||||
|
print("=" * 50)
|
||||||
|
print("Creating customers with special characters: ä, ö, ü, ß, Ä, Ö, Ü")
|
||||||
|
print("-" * 50)
|
||||||
|
|
||||||
|
results = test_umlaut_support()
|
||||||
|
for result in results:
|
||||||
|
print(result)
|
||||||
|
|
||||||
|
# Verify the data in the database
|
||||||
|
print("\n" + "=" * 50)
|
||||||
|
print("Verifying database entries:")
|
||||||
|
print("-" * 50)
|
||||||
|
|
||||||
|
import subprocess
|
||||||
|
result = subprocess.run([
|
||||||
|
"docker", "exec", "db", "psql", "-U", "adminuser", "-d", "meinedatenbank",
|
||||||
|
"-c", "SELECT c.name, c.email, l.license_key, l.license_type FROM licenses l JOIN customers c ON l.customer_id = c.id ORDER BY c.id DESC LIMIT 3;"
|
||||||
|
], capture_output=True, text=True)
|
||||||
|
|
||||||
|
print(result.stdout)
|
||||||
|
|
||||||
|
# Test direct database insertion with umlauts
|
||||||
|
print("Direct database test with umlauts:")
|
||||||
|
print("-" * 50)
|
||||||
|
|
||||||
|
test_query = """
|
||||||
|
INSERT INTO customers (name, email) VALUES ('Testfirma für Umlaute: äöüßÄÖÜ', 'test@überprüfung.de') RETURNING name, email;
|
||||||
|
"""
|
||||||
|
|
||||||
|
result = subprocess.run([
|
||||||
|
"docker", "exec", "db", "psql", "-U", "adminuser", "-d", "meinedatenbank",
|
||||||
|
"-c", test_query
|
||||||
|
], capture_output=True, text=True)
|
||||||
|
|
||||||
|
print(result.stdout)
|
||||||
In neuem Issue referenzieren
Einen Benutzer sperren