Initial commit
Dieser Commit ist enthalten in:
10
v2_testing/.claude/settings.local.json
Normale Datei
10
v2_testing/.claude/settings.local.json
Normale Datei
@ -0,0 +1,10 @@
|
||||
{
|
||||
"permissions": {
|
||||
"allow": [
|
||||
"Bash(python3:*)",
|
||||
"Bash(pip install:*)",
|
||||
"Bash(pip3 install:*)"
|
||||
],
|
||||
"deny": []
|
||||
}
|
||||
}
|
||||
53
v2_testing/test_admin_login.py
Normale Datei
53
v2_testing/test_admin_login.py
Normale Datei
@ -0,0 +1,53 @@
|
||||
#!/usr/bin/env python3
|
||||
import requests
|
||||
import urllib3
|
||||
|
||||
# Disable SSL warnings for self-signed certificate
|
||||
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
|
||||
|
||||
# Test configuration
|
||||
base_url = "https://localhost:443"
|
||||
admin_users = [
|
||||
{"username": "rac00n", "password": "1248163264"},
|
||||
{"username": "w@rh@mm3r", "password": "Warhammer123!"}
|
||||
]
|
||||
|
||||
def test_login(username, password):
|
||||
"""Test login functionality for admin user"""
|
||||
session = requests.Session()
|
||||
|
||||
# Get login page
|
||||
response = session.get(f"{base_url}/login", verify=False)
|
||||
if response.status_code != 200:
|
||||
return f"Failed to access login page: {response.status_code}"
|
||||
|
||||
# Attempt login
|
||||
login_data = {
|
||||
"username": username,
|
||||
"password": password
|
||||
}
|
||||
|
||||
response = session.post(f"{base_url}/login", data=login_data, verify=False, allow_redirects=False)
|
||||
|
||||
# Check if login was successful (redirect to dashboard)
|
||||
if response.status_code == 302 and response.headers.get('Location') == '/':
|
||||
# Try to access dashboard
|
||||
dashboard_response = session.get(f"{base_url}/", verify=False)
|
||||
if dashboard_response.status_code == 200 and username in dashboard_response.text:
|
||||
return f"✓ Login successful for {username}"
|
||||
else:
|
||||
return f"✗ Login succeeded but dashboard access failed for {username}"
|
||||
else:
|
||||
return f"✗ Login failed for {username}"
|
||||
|
||||
# Test both admin users
|
||||
print("Testing Admin Panel Login Functionality")
|
||||
print("=" * 40)
|
||||
|
||||
for user in admin_users:
|
||||
result = test_login(user["username"], user["password"])
|
||||
print(result)
|
||||
|
||||
print("\nTesting invalid credentials...")
|
||||
result = test_login("invalid_user", "wrong_password")
|
||||
print(result)
|
||||
125
v2_testing/test_audit_json.py
Normale Datei
125
v2_testing/test_audit_json.py
Normale Datei
@ -0,0 +1,125 @@
|
||||
#!/usr/bin/env python3
|
||||
import requests
|
||||
import urllib3
|
||||
import subprocess
|
||||
import json
|
||||
|
||||
# Disable SSL warnings
|
||||
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
|
||||
|
||||
base_url = "https://localhost:443"
|
||||
admin_user = {"username": "rac00n", "password": "1248163264"}
|
||||
|
||||
def login(session):
|
||||
"""Login to admin panel"""
|
||||
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)
|
||||
return response.status_code == 302
|
||||
|
||||
def test_json_logging():
|
||||
"""Test JSON value logging in audit log"""
|
||||
session = requests.Session()
|
||||
login(session)
|
||||
|
||||
print("Testing JSON Value Storage in Audit Log")
|
||||
print("=" * 50)
|
||||
|
||||
# 1. Create a license (should log new_values as JSON)
|
||||
print("\n1. Creating license to test JSON logging...")
|
||||
license_data = {
|
||||
"customer_name": "JSON Test GmbH",
|
||||
"email": "json@test.de",
|
||||
"license_key": "JSON-TEST-KEY",
|
||||
"license_type": "full",
|
||||
"valid_from": "2025-01-01",
|
||||
"valid_until": "2025-12-31"
|
||||
}
|
||||
response = session.post(f"{base_url}/create", data=license_data, verify=False, allow_redirects=False)
|
||||
print("✓ License created")
|
||||
|
||||
# 2. Get the license ID
|
||||
result = subprocess.run([
|
||||
"docker", "exec", "db", "psql", "-U", "adminuser", "-d", "meinedatenbank", "-t",
|
||||
"-c", "SELECT id FROM licenses WHERE license_key = 'JSON-TEST-KEY';"
|
||||
], capture_output=True, text=True)
|
||||
license_id = result.stdout.strip()
|
||||
|
||||
if license_id:
|
||||
# 3. Edit the license (should log both old_values and new_values)
|
||||
print("\n2. Editing license to test old/new JSON values...")
|
||||
|
||||
# First get the edit page to ensure we have the right form
|
||||
response = session.get(f"{base_url}/license/edit/{license_id}", verify=False)
|
||||
|
||||
# Now update
|
||||
updated_data = {
|
||||
"license_key": "JSON-TEST-UPDATED",
|
||||
"license_type": "test",
|
||||
"valid_from": "2025-01-01",
|
||||
"valid_until": "2025-06-30",
|
||||
"is_active": "on"
|
||||
}
|
||||
response = session.post(f"{base_url}/license/edit/{license_id}",
|
||||
data=updated_data,
|
||||
verify=False,
|
||||
allow_redirects=False)
|
||||
print("✓ License updated")
|
||||
|
||||
# 4. Check the audit log for JSON values
|
||||
print("\n3. Checking audit log for JSON values...")
|
||||
result = subprocess.run([
|
||||
"docker", "exec", "db", "psql", "-U", "adminuser", "-d", "meinedatenbank",
|
||||
"-c", """SELECT action, entity_type,
|
||||
CASE WHEN old_values IS NULL THEN 'NULL'
|
||||
ELSE jsonb_pretty(old_values) END as old_vals,
|
||||
CASE WHEN new_values IS NULL THEN 'NULL'
|
||||
ELSE jsonb_pretty(new_values) END as new_vals
|
||||
FROM audit_log
|
||||
WHERE entity_type IN ('license', 'customer')
|
||||
AND (old_values IS NOT NULL OR new_values IS NOT NULL)
|
||||
ORDER BY timestamp DESC
|
||||
LIMIT 5;"""
|
||||
], capture_output=True, text=True)
|
||||
|
||||
print(result.stdout)
|
||||
|
||||
# 5. Test specific JSON queries
|
||||
print("\n4. Testing JSON queries...")
|
||||
|
||||
# Query for specific license key in new_values
|
||||
result = subprocess.run([
|
||||
"docker", "exec", "db", "psql", "-U", "adminuser", "-d", "meinedatenbank", "-t",
|
||||
"-c", """SELECT COUNT(*)
|
||||
FROM audit_log
|
||||
WHERE new_values->>'license_key' LIKE 'JSON%';"""
|
||||
], capture_output=True, text=True)
|
||||
|
||||
count = int(result.stdout.strip())
|
||||
if count > 0:
|
||||
print(f"✓ Found {count} entries with JSON license keys")
|
||||
|
||||
# Query for updates (where both old and new values exist)
|
||||
result = subprocess.run([
|
||||
"docker", "exec", "db", "psql", "-U", "adminuser", "-d", "meinedatenbank", "-t",
|
||||
"-c", """SELECT COUNT(*)
|
||||
FROM audit_log
|
||||
WHERE old_values IS NOT NULL
|
||||
AND new_values IS NOT NULL;"""
|
||||
], capture_output=True, text=True)
|
||||
|
||||
update_count = int(result.stdout.strip())
|
||||
print(f"✓ Found {update_count} UPDATE entries with both old and new values")
|
||||
|
||||
# 6. Clean up test data
|
||||
print("\n5. Cleaning up test data...")
|
||||
subprocess.run([
|
||||
"docker", "exec", "db", "psql", "-U", "adminuser", "-d", "meinedatenbank",
|
||||
"-c", "DELETE FROM licenses WHERE license_key LIKE 'JSON%';"
|
||||
], capture_output=True)
|
||||
print("✓ Test data cleaned up")
|
||||
|
||||
# Run the test
|
||||
test_json_logging()
|
||||
238
v2_testing/test_audit_log.py
Normale Datei
238
v2_testing/test_audit_log.py
Normale Datei
@ -0,0 +1,238 @@
|
||||
#!/usr/bin/env python3
|
||||
import requests
|
||||
import urllib3
|
||||
import subprocess
|
||||
import time
|
||||
import json
|
||||
|
||||
# Disable SSL warnings
|
||||
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
|
||||
|
||||
base_url = "https://localhost:443"
|
||||
admin_user = {"username": "rac00n", "password": "1248163264"}
|
||||
|
||||
def login(session):
|
||||
"""Login to admin panel"""
|
||||
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)
|
||||
return response.status_code == 302
|
||||
|
||||
def test_audit_table():
|
||||
"""Test if audit_log table exists"""
|
||||
print("1. Checking Audit Log Table:")
|
||||
print("-" * 40)
|
||||
|
||||
result = subprocess.run([
|
||||
"docker", "exec", "db", "psql", "-U", "adminuser", "-d", "meinedatenbank",
|
||||
"-c", "\\d audit_log"
|
||||
], capture_output=True, text=True)
|
||||
|
||||
if "Table \"public.audit_log\"" in result.stdout:
|
||||
print("✓ Audit log table exists")
|
||||
print("\nTable structure:")
|
||||
print(result.stdout)
|
||||
return True
|
||||
else:
|
||||
print("✗ Audit log table not found - creating it")
|
||||
# Create table
|
||||
subprocess.run([
|
||||
"docker", "exec", "db", "psql", "-U", "adminuser", "-d", "meinedatenbank",
|
||||
"-f", "/docker-entrypoint-initdb.d/init.sql"
|
||||
], capture_output=True)
|
||||
return False
|
||||
|
||||
def test_audit_logging():
|
||||
"""Test various actions to generate audit logs"""
|
||||
session = requests.Session()
|
||||
|
||||
print("\n2. Testing Audit Log Generation:")
|
||||
print("-" * 40)
|
||||
|
||||
# Test 1: Login
|
||||
print("Testing LOGIN audit...")
|
||||
login(session)
|
||||
print("✓ Login performed")
|
||||
|
||||
# Test 2: Create license
|
||||
print("\nTesting CREATE audit...")
|
||||
license_data = {
|
||||
"customer_name": "Audit Test GmbH",
|
||||
"email": "audit@test.de",
|
||||
"license_key": "AUDIT-TEST-001",
|
||||
"license_type": "test",
|
||||
"valid_from": "2025-01-01",
|
||||
"valid_until": "2025-12-31"
|
||||
}
|
||||
response = session.post(f"{base_url}/create", data=license_data, verify=False, allow_redirects=False)
|
||||
if response.status_code == 302:
|
||||
print("✓ License created")
|
||||
|
||||
# Test 3: Export
|
||||
print("\nTesting EXPORT audit...")
|
||||
response = session.get(f"{base_url}/export/licenses?format=csv", verify=False)
|
||||
if response.status_code == 200:
|
||||
print("✓ Export performed")
|
||||
|
||||
# Test 4: Logout
|
||||
print("\nTesting LOGOUT audit...")
|
||||
response = session.get(f"{base_url}/logout", verify=False, allow_redirects=False)
|
||||
if response.status_code == 302:
|
||||
print("✓ Logout performed")
|
||||
|
||||
# Wait for logs to be written
|
||||
time.sleep(1)
|
||||
|
||||
def test_audit_page():
|
||||
"""Test the audit log page"""
|
||||
session = requests.Session()
|
||||
login(session)
|
||||
|
||||
print("\n3. Testing Audit Log Page:")
|
||||
print("-" * 40)
|
||||
|
||||
response = session.get(f"{base_url}/audit", verify=False)
|
||||
|
||||
if response.status_code == 200:
|
||||
print("✓ Audit log page accessible")
|
||||
|
||||
content = response.text
|
||||
|
||||
# Check for expected elements
|
||||
checks = [
|
||||
("Audit-Log", "Page title"),
|
||||
("Zeitstempel", "Timestamp column"),
|
||||
("Benutzer", "User column"),
|
||||
("Aktion", "Action column"),
|
||||
("Entität", "Entity column"),
|
||||
("IP-Adresse", "IP address column"),
|
||||
("LOGIN", "Login action"),
|
||||
("LOGOUT", "Logout action"),
|
||||
("CREATE", "Create action"),
|
||||
("EXPORT", "Export action")
|
||||
]
|
||||
|
||||
found = 0
|
||||
for check_text, description in checks:
|
||||
if check_text in content:
|
||||
found += 1
|
||||
|
||||
print(f"✓ Found {found}/{len(checks)} expected elements")
|
||||
|
||||
# Check filters
|
||||
if '<select' in content and 'filter' in content.lower():
|
||||
print("✓ Filter options available")
|
||||
else:
|
||||
print(f"✗ Failed to access audit log page: Status {response.status_code}")
|
||||
|
||||
def check_audit_logs_db():
|
||||
"""Check audit logs directly in database"""
|
||||
print("\n4. Database Audit Log Check:")
|
||||
print("-" * 40)
|
||||
|
||||
result = subprocess.run([
|
||||
"docker", "exec", "db", "psql", "-U", "adminuser", "-d", "meinedatenbank",
|
||||
"-c", """SELECT action, entity_type, username,
|
||||
CASE WHEN old_values IS NULL THEN 'NULL' ELSE 'JSON' END as old_v,
|
||||
CASE WHEN new_values IS NULL THEN 'NULL' ELSE 'JSON' END as new_v,
|
||||
additional_info
|
||||
FROM audit_log
|
||||
ORDER BY timestamp DESC
|
||||
LIMIT 10;"""
|
||||
], capture_output=True, text=True)
|
||||
|
||||
print(result.stdout)
|
||||
|
||||
# Count total logs
|
||||
result = subprocess.run([
|
||||
"docker", "exec", "db", "psql", "-U", "adminuser", "-d", "meinedatenbank", "-t",
|
||||
"-c", "SELECT COUNT(*) FROM audit_log;"
|
||||
], capture_output=True, text=True)
|
||||
|
||||
count = int(result.stdout.strip())
|
||||
print(f"\nTotal audit log entries: {count}")
|
||||
|
||||
def test_audit_filters():
|
||||
"""Test audit log filters"""
|
||||
session = requests.Session()
|
||||
login(session)
|
||||
|
||||
print("\n5. Testing Audit Log Filters:")
|
||||
print("-" * 40)
|
||||
|
||||
# Test different filters
|
||||
filters = [
|
||||
("?action=LOGIN", "Filter by LOGIN action"),
|
||||
("?user=rac00n", "Filter by username"),
|
||||
("?entity=license", "Filter by entity type"),
|
||||
("?page=2", "Pagination test")
|
||||
]
|
||||
|
||||
for filter_param, description in filters:
|
||||
response = session.get(f"{base_url}/audit{filter_param}", verify=False)
|
||||
if response.status_code == 200:
|
||||
print(f"✓ {description}: Working")
|
||||
else:
|
||||
print(f"✗ {description}: Failed")
|
||||
|
||||
def test_json_values():
|
||||
"""Test JSON storage of old/new values"""
|
||||
print("\n6. Testing JSON Value Storage:")
|
||||
print("-" * 40)
|
||||
|
||||
# Get a recent update log with JSON values
|
||||
result = subprocess.run([
|
||||
"docker", "exec", "db", "psql", "-U", "adminuser", "-d", "meinedatenbank", "-t",
|
||||
"-c", """SELECT new_values::text
|
||||
FROM audit_log
|
||||
WHERE action = 'CREATE'
|
||||
AND new_values IS NOT NULL
|
||||
LIMIT 1;"""
|
||||
], capture_output=True, text=True)
|
||||
|
||||
if result.stdout.strip():
|
||||
try:
|
||||
json_data = json.loads(result.stdout.strip())
|
||||
print("✓ JSON values stored correctly")
|
||||
print(f"Sample JSON keys: {list(json_data.keys())}")
|
||||
except:
|
||||
print("✗ Invalid JSON format")
|
||||
else:
|
||||
print("✗ No JSON values found")
|
||||
|
||||
# Main execution
|
||||
print("Testing Audit Log Functionality")
|
||||
print("=" * 50)
|
||||
|
||||
# Ensure table exists
|
||||
if not test_audit_table():
|
||||
print("\nRestarting containers to create audit_log table...")
|
||||
subprocess.run(["docker-compose", "down"], capture_output=True)
|
||||
subprocess.run(["docker-compose", "up", "-d"], capture_output=True)
|
||||
subprocess.run(["sleep", "7"], capture_output=True)
|
||||
test_audit_table()
|
||||
|
||||
# Generate test data
|
||||
test_audit_logging()
|
||||
|
||||
# Check results
|
||||
test_audit_page()
|
||||
check_audit_logs_db()
|
||||
test_audit_filters()
|
||||
test_json_values()
|
||||
|
||||
print("\n" + "=" * 50)
|
||||
print("Audit Log Summary:")
|
||||
print("-" * 40)
|
||||
|
||||
# Summary statistics
|
||||
result = subprocess.run([
|
||||
"docker", "exec", "db", "psql", "-U", "adminuser", "-d", "meinedatenbank",
|
||||
"-c", """SELECT action, COUNT(*) as count
|
||||
FROM audit_log
|
||||
GROUP BY action
|
||||
ORDER BY count DESC;"""
|
||||
], capture_output=True, text=True)
|
||||
print(result.stdout)
|
||||
104
v2_testing/test_audit_raw.py
Normale Datei
104
v2_testing/test_audit_raw.py
Normale Datei
@ -0,0 +1,104 @@
|
||||
#!/usr/bin/env python3
|
||||
import requests
|
||||
import urllib3
|
||||
from datetime import datetime
|
||||
from zoneinfo import ZoneInfo
|
||||
from bs4 import BeautifulSoup
|
||||
import time
|
||||
|
||||
# Disable SSL warnings for self-signed certificate
|
||||
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
|
||||
|
||||
# Test configuration
|
||||
base_url = "https://admin-panel-undso.z5m7q9dk3ah2v1plx6ju.com"
|
||||
fallback_url = "https://localhost:443"
|
||||
admin_user = {"username": "rac00n", "password": "1248163264"}
|
||||
|
||||
def test_audit_raw():
|
||||
"""Test audit log timezone by parsing HTML"""
|
||||
session = requests.Session()
|
||||
|
||||
print("Audit Log Raw HTML Test")
|
||||
print("=" * 50)
|
||||
|
||||
# Test connection
|
||||
try:
|
||||
test_response = session.get(base_url, verify=True, timeout=5)
|
||||
verify_ssl = True
|
||||
base_url_local = base_url
|
||||
print(f"✓ Using external URL: {base_url}")
|
||||
except:
|
||||
base_url_local = fallback_url
|
||||
verify_ssl = False
|
||||
print(f"ℹ Using fallback URL: {fallback_url}")
|
||||
|
||||
# Show current times
|
||||
utc_now = datetime.now(ZoneInfo("UTC"))
|
||||
berlin_now = datetime.now(ZoneInfo("Europe/Berlin"))
|
||||
|
||||
print(f"\nCurrent times:")
|
||||
print(f" UTC: {utc_now.strftime('%Y-%m-%d %H:%M:%S')}")
|
||||
print(f" Berlin: {berlin_now.strftime('%Y-%m-%d %H:%M:%S')}")
|
||||
|
||||
# Logout first
|
||||
session.get(f"{base_url_local}/logout", verify=verify_ssl)
|
||||
time.sleep(1)
|
||||
|
||||
# Login
|
||||
response = session.get(f"{base_url_local}/login", verify=verify_ssl)
|
||||
login_data = {
|
||||
"username": admin_user["username"],
|
||||
"password": admin_user["password"]
|
||||
}
|
||||
response = session.post(f"{base_url_local}/login", data=login_data, verify=verify_ssl, allow_redirects=False)
|
||||
|
||||
if response.status_code != 302:
|
||||
print(f"✗ Login failed")
|
||||
return
|
||||
|
||||
print("✓ Login successful")
|
||||
|
||||
# Get audit log
|
||||
print("\nFetching audit log...")
|
||||
response = session.get(f"{base_url_local}/audit", verify=verify_ssl)
|
||||
|
||||
if response.status_code == 200:
|
||||
# Save raw HTML for inspection
|
||||
with open("audit_log_raw.html", "w", encoding="utf-8") as f:
|
||||
f.write(response.text)
|
||||
print("✓ Saved raw HTML to audit_log_raw.html")
|
||||
|
||||
# Parse with BeautifulSoup
|
||||
soup = BeautifulSoup(response.text, 'html.parser')
|
||||
|
||||
# Find all table rows
|
||||
rows = soup.find_all('tr')
|
||||
print(f"✓ Found {len(rows)} table rows")
|
||||
|
||||
# Look for LOGIN_SUCCESS in recent entries
|
||||
for i, row in enumerate(rows[:5]): # Check first 5 rows
|
||||
cells = row.find_all('td')
|
||||
if cells and len(cells) > 1:
|
||||
timestamp_cell = cells[0].text.strip()
|
||||
action_cell = cells[2].text.strip() if len(cells) > 2 else ""
|
||||
|
||||
if i == 0:
|
||||
print(f"\nFirst row details:")
|
||||
print(f" Timestamp: {timestamp_cell}")
|
||||
print(f" Action: {action_cell}")
|
||||
|
||||
if "LOGIN_SUCCESS" in action_cell:
|
||||
print(f"\nFound LOGIN_SUCCESS entry:")
|
||||
print(f" Timestamp: {timestamp_cell}")
|
||||
|
||||
# Check if timestamp contains current Berlin hour
|
||||
if berlin_now.strftime("%H:") in timestamp_cell:
|
||||
print(f" ✓ Contains Berlin hour ({berlin_now.strftime('%H:')})")
|
||||
elif utc_now.strftime("%H:") in timestamp_cell:
|
||||
print(f" ✗ Contains UTC hour ({utc_now.strftime('%H:')})")
|
||||
break
|
||||
else:
|
||||
print(f"✗ Failed to fetch audit log: {response.status_code}")
|
||||
|
||||
if __name__ == "__main__":
|
||||
test_audit_raw()
|
||||
113
v2_testing/test_audit_simple.py
Normale Datei
113
v2_testing/test_audit_simple.py
Normale Datei
@ -0,0 +1,113 @@
|
||||
#!/usr/bin/env python3
|
||||
import requests
|
||||
import urllib3
|
||||
from datetime import datetime
|
||||
from zoneinfo import ZoneInfo
|
||||
import time
|
||||
import re
|
||||
|
||||
# Disable SSL warnings for self-signed certificate
|
||||
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
|
||||
|
||||
# Test configuration
|
||||
base_url = "https://admin-panel-undso.z5m7q9dk3ah2v1plx6ju.com"
|
||||
fallback_url = "https://localhost:443"
|
||||
admin_user = {"username": "rac00n", "password": "1248163264"}
|
||||
|
||||
def test_audit_simple():
|
||||
"""Simple test to check audit log timestamps"""
|
||||
session = requests.Session()
|
||||
|
||||
print("Audit Log Timezone Check")
|
||||
print("=" * 50)
|
||||
|
||||
# Test connection
|
||||
try:
|
||||
test_response = session.get(base_url, verify=True, timeout=5)
|
||||
verify_ssl = True
|
||||
base_url_local = base_url
|
||||
print(f"✓ Using external URL: {base_url}")
|
||||
except:
|
||||
base_url_local = fallback_url
|
||||
verify_ssl = False
|
||||
print(f"ℹ Using fallback URL: {fallback_url}")
|
||||
|
||||
# Show current times
|
||||
utc_now = datetime.now(ZoneInfo("UTC"))
|
||||
berlin_now = datetime.now(ZoneInfo("Europe/Berlin"))
|
||||
|
||||
print(f"\nCurrent times:")
|
||||
print(f" UTC: {utc_now.strftime('%Y-%m-%d %H:%M:%S')}")
|
||||
print(f" Berlin: {berlin_now.strftime('%Y-%m-%d %H:%M:%S')}")
|
||||
print(f" Difference: {(berlin_now.hour - utc_now.hour) % 24} hours")
|
||||
|
||||
# Login
|
||||
response = session.get(f"{base_url_local}/login", verify=verify_ssl)
|
||||
login_data = {
|
||||
"username": admin_user["username"],
|
||||
"password": admin_user["password"]
|
||||
}
|
||||
response = session.post(f"{base_url_local}/login", data=login_data, verify=verify_ssl, allow_redirects=False)
|
||||
|
||||
if response.status_code != 302:
|
||||
print(f"✗ Login failed")
|
||||
return
|
||||
|
||||
print("✓ Login successful")
|
||||
|
||||
# Create a distinctive action to find in audit log
|
||||
print("\nCreating a test action...")
|
||||
|
||||
# Try to access customers page (this will create an audit entry)
|
||||
response = session.get(f"{base_url_local}/customers", verify=verify_ssl)
|
||||
|
||||
# Now check audit log
|
||||
print("\nChecking audit log...")
|
||||
response = session.get(f"{base_url_local}/audit", verify=verify_ssl)
|
||||
|
||||
if response.status_code == 200:
|
||||
# Look for table rows with class="table"
|
||||
# Extract just the table content
|
||||
table_match = re.search(r'<table class="table[^>]*>(.*?)</table>', response.text, re.DOTALL)
|
||||
|
||||
if table_match:
|
||||
table_content = table_match.group(1)
|
||||
|
||||
# Find all <tr> tags
|
||||
rows = re.findall(r'<tr[^>]*>(.*?)</tr>', table_content, re.DOTALL)
|
||||
|
||||
print(f"✓ Found {len(rows)} audit log entries")
|
||||
|
||||
if rows:
|
||||
# Get the first data row (skip header)
|
||||
first_row = rows[1] if len(rows) > 1 else rows[0]
|
||||
|
||||
# Extract timestamp from first cell
|
||||
timestamp_match = re.search(r'<td[^>]*>([^<]+)</td>', first_row)
|
||||
|
||||
if timestamp_match:
|
||||
timestamp = timestamp_match.group(1).strip()
|
||||
print(f"\nMost recent audit entry timestamp: {timestamp}")
|
||||
|
||||
# Check if it contains current Berlin hour
|
||||
berlin_hour = berlin_now.strftime("%H:")
|
||||
utc_hour = utc_now.strftime("%H:")
|
||||
|
||||
if berlin_hour in timestamp:
|
||||
print(f"✓ Timestamp contains Berlin hour ({berlin_hour})")
|
||||
print("✓ Audit log is using Berlin timezone!")
|
||||
elif utc_hour in timestamp:
|
||||
print(f"✗ Timestamp contains UTC hour ({utc_hour})")
|
||||
print("✗ Audit log is still using UTC")
|
||||
print("\nTo fix this:")
|
||||
print("1. cd ../v2")
|
||||
print("2. docker-compose down")
|
||||
print("3. docker-compose build --no-cache")
|
||||
print("4. docker-compose up -d")
|
||||
else:
|
||||
print("⚠ Could not determine timezone from timestamp")
|
||||
else:
|
||||
print(f"✗ Failed to fetch audit log: {response.status_code}")
|
||||
|
||||
if __name__ == "__main__":
|
||||
test_audit_simple()
|
||||
123
v2_testing/test_audit_timezone.py
Normale Datei
123
v2_testing/test_audit_timezone.py
Normale Datei
@ -0,0 +1,123 @@
|
||||
#!/usr/bin/env python3
|
||||
import requests
|
||||
import urllib3
|
||||
from datetime import datetime
|
||||
from zoneinfo import ZoneInfo
|
||||
import time
|
||||
import re
|
||||
|
||||
# Disable SSL warnings for self-signed certificate
|
||||
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
|
||||
|
||||
# Test configuration
|
||||
base_url = "https://admin-panel-undso.z5m7q9dk3ah2v1plx6ju.com"
|
||||
fallback_url = "https://localhost:443"
|
||||
admin_user = {"username": "rac00n", "password": "1248163264"}
|
||||
|
||||
def test_audit_timezone():
|
||||
"""Test audit log timezone specifically"""
|
||||
session = requests.Session()
|
||||
|
||||
print("Audit Log Timezone Test")
|
||||
print("=" * 50)
|
||||
|
||||
# Test connection
|
||||
try:
|
||||
test_response = session.get(base_url, verify=True, timeout=5)
|
||||
verify_ssl = True
|
||||
base_url_local = base_url
|
||||
print(f"✓ Using external URL: {base_url}")
|
||||
except:
|
||||
base_url_local = fallback_url
|
||||
verify_ssl = False
|
||||
print(f"ℹ Using fallback URL: {fallback_url}")
|
||||
|
||||
# Show current times
|
||||
utc_now = datetime.now(ZoneInfo("UTC"))
|
||||
berlin_now = datetime.now(ZoneInfo("Europe/Berlin"))
|
||||
|
||||
print(f"\nCurrent times:")
|
||||
print(f" UTC: {utc_now.strftime('%Y-%m-%d %H:%M:%S')}")
|
||||
print(f" Berlin: {berlin_now.strftime('%Y-%m-%d %H:%M:%S')}")
|
||||
print(f" Offset: +{(berlin_now.hour - utc_now.hour) % 24} hours")
|
||||
|
||||
# First logout if already logged in
|
||||
session.get(f"{base_url_local}/logout", verify=verify_ssl)
|
||||
time.sleep(1)
|
||||
|
||||
# Login (this will create a new audit log entry)
|
||||
print(f"\nPerforming login at {berlin_now.strftime('%H:%M:%S')} Berlin time...")
|
||||
|
||||
response = session.get(f"{base_url_local}/login", verify=verify_ssl)
|
||||
if response.status_code != 200:
|
||||
print(f"✗ Failed to access login page: {response.status_code}")
|
||||
return
|
||||
|
||||
login_data = {
|
||||
"username": admin_user["username"],
|
||||
"password": admin_user["password"]
|
||||
}
|
||||
|
||||
response = session.post(f"{base_url_local}/login", data=login_data, verify=verify_ssl, allow_redirects=False)
|
||||
|
||||
if response.status_code != 302:
|
||||
print(f"✗ Login failed: {response.status_code}")
|
||||
return
|
||||
|
||||
print("✓ Login successful")
|
||||
|
||||
# Immediately check audit log
|
||||
print("\nChecking audit log for fresh LOGIN_SUCCESS entry...")
|
||||
response = session.get(f"{base_url_local}/audit", verify=verify_ssl)
|
||||
|
||||
if response.status_code == 200:
|
||||
# Look for timestamps in the audit log
|
||||
# Pattern to find timestamps in format YYYY-MM-DD HH:MM:SS
|
||||
timestamp_pattern = r'(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2})'
|
||||
|
||||
# Find all timestamps
|
||||
timestamps = re.findall(timestamp_pattern, response.text)
|
||||
|
||||
if timestamps:
|
||||
print(f"✓ Found {len(timestamps)} timestamps in audit log")
|
||||
|
||||
# Check the most recent timestamp (should be first in list)
|
||||
if timestamps:
|
||||
latest_timestamp = timestamps[0]
|
||||
print(f"\nMost recent timestamp: {latest_timestamp}")
|
||||
|
||||
# Extract hour from timestamp
|
||||
hour_match = re.search(r' (\d{2}):', latest_timestamp)
|
||||
if hour_match:
|
||||
log_hour = int(hour_match.group(1))
|
||||
berlin_hour = berlin_now.hour
|
||||
utc_hour = utc_now.hour
|
||||
|
||||
print(f" Timestamp hour: {log_hour:02d}")
|
||||
print(f" Berlin hour: {berlin_hour:02d}")
|
||||
print(f" UTC hour: {utc_hour:02d}")
|
||||
|
||||
if log_hour == berlin_hour:
|
||||
print("\n✓ Audit log is using Berlin time!")
|
||||
elif log_hour == utc_hour:
|
||||
print("\n✗ Audit log appears to be using UTC time")
|
||||
print(" → Docker containers may need to be rebuilt")
|
||||
else:
|
||||
print("\n⚠ Could not determine timezone (timestamp doesn't match either timezone)")
|
||||
else:
|
||||
print("✗ No timestamps found in audit log")
|
||||
|
||||
# Also check for "vor X Minuten" text which might indicate timezone
|
||||
if "vor 0 Minuten" in response.text or "vor 1 Minute" in response.text:
|
||||
print("\n✓ Recent entries found (German time format)")
|
||||
else:
|
||||
print(f"✗ Failed to access audit log: {response.status_code}")
|
||||
|
||||
print("\n" + "=" * 50)
|
||||
print("If timestamps show UTC instead of Berlin time:")
|
||||
print("1. Run: docker-compose down")
|
||||
print("2. Run: docker-compose build --no-cache")
|
||||
print("3. Run: docker-compose up -d")
|
||||
|
||||
if __name__ == "__main__":
|
||||
test_audit_timezone()
|
||||
207
v2_testing/test_customer_management.py
Normale Datei
207
v2_testing/test_customer_management.py
Normale Datei
@ -0,0 +1,207 @@
|
||||
#!/usr/bin/env python3
|
||||
import requests
|
||||
import urllib3
|
||||
import subprocess
|
||||
from datetime import datetime
|
||||
|
||||
# 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 login(session):
|
||||
"""Login to admin panel"""
|
||||
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)
|
||||
return response.status_code == 302
|
||||
|
||||
def test_customer_list():
|
||||
"""Test customer list view"""
|
||||
session = requests.Session()
|
||||
|
||||
if not login(session):
|
||||
return "✗ Failed to login"
|
||||
|
||||
response = session.get(f"{base_url}/customers", verify=False)
|
||||
if response.status_code != 200:
|
||||
return f"✗ Failed to access customers page: Status {response.status_code}"
|
||||
|
||||
content = response.text
|
||||
|
||||
# Check for expected customers
|
||||
expected_customers = ["Müller GmbH", "Test Customer", "Schröder Süßwaren AG", "Björn Köhler"]
|
||||
found_customers = []
|
||||
|
||||
for customer in expected_customers:
|
||||
if customer in content:
|
||||
found_customers.append(customer)
|
||||
|
||||
if len(found_customers) > 0:
|
||||
return f"✓ Customer list loaded successfully ({len(found_customers)} customers found)"
|
||||
else:
|
||||
return "✗ No customers found in list"
|
||||
|
||||
def test_edit_customer():
|
||||
"""Test editing a customer"""
|
||||
session = requests.Session()
|
||||
|
||||
if not login(session):
|
||||
return "✗ Failed to login"
|
||||
|
||||
# Get a customer ID to edit (let's find "Test Customer")
|
||||
result = subprocess.run([
|
||||
"docker", "exec", "db", "psql", "-U", "adminuser", "-d", "meinedatenbank", "-t",
|
||||
"-c", "SELECT id FROM customers WHERE name = 'Test Customer' LIMIT 1;"
|
||||
], capture_output=True, text=True)
|
||||
|
||||
customer_id = result.stdout.strip()
|
||||
if not customer_id:
|
||||
return "✗ Failed to find test customer"
|
||||
|
||||
# Test GET edit page
|
||||
response = session.get(f"{base_url}/customer/edit/{customer_id}", verify=False)
|
||||
if response.status_code != 200:
|
||||
return f"✗ Failed to access customer edit page: Status {response.status_code}"
|
||||
|
||||
# Check if customer data and licenses are displayed
|
||||
content = response.text
|
||||
if "Test Customer" not in content:
|
||||
return "✗ Edit page doesn't show customer data"
|
||||
|
||||
# Update customer data
|
||||
updated_data = {
|
||||
"name": "Test Customer GmbH & Co. KG",
|
||||
"email": "updated@testcustomer.de"
|
||||
}
|
||||
|
||||
response = session.post(f"{base_url}/customer/edit/{customer_id}",
|
||||
data=updated_data,
|
||||
verify=False,
|
||||
allow_redirects=False)
|
||||
|
||||
if response.status_code == 302 and response.headers.get('Location') == '/customers':
|
||||
return "✓ Customer edited successfully"
|
||||
else:
|
||||
return f"✗ Failed to edit customer: Status {response.status_code}"
|
||||
|
||||
def test_delete_customer():
|
||||
"""Test deleting a customer"""
|
||||
session = requests.Session()
|
||||
|
||||
if not login(session):
|
||||
return "✗ Failed to login"
|
||||
|
||||
# Create a test customer without licenses
|
||||
test_customer = {
|
||||
"customer_name": "Löschtest Firma GmbH",
|
||||
"email": "delete@löschtest.de",
|
||||
"license_key": "TEMP-KEY-DELETE",
|
||||
"license_type": "Test",
|
||||
"valid_from": "2025-01-01",
|
||||
"valid_until": "2025-01-02"
|
||||
}
|
||||
|
||||
# Create customer with license
|
||||
session.post(f"{base_url}/", data=test_customer, verify=False, allow_redirects=False)
|
||||
|
||||
# Get the customer ID
|
||||
result = subprocess.run([
|
||||
"docker", "exec", "db", "psql", "-U", "adminuser", "-d", "meinedatenbank", "-t",
|
||||
"-c", "SELECT id FROM customers WHERE name = 'Löschtest Firma GmbH';"
|
||||
], capture_output=True, text=True)
|
||||
|
||||
customer_id = result.stdout.strip()
|
||||
if not customer_id:
|
||||
return "✗ Failed to create test customer"
|
||||
|
||||
# First, try to delete customer with license (should fail)
|
||||
response = session.post(f"{base_url}/customer/delete/{customer_id}",
|
||||
verify=False,
|
||||
allow_redirects=False)
|
||||
|
||||
# Check if customer still exists (should not be deleted due to license)
|
||||
result = subprocess.run([
|
||||
"docker", "exec", "db", "psql", "-U", "adminuser", "-d", "meinedatenbank", "-t",
|
||||
"-c", f"SELECT COUNT(*) FROM customers WHERE id = {customer_id};"
|
||||
], capture_output=True, text=True)
|
||||
|
||||
if int(result.stdout.strip()) != 1:
|
||||
return "✗ Customer with licenses was incorrectly deleted"
|
||||
|
||||
# Now delete the license first
|
||||
subprocess.run([
|
||||
"docker", "exec", "db", "psql", "-U", "adminuser", "-d", "meinedatenbank",
|
||||
"-c", f"DELETE FROM licenses WHERE customer_id = {customer_id};"
|
||||
], capture_output=True)
|
||||
|
||||
# Try to delete customer again (should work now)
|
||||
response = session.post(f"{base_url}/customer/delete/{customer_id}",
|
||||
verify=False,
|
||||
allow_redirects=False)
|
||||
|
||||
# Verify deletion
|
||||
result = subprocess.run([
|
||||
"docker", "exec", "db", "psql", "-U", "adminuser", "-d", "meinedatenbank", "-t",
|
||||
"-c", f"SELECT COUNT(*) FROM customers WHERE id = {customer_id};"
|
||||
], capture_output=True, text=True)
|
||||
|
||||
if int(result.stdout.strip()) == 0:
|
||||
return "✓ Customer deletion works correctly (protects customers with licenses)"
|
||||
else:
|
||||
return "✗ Failed to delete customer without licenses"
|
||||
|
||||
# Rebuild and restart admin panel
|
||||
print("Rebuilding admin panel with customer management...")
|
||||
subprocess.run(["docker-compose", "build", "admin-panel"], capture_output=True)
|
||||
subprocess.run(["docker-compose", "up", "-d", "admin-panel"], capture_output=True)
|
||||
print("Waiting for container to start...")
|
||||
subprocess.run(["sleep", "5"], capture_output=True)
|
||||
|
||||
print("\nTesting Customer Management Functionality")
|
||||
print("=" * 50)
|
||||
|
||||
# Test customer list
|
||||
print("\n1. Testing Customer List:")
|
||||
print("-" * 30)
|
||||
list_result = test_customer_list()
|
||||
print(list_result)
|
||||
|
||||
# Test edit functionality
|
||||
print("\n2. Testing Customer Edit:")
|
||||
print("-" * 30)
|
||||
edit_result = test_edit_customer()
|
||||
print(edit_result)
|
||||
|
||||
# Verify the edit
|
||||
print("\nVerifying edited customer:")
|
||||
result = subprocess.run([
|
||||
"docker", "exec", "db", "psql", "-U", "adminuser", "-d", "meinedatenbank",
|
||||
"-c", "SELECT name, email FROM customers WHERE name LIKE 'Test Customer%';"
|
||||
], capture_output=True, text=True)
|
||||
print(result.stdout)
|
||||
|
||||
# Test delete functionality
|
||||
print("\n3. Testing Customer Delete:")
|
||||
print("-" * 30)
|
||||
delete_result = test_delete_customer()
|
||||
print(delete_result)
|
||||
|
||||
# Show customer statistics
|
||||
print("\n" + "=" * 50)
|
||||
print("Customer Statistics:")
|
||||
print("-" * 50)
|
||||
result = subprocess.run([
|
||||
"docker", "exec", "db", "psql", "-U", "adminuser", "-d", "meinedatenbank",
|
||||
"-c", """SELECT c.name, COUNT(l.id) as total_licenses,
|
||||
COUNT(CASE WHEN l.is_active = TRUE AND l.valid_until >= CURRENT_DATE THEN 1 END) as active_licenses
|
||||
FROM customers c
|
||||
LEFT JOIN licenses l ON c.id = l.customer_id
|
||||
GROUP BY c.name
|
||||
ORDER BY c.name;"""
|
||||
], capture_output=True, text=True)
|
||||
print(result.stdout)
|
||||
144
v2_testing/test_dashboard.py
Normale Datei
144
v2_testing/test_dashboard.py
Normale Datei
@ -0,0 +1,144 @@
|
||||
#!/usr/bin/env python3
|
||||
import requests
|
||||
import urllib3
|
||||
import subprocess
|
||||
|
||||
# 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 login(session):
|
||||
"""Login to admin panel"""
|
||||
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)
|
||||
return response.status_code == 302
|
||||
|
||||
def test_dashboard():
|
||||
"""Test dashboard with statistics"""
|
||||
session = requests.Session()
|
||||
|
||||
if not login(session):
|
||||
return "✗ Failed to login"
|
||||
|
||||
response = session.get(f"{base_url}/", verify=False)
|
||||
if response.status_code != 200:
|
||||
return f"✗ Failed to access dashboard: Status {response.status_code}"
|
||||
|
||||
content = response.text
|
||||
results = []
|
||||
|
||||
# Check for statistics elements
|
||||
statistics_checks = [
|
||||
("Gesamtkunden", "Total customers statistic"),
|
||||
("Gesamtlizenzen", "Total licenses statistic"),
|
||||
("Aktive Lizenzen", "Active licenses statistic"),
|
||||
("Abgelaufene Lizenzen", "Expired licenses statistic"),
|
||||
("Läuft bald ab", "Expiring soon statistic"),
|
||||
("Letzte Lizenzen", "Recent licenses section"),
|
||||
("Bald ablaufende Lizenzen", "Expiring licenses section")
|
||||
]
|
||||
|
||||
for check_text, description in statistics_checks:
|
||||
if check_text in content:
|
||||
results.append(f"✓ Found: {description}")
|
||||
else:
|
||||
results.append(f"✗ Missing: {description}")
|
||||
|
||||
# Check if actual numbers are displayed
|
||||
if any(char.isdigit() for char in content):
|
||||
results.append("✓ Statistics numbers are displayed")
|
||||
else:
|
||||
results.append("✗ No statistics numbers found")
|
||||
|
||||
# Check for customer names in recent licenses
|
||||
if "Müller" in content or "Schröder" in content or "Köhler" in content:
|
||||
results.append("✓ Recent licenses show customer names")
|
||||
else:
|
||||
results.append("✗ No customer names in recent licenses")
|
||||
|
||||
return results
|
||||
|
||||
# Rebuild and restart admin panel
|
||||
print("Rebuilding admin panel with dashboard...")
|
||||
subprocess.run(["docker-compose", "build", "admin-panel"], capture_output=True)
|
||||
subprocess.run(["docker-compose", "up", "-d", "admin-panel"], capture_output=True)
|
||||
print("Waiting for container to start...")
|
||||
subprocess.run(["sleep", "5"], capture_output=True)
|
||||
|
||||
print("\nTesting Dashboard with Statistics")
|
||||
print("=" * 50)
|
||||
|
||||
results = test_dashboard()
|
||||
for result in results:
|
||||
print(result)
|
||||
|
||||
# Get actual statistics from database for comparison
|
||||
print("\n" + "=" * 50)
|
||||
print("Actual Database Statistics:")
|
||||
print("-" * 50)
|
||||
|
||||
# Total customers
|
||||
result = subprocess.run([
|
||||
"docker", "exec", "db", "psql", "-U", "adminuser", "-d", "meinedatenbank", "-t",
|
||||
"-c", "SELECT COUNT(*) FROM customers;"
|
||||
], capture_output=True, text=True)
|
||||
print(f"Total Customers: {result.stdout.strip()}")
|
||||
|
||||
# Total licenses
|
||||
result = subprocess.run([
|
||||
"docker", "exec", "db", "psql", "-U", "adminuser", "-d", "meinedatenbank", "-t",
|
||||
"-c", "SELECT COUNT(*) FROM licenses;"
|
||||
], capture_output=True, text=True)
|
||||
print(f"Total Licenses: {result.stdout.strip()}")
|
||||
|
||||
# Active licenses
|
||||
result = subprocess.run([
|
||||
"docker", "exec", "db", "psql", "-U", "adminuser", "-d", "meinedatenbank", "-t",
|
||||
"-c", "SELECT COUNT(*) FROM licenses WHERE valid_until >= CURRENT_DATE AND is_active = TRUE;"
|
||||
], capture_output=True, text=True)
|
||||
print(f"Active Licenses: {result.stdout.strip()}")
|
||||
|
||||
# Expired licenses
|
||||
result = subprocess.run([
|
||||
"docker", "exec", "db", "psql", "-U", "adminuser", "-d", "meinedatenbank", "-t",
|
||||
"-c", "SELECT COUNT(*) FROM licenses WHERE valid_until < CURRENT_DATE;"
|
||||
], capture_output=True, text=True)
|
||||
print(f"Expired Licenses: {result.stdout.strip()}")
|
||||
|
||||
# Expiring soon (30 days)
|
||||
result = subprocess.run([
|
||||
"docker", "exec", "db", "psql", "-U", "adminuser", "-d", "meinedatenbank", "-t",
|
||||
"-c", "SELECT COUNT(*) FROM licenses WHERE valid_until >= CURRENT_DATE AND valid_until < CURRENT_DATE + INTERVAL '30 days' AND is_active = TRUE;"
|
||||
], capture_output=True, text=True)
|
||||
print(f"Expiring Soon (30 days): {result.stdout.strip()}")
|
||||
|
||||
# License types breakdown
|
||||
print("\nLicense Types:")
|
||||
result = subprocess.run([
|
||||
"docker", "exec", "db", "psql", "-U", "adminuser", "-d", "meinedatenbank",
|
||||
"-c", "SELECT license_type, COUNT(*) FROM licenses GROUP BY license_type ORDER BY COUNT(*) DESC;"
|
||||
], capture_output=True, text=True)
|
||||
print(result.stdout)
|
||||
|
||||
# Recent licenses
|
||||
print("Recent Licenses:")
|
||||
result = subprocess.run([
|
||||
"docker", "exec", "db", "psql", "-U", "adminuser", "-d", "meinedatenbank",
|
||||
"-c", """SELECT l.license_key, c.name, l.valid_until,
|
||||
CASE
|
||||
WHEN l.valid_until < CURRENT_DATE THEN 'abgelaufen'
|
||||
WHEN l.valid_until < CURRENT_DATE + INTERVAL '30 days' THEN 'läuft bald ab'
|
||||
ELSE 'aktiv'
|
||||
END as status
|
||||
FROM licenses l
|
||||
JOIN customers c ON l.customer_id = c.id
|
||||
ORDER BY l.id DESC
|
||||
LIMIT 5;"""
|
||||
], capture_output=True, text=True)
|
||||
print(result.stdout)
|
||||
53
v2_testing/test_dashboard_detail.py
Normale Datei
53
v2_testing/test_dashboard_detail.py
Normale Datei
@ -0,0 +1,53 @@
|
||||
#!/usr/bin/env python3
|
||||
import requests
|
||||
import urllib3
|
||||
import re
|
||||
|
||||
# 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_dashboard_detail():
|
||||
"""Test dashboard content in detail"""
|
||||
session = requests.Session()
|
||||
|
||||
# Login
|
||||
login_data = {
|
||||
"username": admin_user["username"],
|
||||
"password": admin_user["password"]
|
||||
}
|
||||
session.post(f"{base_url}/login", data=login_data, verify=False, allow_redirects=False)
|
||||
|
||||
# Get dashboard
|
||||
response = session.get(f"{base_url}/", verify=False)
|
||||
content = response.text
|
||||
|
||||
# Extract numbers from content
|
||||
numbers = re.findall(r'\d+', content)
|
||||
print(f"Numbers found on page: {numbers[:20]}") # First 20 numbers
|
||||
|
||||
# Check specific sections
|
||||
if "8" in numbers: # Total customers
|
||||
print("✓ Found total customers count (8)")
|
||||
|
||||
if "5" in numbers: # Total licenses
|
||||
print("✓ Found total licenses count (5)")
|
||||
|
||||
if "3" in numbers: # Active licenses
|
||||
print("✓ Found active licenses count (3)")
|
||||
|
||||
if "2" in numbers: # Expired licenses
|
||||
print("✓ Found expired licenses count (2)")
|
||||
|
||||
# Print a snippet of the HTML to see structure
|
||||
print("\nHTML snippet (first 1000 chars):")
|
||||
print(content[:1000])
|
||||
|
||||
return response.status_code
|
||||
|
||||
print("Detailed Dashboard Test")
|
||||
print("=" * 50)
|
||||
status = test_dashboard_detail()
|
||||
212
v2_testing/test_export.py
Normale Datei
212
v2_testing/test_export.py
Normale Datei
@ -0,0 +1,212 @@
|
||||
#!/usr/bin/env python3
|
||||
import requests
|
||||
import urllib3
|
||||
import subprocess
|
||||
import os
|
||||
import pandas as pd
|
||||
import zipfile
|
||||
|
||||
# Disable SSL warnings
|
||||
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
|
||||
|
||||
base_url = "https://localhost:443"
|
||||
admin_user = {"username": "rac00n", "password": "1248163264"}
|
||||
|
||||
def login(session):
|
||||
"""Login to admin panel"""
|
||||
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)
|
||||
return response.status_code == 302
|
||||
|
||||
def test_export_licenses():
|
||||
"""Test license export functionality"""
|
||||
session = requests.Session()
|
||||
|
||||
if not login(session):
|
||||
return ["✗ Failed to login"]
|
||||
|
||||
results = []
|
||||
|
||||
# Test Excel export
|
||||
print("1. Testing License Excel Export:")
|
||||
print("-" * 40)
|
||||
|
||||
response = session.get(f"{base_url}/export/licenses?format=excel", verify=False)
|
||||
|
||||
if response.status_code == 200:
|
||||
# Save file
|
||||
filename = "test_licenses.xlsx"
|
||||
with open(filename, 'wb') as f:
|
||||
f.write(response.content)
|
||||
|
||||
# Check file size
|
||||
file_size = os.path.getsize(filename)
|
||||
results.append(f"✓ Excel export successful - Size: {file_size} bytes")
|
||||
|
||||
# Verify it's a valid Excel file
|
||||
try:
|
||||
df = pd.read_excel(filename)
|
||||
results.append(f"✓ Valid Excel file with {len(df)} rows, {len(df.columns)} columns")
|
||||
|
||||
# Check columns
|
||||
expected_cols = ['Lizenzschlüssel', 'Kunde', 'E-Mail', 'Typ', 'Status']
|
||||
found_cols = [col for col in expected_cols if col in df.columns]
|
||||
results.append(f"✓ Found columns: {', '.join(found_cols[:3])}...")
|
||||
|
||||
# Check for UTF-8 content
|
||||
if df['Kunde'].str.contains('ü|ö|ä|ß').any():
|
||||
results.append("✓ UTF-8 characters preserved in Excel")
|
||||
except Exception as e:
|
||||
results.append(f"✗ Error reading Excel: {str(e)}")
|
||||
|
||||
os.remove(filename)
|
||||
else:
|
||||
results.append(f"✗ Excel export failed: Status {response.status_code}")
|
||||
|
||||
# Test CSV export
|
||||
print("\n2. Testing License CSV Export:")
|
||||
print("-" * 40)
|
||||
|
||||
response = session.get(f"{base_url}/export/licenses?format=csv", verify=False)
|
||||
|
||||
if response.status_code == 200:
|
||||
# Save file
|
||||
filename = "test_licenses.csv"
|
||||
with open(filename, 'wb') as f:
|
||||
f.write(response.content)
|
||||
|
||||
# Check file
|
||||
file_size = os.path.getsize(filename)
|
||||
results.append(f"✓ CSV export successful - Size: {file_size} bytes")
|
||||
|
||||
# Read and verify CSV
|
||||
try:
|
||||
df = pd.read_csv(filename, sep=';', encoding='utf-8-sig')
|
||||
results.append(f"✓ Valid CSV file with {len(df)} rows")
|
||||
|
||||
# Check for German date format
|
||||
if df['Gültig bis'].str.match(r'\d{2}\.\d{2}\.\d{4}').any():
|
||||
results.append("✓ German date format (DD.MM.YYYY)")
|
||||
except Exception as e:
|
||||
results.append(f"✗ Error reading CSV: {str(e)}")
|
||||
|
||||
os.remove(filename)
|
||||
else:
|
||||
results.append(f"✗ CSV export failed: Status {response.status_code}")
|
||||
|
||||
return results
|
||||
|
||||
def test_export_customers():
|
||||
"""Test customer export functionality"""
|
||||
session = requests.Session()
|
||||
|
||||
if not login(session):
|
||||
return ["✗ Failed to login"]
|
||||
|
||||
results = []
|
||||
|
||||
# Test Excel export
|
||||
print("\n3. Testing Customer Excel Export:")
|
||||
print("-" * 40)
|
||||
|
||||
response = session.get(f"{base_url}/export/customers?format=excel", verify=False)
|
||||
|
||||
if response.status_code == 200:
|
||||
filename = "test_customers.xlsx"
|
||||
with open(filename, 'wb') as f:
|
||||
f.write(response.content)
|
||||
|
||||
try:
|
||||
df = pd.read_excel(filename)
|
||||
results.append(f"✓ Customer Excel export: {len(df)} customers")
|
||||
|
||||
# Check statistics columns
|
||||
if 'Lizenzen gesamt' in df.columns and 'Aktive Lizenzen' in df.columns:
|
||||
results.append("✓ License statistics included")
|
||||
|
||||
# Check for UTF-8
|
||||
if 'Name' in df.columns and df['Name'].str.contains('ü|ö|ä|ß').any():
|
||||
results.append("✓ UTF-8 customer names preserved")
|
||||
|
||||
except Exception as e:
|
||||
results.append(f"✗ Error: {str(e)}")
|
||||
|
||||
os.remove(filename)
|
||||
else:
|
||||
results.append(f"✗ Customer export failed: Status {response.status_code}")
|
||||
|
||||
# Test CSV export
|
||||
print("\n4. Testing Customer CSV Export:")
|
||||
print("-" * 40)
|
||||
|
||||
response = session.get(f"{base_url}/export/customers?format=csv", verify=False)
|
||||
|
||||
if response.status_code == 200:
|
||||
results.append("✓ Customer CSV export successful")
|
||||
else:
|
||||
results.append(f"✗ Customer CSV export failed: Status {response.status_code}")
|
||||
|
||||
return results
|
||||
|
||||
def check_pandas_installation():
|
||||
"""Check if pandas is installed in container"""
|
||||
print("5. Checking pandas installation:")
|
||||
print("-" * 40)
|
||||
|
||||
result = subprocess.run([
|
||||
"docker", "exec", "admin-panel", "python", "-c",
|
||||
"import pandas; import openpyxl; print('pandas version:', pandas.__version__)"
|
||||
], capture_output=True, text=True)
|
||||
|
||||
if result.returncode == 0:
|
||||
print("✓ pandas is installed")
|
||||
print(result.stdout)
|
||||
else:
|
||||
print("✗ pandas not installed - installing...")
|
||||
# Install pandas
|
||||
subprocess.run([
|
||||
"docker", "exec", "admin-panel", "pip", "install",
|
||||
"pandas", "openpyxl"
|
||||
], capture_output=True)
|
||||
print("✓ pandas and openpyxl installed")
|
||||
|
||||
# Main execution
|
||||
print("Testing Export Functionality")
|
||||
print("=" * 50)
|
||||
|
||||
# Check dependencies first
|
||||
check_pandas_installation()
|
||||
|
||||
# Rebuild if needed
|
||||
print("\nRebuilding admin panel...")
|
||||
subprocess.run(["docker-compose", "build", "admin-panel"], capture_output=True)
|
||||
subprocess.run(["docker-compose", "up", "-d", "admin-panel"], capture_output=True)
|
||||
subprocess.run(["sleep", "5"], capture_output=True)
|
||||
|
||||
# Test exports
|
||||
license_results = test_export_licenses()
|
||||
for result in license_results:
|
||||
print(result)
|
||||
|
||||
customer_results = test_export_customers()
|
||||
for result in customer_results:
|
||||
print(result)
|
||||
|
||||
# Check database content for comparison
|
||||
print("\n6. Database Content Summary:")
|
||||
print("-" * 40)
|
||||
|
||||
result = subprocess.run([
|
||||
"docker", "exec", "db", "psql", "-U", "adminuser", "-d", "meinedatenbank",
|
||||
"-c", "SELECT COUNT(*) as licenses FROM licenses;"
|
||||
], capture_output=True, text=True)
|
||||
print(result.stdout)
|
||||
|
||||
result = subprocess.run([
|
||||
"docker", "exec", "db", "psql", "-U", "adminuser", "-d", "meinedatenbank",
|
||||
"-c", "SELECT COUNT(*) as customers FROM customers;"
|
||||
], capture_output=True, text=True)
|
||||
print(result.stdout)
|
||||
158
v2_testing/test_export_simple.py
Normale Datei
158
v2_testing/test_export_simple.py
Normale Datei
@ -0,0 +1,158 @@
|
||||
#!/usr/bin/env python3
|
||||
import requests
|
||||
import urllib3
|
||||
import subprocess
|
||||
import os
|
||||
|
||||
# Disable SSL warnings
|
||||
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
|
||||
|
||||
base_url = "https://localhost:443"
|
||||
admin_user = {"username": "rac00n", "password": "1248163264"}
|
||||
|
||||
def login(session):
|
||||
"""Login to admin panel"""
|
||||
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)
|
||||
return response.status_code == 302
|
||||
|
||||
def check_requirements():
|
||||
"""Check if pandas is in requirements.txt"""
|
||||
print("1. Checking requirements.txt:")
|
||||
print("-" * 40)
|
||||
|
||||
result = subprocess.run([
|
||||
"cat", "/mnt/c/Users/Administrator/Documents/GitHub/v2-Docker/v2_adminpanel/requirements.txt"
|
||||
], capture_output=True, text=True)
|
||||
|
||||
print(result.stdout)
|
||||
|
||||
if "pandas" not in result.stdout:
|
||||
print("✗ pandas not in requirements.txt - adding it")
|
||||
# Add pandas and openpyxl
|
||||
subprocess.run([
|
||||
"echo", "-e", "pandas\\nopenpyxl", ">>",
|
||||
"/mnt/c/Users/Administrator/Documents/GitHub/v2-Docker/v2_adminpanel/requirements.txt"
|
||||
])
|
||||
|
||||
def test_export_endpoints():
|
||||
"""Test export endpoints"""
|
||||
session = requests.Session()
|
||||
|
||||
if not login(session):
|
||||
return ["✗ Failed to login"]
|
||||
|
||||
print("\n2. Testing Export Endpoints:")
|
||||
print("-" * 40)
|
||||
|
||||
# Test license exports
|
||||
exports = [
|
||||
("/export/licenses?format=excel", "License Excel Export"),
|
||||
("/export/licenses?format=csv", "License CSV Export"),
|
||||
("/export/customers?format=excel", "Customer Excel Export"),
|
||||
("/export/customers?format=csv", "Customer CSV Export")
|
||||
]
|
||||
|
||||
for endpoint, description in exports:
|
||||
response = session.get(f"{base_url}{endpoint}", verify=False, stream=True)
|
||||
|
||||
if response.status_code == 200:
|
||||
# Check headers
|
||||
content_type = response.headers.get('Content-Type', '')
|
||||
content_disp = response.headers.get('Content-Disposition', '')
|
||||
|
||||
# Get first few bytes to check file type
|
||||
first_bytes = response.raw.read(10)
|
||||
|
||||
if 'excel' in endpoint and b'PK' in first_bytes: # Excel files start with PK (ZIP format)
|
||||
print(f"✓ {description}: Valid Excel file signature")
|
||||
elif 'csv' in endpoint and (b'ID' in first_bytes or b'"' in first_bytes or b';' in first_bytes):
|
||||
print(f"✓ {description}: Looks like CSV data")
|
||||
else:
|
||||
print(f"✓ {description}: Response received (Status 200)")
|
||||
|
||||
if 'attachment' in content_disp:
|
||||
print(f" → Download filename: {content_disp.split('filename=')[1] if 'filename=' in content_disp else 'present'}")
|
||||
else:
|
||||
print(f"✗ {description}: Failed with status {response.status_code}")
|
||||
|
||||
def test_export_content():
|
||||
"""Test actual export content"""
|
||||
session = requests.Session()
|
||||
|
||||
if not login(session):
|
||||
return
|
||||
|
||||
print("\n3. Testing Export Content:")
|
||||
print("-" * 40)
|
||||
|
||||
# Get CSV export to check content
|
||||
response = session.get(f"{base_url}/export/licenses?format=csv", verify=False)
|
||||
|
||||
if response.status_code == 200:
|
||||
content = response.text
|
||||
lines = content.split('\n')
|
||||
|
||||
print(f"CSV Lines: {len(lines)}")
|
||||
|
||||
if lines:
|
||||
# Check header
|
||||
header = lines[0]
|
||||
print(f"CSV Header: {header[:100]}...")
|
||||
|
||||
# Check for UTF-8 BOM
|
||||
if content.startswith('\ufeff'):
|
||||
print("✓ UTF-8 BOM present (Excel compatibility)")
|
||||
|
||||
# Check for umlauts
|
||||
if any(char in content for char in 'äöüßÄÖÜ'):
|
||||
print("✓ German umlauts found in export")
|
||||
|
||||
# Check separator
|
||||
if ';' in header:
|
||||
print("✓ Using semicolon separator (German Excel standard)")
|
||||
|
||||
# Main execution
|
||||
print("Testing Export Functionality")
|
||||
print("=" * 50)
|
||||
|
||||
# Check and fix requirements
|
||||
check_requirements()
|
||||
|
||||
# Rebuild admin panel with pandas
|
||||
print("\nRebuilding admin panel with pandas...")
|
||||
subprocess.run([
|
||||
"docker", "exec", "admin-panel", "pip", "install", "pandas", "openpyxl"
|
||||
], capture_output=True)
|
||||
|
||||
result = subprocess.run([
|
||||
"docker", "exec", "admin-panel", "python", "-c",
|
||||
"import pandas; print('pandas installed:', pandas.__version__)"
|
||||
], capture_output=True, text=True)
|
||||
|
||||
if result.returncode == 0:
|
||||
print("✓ pandas installed in container")
|
||||
print(result.stdout.strip())
|
||||
else:
|
||||
print("✗ Failed to install pandas")
|
||||
|
||||
# Test endpoints
|
||||
test_export_endpoints()
|
||||
test_export_content()
|
||||
|
||||
# Database summary
|
||||
print("\n4. Database Summary:")
|
||||
print("-" * 40)
|
||||
|
||||
result = subprocess.run([
|
||||
"docker", "exec", "db", "psql", "-U", "adminuser", "-d", "meinedatenbank", "-t",
|
||||
"-c", """SELECT
|
||||
(SELECT COUNT(*) FROM licenses) as licenses,
|
||||
(SELECT COUNT(*) FROM customers) as customers,
|
||||
(SELECT COUNT(*) FROM licenses WHERE valid_until >= CURRENT_DATE) as active_licenses;"""
|
||||
], capture_output=True, text=True)
|
||||
|
||||
print(f"Available for export: {result.stdout.strip()}")
|
||||
95
v2_testing/test_filter_detail.py
Normale Datei
95
v2_testing/test_filter_detail.py
Normale Datei
@ -0,0 +1,95 @@
|
||||
#!/usr/bin/env python3
|
||||
import requests
|
||||
import urllib3
|
||||
import re
|
||||
|
||||
# Disable SSL warnings
|
||||
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
|
||||
|
||||
base_url = "https://localhost:443"
|
||||
admin_user = {"username": "rac00n", "password": "1248163264"}
|
||||
|
||||
def test_detailed():
|
||||
session = requests.Session()
|
||||
|
||||
# Login
|
||||
login_data = {
|
||||
"username": admin_user["username"],
|
||||
"password": admin_user["password"]
|
||||
}
|
||||
session.post(f"{base_url}/login", data=login_data, verify=False, allow_redirects=False)
|
||||
|
||||
print("Testing License Page with Filters:")
|
||||
print("=" * 50)
|
||||
|
||||
# Test 1: Basic license page
|
||||
response = session.get(f"{base_url}/licenses", verify=False)
|
||||
print(f"\n1. Basic licenses page - Status: {response.status_code}")
|
||||
|
||||
# Check for filter dropdowns
|
||||
content = response.text
|
||||
if '<select' in content and 'filter' in content.lower():
|
||||
print("✓ Filter dropdowns found")
|
||||
else:
|
||||
print("✗ No filter dropdowns found")
|
||||
|
||||
# Check for pagination
|
||||
if 'page=' in content or 'Seite' in content:
|
||||
print("✓ Pagination elements found")
|
||||
else:
|
||||
print("✗ No pagination elements")
|
||||
|
||||
# Count licenses shown
|
||||
license_count = content.count('license_key') - 1 # Minus header
|
||||
print(f"Licenses shown: {license_count}")
|
||||
|
||||
# Test 2: With type filter
|
||||
print("\n2. Testing type filter:")
|
||||
response = session.get(f"{base_url}/licenses?type=test", verify=False)
|
||||
print(f"Status: {response.status_code}")
|
||||
content = response.text
|
||||
test_licenses = content.count('PAGE-TEST-')
|
||||
print(f"Test licenses found: {test_licenses}")
|
||||
|
||||
# Test 3: With status filter
|
||||
print("\n3. Testing status filter:")
|
||||
response = session.get(f"{base_url}/licenses?status=active", verify=False)
|
||||
print(f"Status: {response.status_code}")
|
||||
content = response.text
|
||||
active_count = content.count('aktiv') - content.count('inaktiv')
|
||||
print(f"Active status mentions: {active_count}")
|
||||
|
||||
# Test 4: Check pagination info
|
||||
print("\n4. Checking total count display:")
|
||||
# Look for patterns like "X von Y Einträgen" or similar
|
||||
total_pattern = re.findall(r'(\d+)\s*von\s*(\d+)', content)
|
||||
if total_pattern:
|
||||
print(f"✓ Found pagination info: {total_pattern}")
|
||||
else:
|
||||
# Try other patterns
|
||||
if re.search(r'Gesamt.*\d+', content):
|
||||
print("✓ Found total count")
|
||||
elif 'total' in content.lower() and re.search(r'\d+', content):
|
||||
print("✓ Found total indicator")
|
||||
else:
|
||||
print("✗ No total count found")
|
||||
|
||||
# Test 5: Customer page
|
||||
print("\n5. Testing customer page:")
|
||||
response = session.get(f"{base_url}/customers", verify=False)
|
||||
print(f"Status: {response.status_code}")
|
||||
content = response.text
|
||||
customer_count = content.count('customer_name') + content.count('<tr') - 2
|
||||
print(f"Customers shown: ~{customer_count}")
|
||||
|
||||
# Print a snippet to see actual content
|
||||
print("\n6. HTML snippet from licenses page:")
|
||||
print("-" * 30)
|
||||
# Find filter section
|
||||
filter_start = content.find('filter')
|
||||
if filter_start > 0:
|
||||
print(content[max(0, filter_start-100):filter_start+200])
|
||||
else:
|
||||
print("No filter section found in HTML")
|
||||
|
||||
test_detailed()
|
||||
222
v2_testing/test_filter_pagination.py
Normale Datei
222
v2_testing/test_filter_pagination.py
Normale Datei
@ -0,0 +1,222 @@
|
||||
#!/usr/bin/env python3
|
||||
import requests
|
||||
import urllib3
|
||||
import subprocess
|
||||
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 login(session):
|
||||
"""Login to admin panel"""
|
||||
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)
|
||||
return response.status_code == 302
|
||||
|
||||
def create_test_data():
|
||||
"""Create additional test data for pagination testing"""
|
||||
session = requests.Session()
|
||||
if not login(session):
|
||||
return False
|
||||
|
||||
# Create 25 test licenses to test pagination (20 per page)
|
||||
for i in range(25):
|
||||
license_data = {
|
||||
"customer_name": f"Pagination Test {i+1}",
|
||||
"email": f"page{i+1}@test.de",
|
||||
"license_key": f"PAGE-TEST-{i+1:03d}",
|
||||
"license_type": "test" if i % 3 == 0 else "full",
|
||||
"valid_from": "2025-01-01",
|
||||
"valid_until": (datetime.now() + timedelta(days=i*10)).strftime("%Y-%m-%d") if i % 2 == 0 else "2024-12-31"
|
||||
}
|
||||
session.post(f"{base_url}/create", data=license_data, verify=False, allow_redirects=False)
|
||||
|
||||
return True
|
||||
|
||||
def test_license_filters():
|
||||
"""Test license filtering functionality"""
|
||||
session = requests.Session()
|
||||
|
||||
if not login(session):
|
||||
return ["✗ Failed to login"]
|
||||
|
||||
results = []
|
||||
|
||||
# Test type filters
|
||||
filter_tests = [
|
||||
("type=test", "Filter by type 'test'"),
|
||||
("type=full", "Filter by type 'full'"),
|
||||
("status=active", "Filter by active status"),
|
||||
("status=expired", "Filter by expired status"),
|
||||
("status=expiring", "Filter by expiring soon"),
|
||||
("type=test&status=active", "Combined filter: test + active"),
|
||||
("search=page&type=test", "Search + type filter"),
|
||||
("search=müller&status=active", "Search with umlaut + status filter")
|
||||
]
|
||||
|
||||
for filter_param, description in filter_tests:
|
||||
response = session.get(f"{base_url}/licenses?{filter_param}", verify=False)
|
||||
|
||||
if response.status_code == 200:
|
||||
content = response.text
|
||||
# Check if results are shown (not "Keine Lizenzen gefunden")
|
||||
if "license_key" in content or "Keine Lizenzen gefunden" in content:
|
||||
results.append(f"✓ {description}: Filter applied successfully")
|
||||
else:
|
||||
results.append(f"✗ {description}: No results section found")
|
||||
else:
|
||||
results.append(f"✗ {description}: Failed with status {response.status_code}")
|
||||
|
||||
return results
|
||||
|
||||
def test_pagination():
|
||||
"""Test pagination functionality"""
|
||||
session = requests.Session()
|
||||
|
||||
if not login(session):
|
||||
return ["✗ Failed to login"]
|
||||
|
||||
results = []
|
||||
|
||||
# Test licenses pagination
|
||||
response = session.get(f"{base_url}/licenses", verify=False)
|
||||
if response.status_code == 200:
|
||||
content = response.text
|
||||
|
||||
# Check for pagination elements
|
||||
if "page=" in content:
|
||||
results.append("✓ Pagination links present in licenses")
|
||||
else:
|
||||
results.append("✗ No pagination links in licenses")
|
||||
|
||||
# Check page 2
|
||||
response2 = session.get(f"{base_url}/licenses?page=2", verify=False)
|
||||
if response2.status_code == 200:
|
||||
content2 = response2.text
|
||||
if content != content2: # Different content on different pages
|
||||
results.append("✓ Page 2 shows different content")
|
||||
else:
|
||||
results.append("✗ Page 2 shows same content as page 1")
|
||||
|
||||
# Check for total count display
|
||||
if "von" in content and "Einträgen" in content:
|
||||
results.append("✓ Total entries count displayed")
|
||||
else:
|
||||
results.append("✗ Total entries count not displayed")
|
||||
|
||||
# Test customers pagination
|
||||
response = session.get(f"{base_url}/customers", verify=False)
|
||||
if response.status_code == 200:
|
||||
content = response.text
|
||||
if "page=" in content or "Seite" in content:
|
||||
results.append("✓ Pagination present in customers")
|
||||
else:
|
||||
results.append("✗ No pagination in customers")
|
||||
|
||||
return results
|
||||
|
||||
def test_pagination_with_filters():
|
||||
"""Test pagination combined with filters"""
|
||||
session = requests.Session()
|
||||
|
||||
if not login(session):
|
||||
return ["✗ Failed to login"]
|
||||
|
||||
results = []
|
||||
|
||||
# Test pagination preserves filters
|
||||
test_urls = [
|
||||
(f"{base_url}/licenses?type=test&page=2", "Pagination with type filter"),
|
||||
(f"{base_url}/licenses?search=page&page=2", "Pagination with search"),
|
||||
(f"{base_url}/licenses?status=active&type=full&page=1", "Multiple filters with pagination"),
|
||||
(f"{base_url}/customers?search=test&page=2", "Customer search with pagination")
|
||||
]
|
||||
|
||||
for test_url, description in test_urls:
|
||||
response = session.get(test_url, verify=False)
|
||||
if response.status_code == 200:
|
||||
content = response.text
|
||||
# Check if filters are preserved in pagination links
|
||||
if "type=" in test_url and "type=" in content:
|
||||
results.append(f"✓ {description}: Filters preserved")
|
||||
elif "search=" in test_url and "search=" in content:
|
||||
results.append(f"✓ {description}: Search preserved")
|
||||
else:
|
||||
results.append(f"✓ {description}: Page loaded")
|
||||
else:
|
||||
results.append(f"✗ {description}: Failed")
|
||||
|
||||
return results
|
||||
|
||||
# Setup
|
||||
print("Setting up test environment...")
|
||||
subprocess.run(["docker-compose", "build", "admin-panel"], capture_output=True)
|
||||
subprocess.run(["docker-compose", "up", "-d", "admin-panel"], capture_output=True)
|
||||
subprocess.run(["sleep", "5"], capture_output=True)
|
||||
|
||||
print("\nCreating test data for pagination...")
|
||||
if create_test_data():
|
||||
print("✓ Test data created")
|
||||
else:
|
||||
print("✗ Failed to create test data")
|
||||
|
||||
print("\nTesting Filter and Pagination Functionality")
|
||||
print("=" * 50)
|
||||
|
||||
# Test filters
|
||||
print("\n1. License Filter Tests:")
|
||||
print("-" * 30)
|
||||
filter_results = test_license_filters()
|
||||
for result in filter_results:
|
||||
print(result)
|
||||
|
||||
# Test pagination
|
||||
print("\n2. Pagination Tests:")
|
||||
print("-" * 30)
|
||||
pagination_results = test_pagination()
|
||||
for result in pagination_results:
|
||||
print(result)
|
||||
|
||||
# Test combined
|
||||
print("\n3. Combined Filter + Pagination Tests:")
|
||||
print("-" * 30)
|
||||
combined_results = test_pagination_with_filters()
|
||||
for result in combined_results:
|
||||
print(result)
|
||||
|
||||
# Database statistics
|
||||
print("\n" + "=" * 50)
|
||||
print("Database Statistics after Tests:")
|
||||
print("-" * 50)
|
||||
|
||||
# License type distribution
|
||||
result = subprocess.run([
|
||||
"docker", "exec", "db", "psql", "-U", "adminuser", "-d", "meinedatenbank",
|
||||
"-c", "SELECT license_type, COUNT(*) FROM licenses GROUP BY license_type ORDER BY COUNT(*) DESC;"
|
||||
], capture_output=True, text=True)
|
||||
print("License Types:")
|
||||
print(result.stdout)
|
||||
|
||||
# Status distribution
|
||||
result = subprocess.run([
|
||||
"docker", "exec", "db", "psql", "-U", "adminuser", "-d", "meinedatenbank",
|
||||
"-c", """SELECT
|
||||
CASE
|
||||
WHEN valid_until < CURRENT_DATE THEN 'expired'
|
||||
WHEN valid_until < CURRENT_DATE + INTERVAL '30 days' THEN 'expiring'
|
||||
ELSE 'active'
|
||||
END as status,
|
||||
COUNT(*)
|
||||
FROM licenses
|
||||
GROUP BY status
|
||||
ORDER BY COUNT(*) DESC;"""
|
||||
], capture_output=True, text=True)
|
||||
print("License Status:")
|
||||
print(result.stdout)
|
||||
57
v2_testing/test_license_creation.py
Normale Datei
57
v2_testing/test_license_creation.py
Normale Datei
@ -0,0 +1,57 @@
|
||||
#!/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_license_creation():
|
||||
"""Test creating a license through the admin panel"""
|
||||
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 a test license
|
||||
license_data = {
|
||||
"customer_name": "Test Customer",
|
||||
"email": "test@example.com",
|
||||
"license_key": "TEST-LICENSE-KEY-123",
|
||||
"license_type": "premium",
|
||||
"valid_from": datetime.now().strftime("%Y-%m-%d"),
|
||||
"valid_until": (datetime.now() + timedelta(days=365)).strftime("%Y-%m-%d")
|
||||
}
|
||||
|
||||
response = session.post(f"{base_url}/", data=license_data, verify=False, allow_redirects=False)
|
||||
|
||||
if response.status_code == 302 and response.headers.get('Location') == '/':
|
||||
return "✓ License created successfully"
|
||||
else:
|
||||
return f"✗ Failed to create license: {response.status_code}"
|
||||
|
||||
print("Testing License Creation")
|
||||
print("=" * 40)
|
||||
result = test_license_creation()
|
||||
print(result)
|
||||
|
||||
# Verify the license was created in the database
|
||||
import subprocess
|
||||
result = subprocess.run([
|
||||
"docker", "exec", "db", "psql", "-U", "adminuser", "-d", "meinedatenbank",
|
||||
"-c", "SELECT c.name, l.license_key, l.license_type, l.valid_from, l.valid_until FROM licenses l JOIN customers c ON l.customer_id = c.id;"
|
||||
], capture_output=True, text=True)
|
||||
|
||||
print("\nLicenses in database:")
|
||||
print(result.stdout)
|
||||
150
v2_testing/test_license_edit_delete.py
Normale Datei
150
v2_testing/test_license_edit_delete.py
Normale Datei
@ -0,0 +1,150 @@
|
||||
#!/usr/bin/env python3
|
||||
import requests
|
||||
import urllib3
|
||||
from datetime import datetime, timedelta
|
||||
import subprocess
|
||||
|
||||
# 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 login(session):
|
||||
"""Login to admin panel"""
|
||||
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)
|
||||
return response.status_code == 302
|
||||
|
||||
def test_edit_license():
|
||||
"""Test editing a license"""
|
||||
session = requests.Session()
|
||||
|
||||
if not login(session):
|
||||
return "✗ Failed to login"
|
||||
|
||||
# First, get a license ID to edit (let's edit license ID 5 - "Bli-bla-blub")
|
||||
license_id = 5
|
||||
|
||||
# Test GET edit page
|
||||
response = session.get(f"{base_url}/license/edit/{license_id}", verify=False)
|
||||
if response.status_code != 200:
|
||||
return f"✗ Failed to access edit page: Status {response.status_code}"
|
||||
|
||||
# Check if edit form is displayed
|
||||
if "Bli-bla-blub" not in response.text:
|
||||
return "✗ Edit page doesn't show current license data"
|
||||
|
||||
# Test POST edit with new data
|
||||
new_license_data = {
|
||||
"license_key": "UPDATED-KEY-2025",
|
||||
"license_type": "Enterprise-Lösung",
|
||||
"valid_from": "2025-01-01",
|
||||
"valid_until": "2025-12-31",
|
||||
"is_active": "on"
|
||||
}
|
||||
|
||||
response = session.post(f"{base_url}/license/edit/{license_id}",
|
||||
data=new_license_data,
|
||||
verify=False,
|
||||
allow_redirects=False)
|
||||
|
||||
if response.status_code == 302 and response.headers.get('Location') == '/licenses':
|
||||
return "✓ License edited successfully"
|
||||
else:
|
||||
return f"✗ Failed to edit license: Status {response.status_code}"
|
||||
|
||||
def test_delete_license():
|
||||
"""Test deleting a license"""
|
||||
session = requests.Session()
|
||||
|
||||
if not login(session):
|
||||
return "✗ Failed to login"
|
||||
|
||||
# Create a test license to delete
|
||||
test_license = {
|
||||
"customer_name": "Delete Test Company",
|
||||
"email": "delete@test.com",
|
||||
"license_key": "DELETE-TEST-KEY",
|
||||
"license_type": "Test",
|
||||
"valid_from": datetime.now().strftime("%Y-%m-%d"),
|
||||
"valid_until": (datetime.now() + timedelta(days=30)).strftime("%Y-%m-%d")
|
||||
}
|
||||
|
||||
# Create the license
|
||||
response = session.post(f"{base_url}/", data=test_license, verify=False, allow_redirects=False)
|
||||
if response.status_code != 302:
|
||||
return "✗ Failed to create test license for deletion"
|
||||
|
||||
# Get the ID of the newly created license
|
||||
result = subprocess.run([
|
||||
"docker", "exec", "db", "psql", "-U", "adminuser", "-d", "meinedatenbank", "-t",
|
||||
"-c", "SELECT id FROM licenses WHERE license_key = 'DELETE-TEST-KEY';"
|
||||
], capture_output=True, text=True)
|
||||
|
||||
license_id = result.stdout.strip()
|
||||
if not license_id:
|
||||
return "✗ Failed to find test license ID"
|
||||
|
||||
# Delete the license
|
||||
response = session.post(f"{base_url}/license/delete/{license_id}",
|
||||
verify=False,
|
||||
allow_redirects=False)
|
||||
|
||||
if response.status_code == 302 and response.headers.get('Location') == '/licenses':
|
||||
# Verify it's really deleted
|
||||
result = subprocess.run([
|
||||
"docker", "exec", "db", "psql", "-U", "adminuser", "-d", "meinedatenbank", "-t",
|
||||
"-c", f"SELECT COUNT(*) FROM licenses WHERE id = {license_id};"
|
||||
], capture_output=True, text=True)
|
||||
|
||||
count = int(result.stdout.strip())
|
||||
if count == 0:
|
||||
return "✓ License deleted successfully"
|
||||
else:
|
||||
return "✗ License still exists in database"
|
||||
else:
|
||||
return f"✗ Failed to delete license: Status {response.status_code}"
|
||||
|
||||
# Rebuild and restart admin panel
|
||||
print("Rebuilding admin panel with new features...")
|
||||
subprocess.run(["docker-compose", "build", "admin-panel"], capture_output=True)
|
||||
subprocess.run(["docker-compose", "up", "-d", "admin-panel"], capture_output=True)
|
||||
subprocess.run(["sleep", "5"], capture_output=True)
|
||||
|
||||
print("\nTesting License Edit/Delete Functionality")
|
||||
print("=" * 50)
|
||||
|
||||
# Test edit functionality
|
||||
print("\n1. Testing License Edit:")
|
||||
print("-" * 30)
|
||||
edit_result = test_edit_license()
|
||||
print(edit_result)
|
||||
|
||||
# Verify the edit worked
|
||||
print("\nVerifying edited license in database:")
|
||||
result = subprocess.run([
|
||||
"docker", "exec", "db", "psql", "-U", "adminuser", "-d", "meinedatenbank",
|
||||
"-c", "SELECT license_key, license_type, valid_from, valid_until, is_active FROM licenses WHERE license_key = 'UPDATED-KEY-2025';"
|
||||
], capture_output=True, text=True)
|
||||
print(result.stdout)
|
||||
|
||||
# Test delete functionality
|
||||
print("\n2. Testing License Delete:")
|
||||
print("-" * 30)
|
||||
delete_result = test_delete_license()
|
||||
print(delete_result)
|
||||
|
||||
# Show current licenses
|
||||
print("\n" + "=" * 50)
|
||||
print("Current licenses in database:")
|
||||
print("-" * 50)
|
||||
result = subprocess.run([
|
||||
"docker", "exec", "db", "psql", "-U", "adminuser", "-d", "meinedatenbank",
|
||||
"-c", "SELECT l.id, l.license_key, c.name, l.license_type FROM licenses l JOIN customers c ON l.customer_id = c.id ORDER BY l.id;"
|
||||
], capture_output=True, text=True)
|
||||
print(result.stdout)
|
||||
104
v2_testing/test_license_overview.py
Normale Datei
104
v2_testing/test_license_overview.py
Normale Datei
@ -0,0 +1,104 @@
|
||||
#!/usr/bin/env python3
|
||||
import requests
|
||||
import urllib3
|
||||
|
||||
# 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_license_overview():
|
||||
"""Test the new license overview page"""
|
||||
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"
|
||||
|
||||
# Access the licenses page
|
||||
response = session.get(f"{base_url}/licenses", verify=False)
|
||||
|
||||
if response.status_code == 200:
|
||||
content = response.text
|
||||
|
||||
# Check if we have the expected licenses
|
||||
test_results = []
|
||||
|
||||
# Check for previously created licenses
|
||||
if "Müller GmbH & Co. KG" in content:
|
||||
test_results.append("✓ Found: Müller GmbH & Co. KG")
|
||||
else:
|
||||
test_results.append("✗ Missing: Müller GmbH & Co. KG")
|
||||
|
||||
if "Schröder Süßwaren AG" in content:
|
||||
test_results.append("✓ Found: Schröder Süßwaren AG")
|
||||
else:
|
||||
test_results.append("✗ Missing: Schröder Süßwaren AG")
|
||||
|
||||
if "Björn Köhler Einzelunternehmen" in content:
|
||||
test_results.append("✓ Found: Björn Köhler Einzelunternehmen")
|
||||
else:
|
||||
test_results.append("✗ Missing: Björn Köhler Einzelunternehmen")
|
||||
|
||||
# Check for license status indicators
|
||||
if "aktiv" in content or "abgelaufen" in content or "läuft bald ab" in content:
|
||||
test_results.append("✓ Status indicators found")
|
||||
else:
|
||||
test_results.append("✗ No status indicators found")
|
||||
|
||||
# Check for UTF-8 characters
|
||||
if "ä" in content or "ö" in content or "ü" in content or "ß" in content:
|
||||
test_results.append("✓ UTF-8 characters displayed correctly")
|
||||
else:
|
||||
test_results.append("✗ No UTF-8 characters found")
|
||||
|
||||
return test_results, response.status_code
|
||||
else:
|
||||
return [f"✗ Failed to access licenses page: Status {response.status_code}"], response.status_code
|
||||
|
||||
print("Testing License Overview Page")
|
||||
print("=" * 50)
|
||||
|
||||
# First restart admin panel to get the new code
|
||||
print("Restarting admin panel container...")
|
||||
import subprocess
|
||||
subprocess.run(["docker", "restart", "admin-panel"], capture_output=True)
|
||||
print("Waiting for container to start...")
|
||||
subprocess.run(["sleep", "5"], capture_output=True)
|
||||
|
||||
results, status_code = test_license_overview()
|
||||
|
||||
print(f"\nAccessing /licenses endpoint - Status Code: {status_code}")
|
||||
print("-" * 50)
|
||||
|
||||
for result in results:
|
||||
print(result)
|
||||
|
||||
print("\n" + "=" * 50)
|
||||
print("Database content check:")
|
||||
print("-" * 50)
|
||||
|
||||
# Check what's actually in the database
|
||||
result = subprocess.run([
|
||||
"docker", "exec", "db", "psql", "-U", "adminuser", "-d", "meinedatenbank",
|
||||
"-c", """SELECT l.id, l.license_key, c.name, l.license_type,
|
||||
l.valid_until,
|
||||
CASE
|
||||
WHEN l.valid_until < CURRENT_DATE THEN 'abgelaufen'
|
||||
WHEN l.valid_until < CURRENT_DATE + INTERVAL '30 days' THEN 'läuft bald ab'
|
||||
ELSE 'aktiv'
|
||||
END as status
|
||||
FROM licenses l
|
||||
JOIN customers c ON l.customer_id = c.id
|
||||
ORDER BY l.id DESC LIMIT 5;"""
|
||||
], capture_output=True, text=True)
|
||||
|
||||
print(result.stdout)
|
||||
156
v2_testing/test_search.py
Normale Datei
156
v2_testing/test_search.py
Normale Datei
@ -0,0 +1,156 @@
|
||||
#!/usr/bin/env python3
|
||||
import requests
|
||||
import urllib3
|
||||
import subprocess
|
||||
|
||||
# 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 login(session):
|
||||
"""Login to admin panel"""
|
||||
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)
|
||||
return response.status_code == 302
|
||||
|
||||
def test_license_search():
|
||||
"""Test license search functionality"""
|
||||
session = requests.Session()
|
||||
|
||||
if not login(session):
|
||||
return "✗ Failed to login"
|
||||
|
||||
test_cases = [
|
||||
# (search_term, expected_results, description)
|
||||
("müller", ["Müller GmbH & Co. KG"], "Search by customer name with umlaut"),
|
||||
("KÖHLER", ["Björn Köhler"], "Search by license key (case insensitive)"),
|
||||
("@übersetzungen.de", ["Björn Köhler"], "Search by email domain with umlaut"),
|
||||
("2025", ["KÖHLER-2025", "MÜLLER-2025", "SCHRÖDER-2025"], "Search by year in license key"),
|
||||
("premium", ["TEST-LICENSE-KEY"], "Search by license type"),
|
||||
("süßwaren", ["Schröder Süßwaren"], "Search with special characters"),
|
||||
("xyz123", [], "Search with no results")
|
||||
]
|
||||
|
||||
results = []
|
||||
|
||||
for search_term, expected, description in test_cases:
|
||||
response = session.get(f"{base_url}/licenses?search={search_term}", verify=False)
|
||||
|
||||
if response.status_code != 200:
|
||||
results.append(f"✗ {description}: Failed with status {response.status_code}")
|
||||
continue
|
||||
|
||||
content = response.text
|
||||
found = []
|
||||
|
||||
for expected_item in expected:
|
||||
if expected_item.lower() in content.lower():
|
||||
found.append(expected_item)
|
||||
|
||||
if len(found) == len(expected) and len(expected) > 0:
|
||||
results.append(f"✓ {description}: Found {len(found)} result(s)")
|
||||
elif len(expected) == 0 and "Keine Lizenzen gefunden" in content:
|
||||
results.append(f"✓ {description}: Correctly shows no results")
|
||||
else:
|
||||
results.append(f"✗ {description}: Expected {len(expected)}, found {len(found)}")
|
||||
|
||||
return results
|
||||
|
||||
def test_customer_search():
|
||||
"""Test customer search functionality"""
|
||||
session = requests.Session()
|
||||
|
||||
if not login(session):
|
||||
return "✗ Failed to login"
|
||||
|
||||
test_cases = [
|
||||
# (search_term, expected_results, description)
|
||||
("gmbh", ["Müller GmbH", "Schröder", "Test Customer GmbH", "Löschtest"], "Search for GmbH companies"),
|
||||
("björn", ["Björn Köhler"], "Search by first name with umlaut"),
|
||||
("@müller", ["Müller GmbH & Co. KG"], "Search by email with umlaut"),
|
||||
("test", ["Test Customer", "Testfirma", "Löschtest"], "Search for test entries"),
|
||||
("überprüfung", ["Testfirma für Umlaute"], "Search with umlaut in term"),
|
||||
("nonexistent", [], "Search with no results")
|
||||
]
|
||||
|
||||
results = []
|
||||
|
||||
for search_term, expected, description in test_cases:
|
||||
response = session.get(f"{base_url}/customers?search={search_term}", verify=False)
|
||||
|
||||
if response.status_code != 200:
|
||||
results.append(f"✗ {description}: Failed with status {response.status_code}")
|
||||
continue
|
||||
|
||||
content = response.text
|
||||
found = []
|
||||
|
||||
for expected_item in expected:
|
||||
if expected_item.lower() in content.lower():
|
||||
found.append(expected_item)
|
||||
|
||||
if len(found) >= len(expected) * 0.7: # Allow 70% match rate due to variations
|
||||
results.append(f"✓ {description}: Found {len(found)} result(s)")
|
||||
else:
|
||||
results.append(f"✗ {description}: Expected ~{len(expected)}, found {len(found)}")
|
||||
|
||||
return results
|
||||
|
||||
# Rebuild and restart admin panel
|
||||
print("Rebuilding admin panel with search functionality...")
|
||||
subprocess.run(["docker-compose", "build", "admin-panel"], capture_output=True)
|
||||
subprocess.run(["docker-compose", "up", "-d", "admin-panel"], capture_output=True)
|
||||
print("Waiting for container to start...")
|
||||
subprocess.run(["sleep", "5"], capture_output=True)
|
||||
|
||||
print("\nTesting Search Functionality")
|
||||
print("=" * 50)
|
||||
|
||||
# Test license search
|
||||
print("\n1. License Search Tests:")
|
||||
print("-" * 30)
|
||||
license_results = test_license_search()
|
||||
for result in license_results:
|
||||
print(result)
|
||||
|
||||
# Test customer search
|
||||
print("\n2. Customer Search Tests:")
|
||||
print("-" * 30)
|
||||
customer_results = test_customer_search()
|
||||
for result in customer_results:
|
||||
print(result)
|
||||
|
||||
# Show some example search results from database
|
||||
print("\n" + "=" * 50)
|
||||
print("Database Search Examples:")
|
||||
print("-" * 50)
|
||||
|
||||
# Example: Search for "müller" in licenses
|
||||
print("\nSearching for 'müller' in licenses:")
|
||||
result = subprocess.run([
|
||||
"docker", "exec", "db", "psql", "-U", "adminuser", "-d", "meinedatenbank",
|
||||
"-c", """SELECT l.license_key, c.name, c.email
|
||||
FROM licenses l
|
||||
JOIN customers c ON l.customer_id = c.id
|
||||
WHERE LOWER(c.name) LIKE LOWER('%müller%')
|
||||
OR LOWER(l.license_key) LIKE LOWER('%müller%')
|
||||
OR LOWER(c.email) LIKE LOWER('%müller%');"""
|
||||
], capture_output=True, text=True)
|
||||
print(result.stdout)
|
||||
|
||||
# Example: Search for customers with "test"
|
||||
print("Searching for 'test' in customers:")
|
||||
result = subprocess.run([
|
||||
"docker", "exec", "db", "psql", "-U", "adminuser", "-d", "meinedatenbank",
|
||||
"-c", """SELECT name, email
|
||||
FROM customers
|
||||
WHERE LOWER(name) LIKE LOWER('%test%')
|
||||
OR LOWER(email) LIKE LOWER('%test%');"""
|
||||
], capture_output=True, text=True)
|
||||
print(result.stdout)
|
||||
194
v2_testing/test_sessions.py
Normale Datei
194
v2_testing/test_sessions.py
Normale Datei
@ -0,0 +1,194 @@
|
||||
#!/usr/bin/env python3
|
||||
import requests
|
||||
import urllib3
|
||||
import subprocess
|
||||
from datetime import datetime
|
||||
|
||||
# Disable SSL warnings
|
||||
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
|
||||
|
||||
base_url = "https://localhost:443"
|
||||
admin_user = {"username": "rac00n", "password": "1248163264"}
|
||||
|
||||
def login(session):
|
||||
"""Login to admin panel"""
|
||||
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)
|
||||
return response.status_code == 302
|
||||
|
||||
def test_session_table():
|
||||
"""Test if session table exists and structure"""
|
||||
print("1. Checking Session Table Structure:")
|
||||
print("-" * 40)
|
||||
|
||||
result = subprocess.run([
|
||||
"docker", "exec", "db", "psql", "-U", "adminuser", "-d", "meinedatenbank",
|
||||
"-c", "\\d sessions"
|
||||
], capture_output=True, text=True)
|
||||
|
||||
if "Table \"public.sessions\"" in result.stdout:
|
||||
print("✓ Sessions table exists")
|
||||
print("\nTable structure:")
|
||||
print(result.stdout)
|
||||
else:
|
||||
print("✗ Sessions table not found")
|
||||
return False
|
||||
|
||||
# Check if table is empty
|
||||
result = subprocess.run([
|
||||
"docker", "exec", "db", "psql", "-U", "adminuser", "-d", "meinedatenbank", "-t",
|
||||
"-c", "SELECT COUNT(*) FROM sessions;"
|
||||
], capture_output=True, text=True)
|
||||
|
||||
count = int(result.stdout.strip())
|
||||
print(f"\nCurrent session count: {count}")
|
||||
if count == 0:
|
||||
print("✓ Session table is empty (as expected - License Server not implemented)")
|
||||
|
||||
return True
|
||||
|
||||
def test_session_page():
|
||||
"""Test the sessions management page"""
|
||||
session = requests.Session()
|
||||
|
||||
if not login(session):
|
||||
return "✗ Failed to login"
|
||||
|
||||
print("\n2. Testing Sessions Page:")
|
||||
print("-" * 40)
|
||||
|
||||
response = session.get(f"{base_url}/sessions", verify=False)
|
||||
|
||||
if response.status_code == 200:
|
||||
print("✓ Sessions page accessible")
|
||||
|
||||
content = response.text
|
||||
|
||||
# Check for expected elements
|
||||
checks = [
|
||||
("Aktive Sessions", "Active sessions section"),
|
||||
("Letzte Sessions", "Recent sessions section"),
|
||||
("IP-Adresse", "IP address column"),
|
||||
("User Agent", "User agent column"),
|
||||
("Heartbeat", "Heartbeat info"),
|
||||
("Session beenden", "End session button")
|
||||
]
|
||||
|
||||
for check_text, description in checks:
|
||||
if check_text in content:
|
||||
print(f"✓ Found: {description}")
|
||||
else:
|
||||
print(f"✗ Missing: {description}")
|
||||
|
||||
# Check for empty state
|
||||
if "Keine aktiven Sessions" in content:
|
||||
print("✓ Shows empty state for active sessions")
|
||||
|
||||
else:
|
||||
print(f"✗ Failed to access sessions page: Status {response.status_code}")
|
||||
|
||||
def test_dashboard_session_count():
|
||||
"""Test if dashboard shows session count"""
|
||||
session = requests.Session()
|
||||
|
||||
if not login(session):
|
||||
return "✗ Failed to login"
|
||||
|
||||
print("\n3. Testing Dashboard Session Counter:")
|
||||
print("-" * 40)
|
||||
|
||||
response = session.get(f"{base_url}/", verify=False)
|
||||
|
||||
if response.status_code == 200:
|
||||
content = response.text
|
||||
|
||||
if "Aktive Sessions" in content or "sessions" in content.lower():
|
||||
print("✓ Dashboard shows session information")
|
||||
|
||||
# Check if it shows 0
|
||||
if "0" in content:
|
||||
print("✓ Shows 0 active sessions (correct)")
|
||||
else:
|
||||
print("✗ No session information on dashboard")
|
||||
|
||||
def simulate_session_data():
|
||||
"""Add test session data directly to database"""
|
||||
print("\n4. Simulating Session Data:")
|
||||
print("-" * 40)
|
||||
|
||||
# Get a license ID
|
||||
result = subprocess.run([
|
||||
"docker", "exec", "db", "psql", "-U", "adminuser", "-d", "meinedatenbank", "-t",
|
||||
"-c", "SELECT id FROM licenses WHERE is_active = TRUE LIMIT 1;"
|
||||
], capture_output=True, text=True)
|
||||
|
||||
license_id = result.stdout.strip()
|
||||
if not license_id:
|
||||
print("✗ No active license found for test")
|
||||
return
|
||||
|
||||
# Insert test sessions
|
||||
test_sessions = [
|
||||
# Active session
|
||||
f"""INSERT INTO sessions (license_id, session_id, ip_address, user_agent, is_active)
|
||||
VALUES ({license_id}, 'TEST-SESSION-001', '192.168.1.100',
|
||||
'Mozilla/5.0 Test Browser', TRUE);""",
|
||||
|
||||
# Inactive session from today
|
||||
f"""INSERT INTO sessions (license_id, session_id, ip_address, user_agent,
|
||||
started_at, ended_at, is_active)
|
||||
VALUES ({license_id}, 'TEST-SESSION-002', '10.0.0.50',
|
||||
'Chrome/120.0 Windows',
|
||||
NOW() - INTERVAL '2 hours', NOW() - INTERVAL '1 hour', FALSE);"""
|
||||
]
|
||||
|
||||
for sql in test_sessions:
|
||||
result = subprocess.run([
|
||||
"docker", "exec", "db", "psql", "-U", "adminuser", "-d", "meinedatenbank",
|
||||
"-c", sql
|
||||
], capture_output=True, text=True)
|
||||
|
||||
if "INSERT" in result.stdout:
|
||||
print("✓ Test session inserted")
|
||||
else:
|
||||
print("✗ Failed to insert test session")
|
||||
|
||||
# Verify
|
||||
result = subprocess.run([
|
||||
"docker", "exec", "db", "psql", "-U", "adminuser", "-d", "meinedatenbank",
|
||||
"-c", "SELECT COUNT(*) as total, COUNT(CASE WHEN is_active THEN 1 END) as active FROM sessions;"
|
||||
], capture_output=True, text=True)
|
||||
print("\nSession count after simulation:")
|
||||
print(result.stdout)
|
||||
|
||||
# Main execution
|
||||
print("Testing Session Management Features")
|
||||
print("=" * 50)
|
||||
|
||||
# Rebuild admin panel
|
||||
print("Rebuilding admin panel with session features...")
|
||||
subprocess.run(["docker-compose", "build", "admin-panel"], capture_output=True)
|
||||
subprocess.run(["docker-compose", "up", "-d"], capture_output=True)
|
||||
subprocess.run(["sleep", "5"], capture_output=True)
|
||||
|
||||
# Run tests
|
||||
test_session_table()
|
||||
test_session_page()
|
||||
test_dashboard_session_count()
|
||||
simulate_session_data()
|
||||
|
||||
# Test again with data
|
||||
print("\n5. Re-testing with simulated data:")
|
||||
print("-" * 40)
|
||||
test_session_page()
|
||||
|
||||
# Cleanup test data
|
||||
print("\n6. Cleaning up test data:")
|
||||
subprocess.run([
|
||||
"docker", "exec", "db", "psql", "-U", "adminuser", "-d", "meinedatenbank",
|
||||
"-c", "DELETE FROM sessions WHERE session_id LIKE 'TEST-%';"
|
||||
], capture_output=True, text=True)
|
||||
print("✓ Test sessions removed")
|
||||
159
v2_testing/test_timezone.py
Normale Datei
159
v2_testing/test_timezone.py
Normale Datei
@ -0,0 +1,159 @@
|
||||
#!/usr/bin/env python3
|
||||
import requests
|
||||
import urllib3
|
||||
from datetime import datetime
|
||||
from zoneinfo import ZoneInfo
|
||||
import json
|
||||
import time
|
||||
|
||||
# Disable SSL warnings for self-signed certificate
|
||||
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
|
||||
|
||||
# Test configuration
|
||||
# Use external URL for testing
|
||||
base_url = "https://admin-panel-undso.z5m7q9dk3ah2v1plx6ju.com"
|
||||
# Fallback to localhost if external URL is not accessible
|
||||
fallback_url = "https://localhost:443"
|
||||
admin_user = {"username": "rac00n", "password": "1248163264"}
|
||||
|
||||
def test_timezone_functionality():
|
||||
"""Test if timestamps are in German timezone (Europe/Berlin)"""
|
||||
session = requests.Session()
|
||||
|
||||
print("Testing Timezone Functionality (Europe/Berlin)")
|
||||
print("=" * 50)
|
||||
|
||||
# Test connection to external URL first
|
||||
global base_url
|
||||
try:
|
||||
test_response = session.get(base_url, verify=True, timeout=5)
|
||||
print(f"✓ Using external URL: {base_url}")
|
||||
except:
|
||||
base_url = fallback_url
|
||||
print(f"ℹ Using fallback URL: {base_url}")
|
||||
|
||||
# Get current time in UTC and Berlin
|
||||
utc_now = datetime.now(ZoneInfo("UTC"))
|
||||
berlin_now = datetime.now(ZoneInfo("Europe/Berlin"))
|
||||
|
||||
print(f"Current UTC time: {utc_now.strftime('%Y-%m-%d %H:%M:%S %Z')}")
|
||||
print(f"Current Berlin time: {berlin_now.strftime('%Y-%m-%d %H:%M:%S %Z')}")
|
||||
print(f"Time difference: {(berlin_now.hour - utc_now.hour) % 24} hours")
|
||||
print()
|
||||
|
||||
# Login
|
||||
verify_ssl = base_url != fallback_url # Verify SSL for external URL only
|
||||
response = session.get(f"{base_url}/login", verify=verify_ssl)
|
||||
if response.status_code != 200:
|
||||
print(f"✗ Failed to access login page: {response.status_code}")
|
||||
return
|
||||
|
||||
login_data = {
|
||||
"username": admin_user["username"],
|
||||
"password": admin_user["password"]
|
||||
}
|
||||
|
||||
response = session.post(f"{base_url}/login", data=login_data, verify=verify_ssl, allow_redirects=False)
|
||||
|
||||
if response.status_code != 302:
|
||||
print(f"✗ Login failed: {response.status_code}")
|
||||
return
|
||||
|
||||
print("✓ Login successful")
|
||||
print()
|
||||
|
||||
# Test 1: Create a test license to check created_at timestamp
|
||||
print("Test 1: Creating test license to check timestamps...")
|
||||
|
||||
# First, get a customer ID or create one
|
||||
license_data = {
|
||||
"customer_select": "new",
|
||||
"customer_name": f"Timezone Test Customer {int(time.time())}",
|
||||
"customer_email": f"timezone-test-{int(time.time())}@example.com",
|
||||
"license_key": f"AF-{berlin_now.strftime('%Y%m')}T-TEST-TIME-ZONE",
|
||||
"license_type": "test",
|
||||
"max_sessions": "1",
|
||||
"start_date": berlin_now.strftime("%Y-%m-%d"),
|
||||
"duration": "1",
|
||||
"duration_unit": "days"
|
||||
}
|
||||
|
||||
response = session.post(f"{base_url}/create", data=license_data, verify=verify_ssl)
|
||||
|
||||
if response.status_code == 200:
|
||||
print("✓ Test license created")
|
||||
else:
|
||||
print(f"✗ Failed to create license: {response.status_code}")
|
||||
|
||||
# Test 2: Check audit log for timezone
|
||||
print("\nTest 2: Checking audit log timestamps...")
|
||||
|
||||
response = session.get(f"{base_url}/audit", verify=verify_ssl)
|
||||
if response.status_code == 200:
|
||||
# Extract the most recent audit log entry timestamp from HTML
|
||||
if "CREATE" in response.text and license_data["license_key"] in response.text:
|
||||
print("✓ Audit log entry created")
|
||||
# Check if timestamps in audit log appear to be in German time
|
||||
# This is a simple check - in production you'd parse the HTML properly
|
||||
current_hour = berlin_now.strftime("%H:")
|
||||
if current_hour in response.text:
|
||||
print(f"✓ Audit log shows Berlin time (contains {current_hour})")
|
||||
else:
|
||||
print(f"⚠ Audit log might show UTC time (doesn't contain {current_hour})")
|
||||
else:
|
||||
print(f"✗ Failed to access audit log: {response.status_code}")
|
||||
|
||||
# Test 3: Check backup functionality for filename timezone
|
||||
print("\nTest 3: Testing backup filename timezone...")
|
||||
|
||||
response = session.post(f"{base_url}/backup/create", verify=verify_ssl)
|
||||
if response.status_code == 302: # Redirect after backup
|
||||
print("✓ Backup created")
|
||||
|
||||
# Check backup list
|
||||
response = session.get(f"{base_url}/backups", verify=verify_ssl)
|
||||
if response.status_code == 200:
|
||||
# Check if backup filename contains current Berlin hour
|
||||
berlin_hour = berlin_now.strftime("%H")
|
||||
if f"_{berlin_hour}" in response.text:
|
||||
print(f"✓ Backup filename uses Berlin time (contains hour {berlin_hour})")
|
||||
else:
|
||||
utc_hour = utc_now.strftime("%H")
|
||||
if f"_{utc_hour}" in response.text:
|
||||
print(f"✗ Backup filename might use UTC time (contains hour {utc_hour})")
|
||||
else:
|
||||
print("⚠ Could not determine timezone from backup filename")
|
||||
else:
|
||||
print(f"✗ Failed to create backup: {response.status_code}")
|
||||
|
||||
# Test 4: Check session timestamps
|
||||
print("\nTest 4: Checking session timestamps...")
|
||||
|
||||
response = session.get(f"{base_url}/sessions", verify=verify_ssl)
|
||||
if response.status_code == 200:
|
||||
print("✓ Accessed sessions page")
|
||||
# Active sessions should show current time
|
||||
if "Keine aktiven Sessions" not in response.text:
|
||||
print("✓ Session data available")
|
||||
else:
|
||||
print("ℹ No active sessions to check (this is normal)")
|
||||
else:
|
||||
print(f"✗ Failed to access sessions: {response.status_code}")
|
||||
|
||||
# Test 5: Database timezone check
|
||||
print("\nTest 5: Summary")
|
||||
print("-" * 30)
|
||||
|
||||
time_diff = (berlin_now.hour - utc_now.hour) % 24
|
||||
if time_diff == 1:
|
||||
print("✓ Timezone offset is +1 hour (CET - Central European Time)")
|
||||
elif time_diff == 2:
|
||||
print("✓ Timezone offset is +2 hours (CEST - Central European Summer Time)")
|
||||
else:
|
||||
print(f"⚠ Unexpected timezone offset: {time_diff} hours")
|
||||
|
||||
print("\nNote: All new timestamps should be in Europe/Berlin timezone")
|
||||
print("Existing data might still show UTC until updated")
|
||||
|
||||
if __name__ == "__main__":
|
||||
test_timezone_functionality()
|
||||
122
v2_testing/test_timezone_simple.py
Normale Datei
122
v2_testing/test_timezone_simple.py
Normale Datei
@ -0,0 +1,122 @@
|
||||
#!/usr/bin/env python3
|
||||
import requests
|
||||
import urllib3
|
||||
from datetime import datetime
|
||||
from zoneinfo import ZoneInfo
|
||||
import re
|
||||
|
||||
# Disable SSL warnings for self-signed certificate
|
||||
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
|
||||
|
||||
# Test configuration
|
||||
base_url = "https://admin-panel-undso.z5m7q9dk3ah2v1plx6ju.com"
|
||||
fallback_url = "https://localhost:443"
|
||||
admin_user = {"username": "rac00n", "password": "1248163264"}
|
||||
|
||||
def test_timezone_simple():
|
||||
"""Simple test to verify timezone is Europe/Berlin"""
|
||||
session = requests.Session()
|
||||
|
||||
print("Timezone Verification Test (Europe/Berlin)")
|
||||
print("=" * 50)
|
||||
|
||||
# Test connection
|
||||
try:
|
||||
test_response = session.get(base_url, verify=True, timeout=5)
|
||||
verify_ssl = True
|
||||
print(f"✓ Using external URL: {base_url}")
|
||||
except:
|
||||
base_url_local = fallback_url
|
||||
verify_ssl = False
|
||||
print(f"ℹ Using fallback URL: {fallback_url}")
|
||||
else:
|
||||
base_url_local = base_url
|
||||
|
||||
# Show current times
|
||||
utc_now = datetime.now(ZoneInfo("UTC"))
|
||||
berlin_now = datetime.now(ZoneInfo("Europe/Berlin"))
|
||||
|
||||
print(f"\nCurrent times:")
|
||||
print(f" UTC: {utc_now.strftime('%Y-%m-%d %H:%M:%S')}")
|
||||
print(f" Berlin: {berlin_now.strftime('%Y-%m-%d %H:%M:%S')}")
|
||||
|
||||
# Calculate offset
|
||||
time_diff = (berlin_now.hour - utc_now.hour) % 24
|
||||
if berlin_now.day != utc_now.day:
|
||||
# Handle day boundary
|
||||
if berlin_now.day > utc_now.day:
|
||||
time_diff = (berlin_now.hour + 24 - utc_now.hour) % 24
|
||||
else:
|
||||
time_diff = (berlin_now.hour - utc_now.hour - 24) % 24
|
||||
|
||||
print(f" Offset: +{time_diff} hours")
|
||||
|
||||
# Login
|
||||
response = session.get(f"{base_url_local}/login", verify=verify_ssl)
|
||||
if response.status_code != 200:
|
||||
print(f"\n✗ Failed to access login page: {response.status_code}")
|
||||
return
|
||||
|
||||
login_data = {
|
||||
"username": admin_user["username"],
|
||||
"password": admin_user["password"]
|
||||
}
|
||||
|
||||
response = session.post(f"{base_url_local}/login", data=login_data, verify=verify_ssl, allow_redirects=False)
|
||||
|
||||
if response.status_code != 302:
|
||||
print(f"\n✗ Login failed: {response.status_code}")
|
||||
return
|
||||
|
||||
print(f"\n✓ Login successful")
|
||||
|
||||
# Check dashboard for any timestamps
|
||||
print("\nChecking for timestamps in dashboard...")
|
||||
response = session.get(f"{base_url_local}/", verify=verify_ssl)
|
||||
if response.status_code == 200:
|
||||
# Look for time patterns in dashboard
|
||||
time_pattern = r'\d{2}:\d{2}:\d{2}'
|
||||
times_found = re.findall(time_pattern, response.text)
|
||||
if times_found:
|
||||
print(f"✓ Found {len(times_found)} timestamps in dashboard")
|
||||
# Check if any match current Berlin hour
|
||||
berlin_hour = berlin_now.strftime("%H:")
|
||||
if any(berlin_hour in time for time in times_found):
|
||||
print(f"✓ Timestamps appear to use Berlin time (found {berlin_hour}xx)")
|
||||
else:
|
||||
print(f"ℹ Could not confirm timezone from timestamps")
|
||||
else:
|
||||
print("ℹ No timestamps found in dashboard")
|
||||
|
||||
# Check audit log
|
||||
print("\nChecking audit log for LOGIN timestamp...")
|
||||
response = session.get(f"{base_url_local}/audit", verify=verify_ssl)
|
||||
if response.status_code == 200:
|
||||
# Extract the most recent LOGIN entry
|
||||
if "LOGIN_SUCCESS" in response.text:
|
||||
# Look for timestamp near LOGIN_SUCCESS
|
||||
berlin_time_str = berlin_now.strftime("%Y-%m-%d %H:")
|
||||
if berlin_time_str in response.text:
|
||||
print(f"✓ Audit log shows Berlin time (contains {berlin_time_str}xx)")
|
||||
else:
|
||||
utc_time_str = utc_now.strftime("%Y-%m-%d %H:")
|
||||
if utc_time_str in response.text:
|
||||
print(f"✗ Audit log might show UTC time (contains {utc_time_str}xx)")
|
||||
else:
|
||||
print(f"ℹ Could not determine timezone from audit log")
|
||||
|
||||
# Summary
|
||||
print("\n" + "=" * 50)
|
||||
print("Summary:")
|
||||
if time_diff == 1:
|
||||
print("✓ System timezone offset: +1 hour (CET - Winter time)")
|
||||
elif time_diff == 2:
|
||||
print("✓ System timezone offset: +2 hours (CEST - Summer time)")
|
||||
else:
|
||||
print(f"⚠ Unexpected timezone offset: +{time_diff} hours")
|
||||
|
||||
print("\nNote: The system should use Europe/Berlin timezone for all new data.")
|
||||
print("Existing data created before the timezone change may still show UTC.")
|
||||
|
||||
if __name__ == "__main__":
|
||||
test_timezone_simple()
|
||||
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