Test zu Fake geändert, weil Namensproblem
Dieser Commit ist enthalten in:
@@ -73,7 +73,8 @@
|
|||||||
"Bash(docker compose:*)",
|
"Bash(docker compose:*)",
|
||||||
"Bash(true)",
|
"Bash(true)",
|
||||||
"Bash(git checkout:*)",
|
"Bash(git checkout:*)",
|
||||||
"Bash(touch:*)"
|
"Bash(touch:*)",
|
||||||
|
"Bash(wget:*)"
|
||||||
],
|
],
|
||||||
"deny": []
|
"deny": []
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ CREATE TABLE IF NOT EXISTS customers (
|
|||||||
id SERIAL PRIMARY KEY,
|
id SERIAL PRIMARY KEY,
|
||||||
name TEXT NOT NULL,
|
name TEXT NOT NULL,
|
||||||
email TEXT,
|
email TEXT,
|
||||||
is_test BOOLEAN DEFAULT FALSE,
|
is_fake BOOLEAN DEFAULT FALSE,
|
||||||
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
|
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
|
||||||
CONSTRAINT unique_email UNIQUE (email)
|
CONSTRAINT unique_email UNIQUE (email)
|
||||||
);
|
);
|
||||||
@@ -21,7 +21,7 @@ CREATE TABLE IF NOT EXISTS licenses (
|
|||||||
valid_from DATE NOT NULL,
|
valid_from DATE NOT NULL,
|
||||||
valid_until DATE NOT NULL,
|
valid_until DATE NOT NULL,
|
||||||
is_active BOOLEAN DEFAULT TRUE,
|
is_active BOOLEAN DEFAULT TRUE,
|
||||||
is_test BOOLEAN DEFAULT FALSE,
|
is_fake BOOLEAN DEFAULT FALSE,
|
||||||
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP
|
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -129,7 +129,7 @@ CREATE TABLE IF NOT EXISTS resource_pools (
|
|||||||
quarantine_until TIMESTAMP WITH TIME ZONE,
|
quarantine_until TIMESTAMP WITH TIME ZONE,
|
||||||
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
|
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
|
||||||
notes TEXT,
|
notes TEXT,
|
||||||
is_test BOOLEAN DEFAULT FALSE,
|
is_fake BOOLEAN DEFAULT FALSE,
|
||||||
UNIQUE(resource_type, resource_value)
|
UNIQUE(resource_type, resource_value)
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -245,48 +245,48 @@ CREATE TABLE IF NOT EXISTS users (
|
|||||||
CREATE INDEX IF NOT EXISTS idx_users_username ON users(username);
|
CREATE INDEX IF NOT EXISTS idx_users_username ON users(username);
|
||||||
CREATE INDEX IF NOT EXISTS idx_users_reset_token ON users(password_reset_token) WHERE password_reset_token IS NOT NULL;
|
CREATE INDEX IF NOT EXISTS idx_users_reset_token ON users(password_reset_token) WHERE password_reset_token IS NOT NULL;
|
||||||
|
|
||||||
-- Migration: Add is_test column to licenses if it doesn't exist
|
-- Migration: Add is_fake column to licenses if it doesn't exist
|
||||||
DO $$
|
DO $$
|
||||||
BEGIN
|
BEGIN
|
||||||
IF NOT EXISTS (SELECT 1 FROM information_schema.columns
|
IF NOT EXISTS (SELECT 1 FROM information_schema.columns
|
||||||
WHERE table_name = 'licenses' AND column_name = 'is_test') THEN
|
WHERE table_name = 'licenses' AND column_name = 'is_fake') THEN
|
||||||
ALTER TABLE licenses ADD COLUMN is_test BOOLEAN DEFAULT FALSE;
|
ALTER TABLE licenses ADD COLUMN is_fake BOOLEAN DEFAULT FALSE;
|
||||||
|
|
||||||
-- Mark all existing licenses as test data
|
-- Mark all existing licenses as fake data
|
||||||
UPDATE licenses SET is_test = TRUE;
|
UPDATE licenses SET is_fake = TRUE;
|
||||||
|
|
||||||
-- Add index for better performance when filtering test data
|
-- Add index for better performance when filtering fake data
|
||||||
CREATE INDEX idx_licenses_is_test ON licenses(is_test);
|
CREATE INDEX idx_licenses_is_fake ON licenses(is_fake);
|
||||||
END IF;
|
END IF;
|
||||||
END $$;
|
END $$;
|
||||||
|
|
||||||
-- Migration: Add is_test column to customers if it doesn't exist
|
-- Migration: Add is_fake column to customers if it doesn't exist
|
||||||
DO $$
|
DO $$
|
||||||
BEGIN
|
BEGIN
|
||||||
IF NOT EXISTS (SELECT 1 FROM information_schema.columns
|
IF NOT EXISTS (SELECT 1 FROM information_schema.columns
|
||||||
WHERE table_name = 'customers' AND column_name = 'is_test') THEN
|
WHERE table_name = 'customers' AND column_name = 'is_fake') THEN
|
||||||
ALTER TABLE customers ADD COLUMN is_test BOOLEAN DEFAULT FALSE;
|
ALTER TABLE customers ADD COLUMN is_fake BOOLEAN DEFAULT FALSE;
|
||||||
|
|
||||||
-- Mark all existing customers as test data
|
-- Mark all existing customers as fake data
|
||||||
UPDATE customers SET is_test = TRUE;
|
UPDATE customers SET is_fake = TRUE;
|
||||||
|
|
||||||
-- Add index for better performance
|
-- Add index for better performance
|
||||||
CREATE INDEX idx_customers_is_test ON customers(is_test);
|
CREATE INDEX idx_customers_is_fake ON customers(is_fake);
|
||||||
END IF;
|
END IF;
|
||||||
END $$;
|
END $$;
|
||||||
|
|
||||||
-- Migration: Add is_test column to resource_pools if it doesn't exist
|
-- Migration: Add is_fake column to resource_pools if it doesn't exist
|
||||||
DO $$
|
DO $$
|
||||||
BEGIN
|
BEGIN
|
||||||
IF NOT EXISTS (SELECT 1 FROM information_schema.columns
|
IF NOT EXISTS (SELECT 1 FROM information_schema.columns
|
||||||
WHERE table_name = 'resource_pools' AND column_name = 'is_test') THEN
|
WHERE table_name = 'resource_pools' AND column_name = 'is_fake') THEN
|
||||||
ALTER TABLE resource_pools ADD COLUMN is_test BOOLEAN DEFAULT FALSE;
|
ALTER TABLE resource_pools ADD COLUMN is_fake BOOLEAN DEFAULT FALSE;
|
||||||
|
|
||||||
-- Mark all existing resources as test data
|
-- Mark all existing resources as fake data
|
||||||
UPDATE resource_pools SET is_test = TRUE;
|
UPDATE resource_pools SET is_fake = TRUE;
|
||||||
|
|
||||||
-- Add index for better performance
|
-- Add index for better performance
|
||||||
CREATE INDEX idx_resource_pools_is_test ON resource_pools(is_test);
|
CREATE INDEX idx_resource_pools_is_fake ON resource_pools(is_fake);
|
||||||
END IF;
|
END IF;
|
||||||
END $$;
|
END $$;
|
||||||
|
|
||||||
|
|||||||
48
v2_adminpanel/migrations/rename_test_to_fake.sql
Normale Datei
48
v2_adminpanel/migrations/rename_test_to_fake.sql
Normale Datei
@@ -0,0 +1,48 @@
|
|||||||
|
-- Migration script to rename is_test columns to is_fake
|
||||||
|
-- This separates fake/demo data from test licenses
|
||||||
|
|
||||||
|
-- 1. Rename columns in all tables
|
||||||
|
DO $$
|
||||||
|
BEGIN
|
||||||
|
-- Rename is_test to is_fake in customers table
|
||||||
|
IF EXISTS (SELECT 1 FROM information_schema.columns
|
||||||
|
WHERE table_name = 'customers' AND column_name = 'is_test') THEN
|
||||||
|
ALTER TABLE customers RENAME COLUMN is_test TO is_fake;
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
-- Rename is_test to is_fake in licenses table
|
||||||
|
IF EXISTS (SELECT 1 FROM information_schema.columns
|
||||||
|
WHERE table_name = 'licenses' AND column_name = 'is_test') THEN
|
||||||
|
ALTER TABLE licenses RENAME COLUMN is_test TO is_fake;
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
-- Rename is_test to is_fake in resource_pools table
|
||||||
|
IF EXISTS (SELECT 1 FROM information_schema.columns
|
||||||
|
WHERE table_name = 'resource_pools' AND column_name = 'is_test') THEN
|
||||||
|
ALTER TABLE resource_pools RENAME COLUMN is_test TO is_fake;
|
||||||
|
END IF;
|
||||||
|
END $$;
|
||||||
|
|
||||||
|
-- 2. Rename indexes
|
||||||
|
DO $$
|
||||||
|
BEGIN
|
||||||
|
-- Rename index for customers
|
||||||
|
IF EXISTS (SELECT 1 FROM pg_indexes WHERE indexname = 'idx_customers_is_test') THEN
|
||||||
|
ALTER INDEX idx_customers_is_test RENAME TO idx_customers_is_fake;
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
-- Rename index for licenses
|
||||||
|
IF EXISTS (SELECT 1 FROM pg_indexes WHERE indexname = 'idx_licenses_is_test') THEN
|
||||||
|
ALTER INDEX idx_licenses_is_test RENAME TO idx_licenses_is_fake;
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
-- Rename index for resource_pools
|
||||||
|
IF EXISTS (SELECT 1 FROM pg_indexes WHERE indexname = 'idx_resource_pools_is_test') THEN
|
||||||
|
ALTER INDEX idx_resource_pools_is_test RENAME TO idx_resource_pools_is_fake;
|
||||||
|
END IF;
|
||||||
|
END $$;
|
||||||
|
|
||||||
|
-- 3. Add comments to clarify the purpose
|
||||||
|
COMMENT ON COLUMN customers.is_fake IS 'Marks fake/demo data, not to be confused with test licenses';
|
||||||
|
COMMENT ON COLUMN licenses.is_fake IS 'Marks fake/demo data, not to be confused with test license type';
|
||||||
|
COMMENT ON COLUMN resource_pools.is_fake IS 'Marks fake/demo resources';
|
||||||
@@ -32,12 +32,12 @@ def get_user_by_username(username):
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
def get_licenses(show_test=False):
|
def get_licenses(show_fake=False):
|
||||||
"""Get all licenses from database"""
|
"""Get all licenses from database"""
|
||||||
try:
|
try:
|
||||||
with get_db_connection() as conn:
|
with get_db_connection() as conn:
|
||||||
with get_db_cursor(conn) as cur:
|
with get_db_cursor(conn) as cur:
|
||||||
if show_test:
|
if show_fake:
|
||||||
cur.execute("""
|
cur.execute("""
|
||||||
SELECT l.*, c.name as customer_name
|
SELECT l.*, c.name as customer_name
|
||||||
FROM licenses l
|
FROM licenses l
|
||||||
@@ -49,7 +49,7 @@ def get_licenses(show_test=False):
|
|||||||
SELECT l.*, c.name as customer_name
|
SELECT l.*, c.name as customer_name
|
||||||
FROM licenses l
|
FROM licenses l
|
||||||
LEFT JOIN customers c ON l.customer_id = c.id
|
LEFT JOIN customers c ON l.customer_id = c.id
|
||||||
WHERE l.is_test = false
|
WHERE l.is_fake = false
|
||||||
ORDER BY l.created_at DESC
|
ORDER BY l.created_at DESC
|
||||||
""")
|
""")
|
||||||
|
|
||||||
@@ -86,7 +86,7 @@ def get_license_by_id(license_id):
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
def get_customers(show_test=False, search=None):
|
def get_customers(show_fake=False, search=None):
|
||||||
"""Get all customers from database"""
|
"""Get all customers from database"""
|
||||||
try:
|
try:
|
||||||
with get_db_connection() as conn:
|
with get_db_connection() as conn:
|
||||||
@@ -102,8 +102,8 @@ def get_customers(show_test=False, search=None):
|
|||||||
where_clauses = []
|
where_clauses = []
|
||||||
params = []
|
params = []
|
||||||
|
|
||||||
if not show_test:
|
if not show_fake:
|
||||||
where_clauses.append("c.is_test = false")
|
where_clauses.append("c.is_fake = false")
|
||||||
|
|
||||||
if search:
|
if search:
|
||||||
where_clauses.append("(LOWER(c.name) LIKE LOWER(%s) OR LOWER(c.email) LIKE LOWER(%s))")
|
where_clauses.append("(LOWER(c.name) LIKE LOWER(%s) OR LOWER(c.email) LIKE LOWER(%s))")
|
||||||
|
|||||||
@@ -25,18 +25,18 @@ def dashboard():
|
|||||||
try:
|
try:
|
||||||
# Hole Statistiken mit sicheren Defaults
|
# Hole Statistiken mit sicheren Defaults
|
||||||
# Anzahl aktiver Lizenzen (nur echte Daten, keine Testdaten)
|
# Anzahl aktiver Lizenzen (nur echte Daten, keine Testdaten)
|
||||||
cur.execute("SELECT COUNT(*) FROM licenses WHERE is_active = true AND is_test = false")
|
cur.execute("SELECT COUNT(*) FROM licenses WHERE is_active = true AND is_fake = false")
|
||||||
active_licenses = cur.fetchone()[0] if cur.rowcount > 0 else 0
|
active_licenses = cur.fetchone()[0] if cur.rowcount > 0 else 0
|
||||||
|
|
||||||
# Anzahl Kunden (nur echte Kunden, keine Testkunden)
|
# Anzahl Kunden (nur echte Kunden, keine Fake-Kunden)
|
||||||
cur.execute("SELECT COUNT(*) FROM customers WHERE is_test = false")
|
cur.execute("SELECT COUNT(*) FROM customers WHERE is_fake = false")
|
||||||
total_customers = cur.fetchone()[0] if cur.rowcount > 0 else 0
|
total_customers = cur.fetchone()[0] if cur.rowcount > 0 else 0
|
||||||
|
|
||||||
# Testdaten separat zählen für optionale Anzeige
|
# Testdaten separat zählen für optionale Anzeige
|
||||||
cur.execute("SELECT COUNT(*) FROM customers WHERE is_test = true")
|
cur.execute("SELECT COUNT(*) FROM customers WHERE is_fake = true")
|
||||||
test_customers_count = cur.fetchone()[0] if cur.rowcount > 0 else 0
|
fake_customers_count = cur.fetchone()[0] if cur.rowcount > 0 else 0
|
||||||
|
|
||||||
cur.execute("SELECT COUNT(*) FROM licenses WHERE is_test = true")
|
cur.execute("SELECT COUNT(*) FROM licenses WHERE is_fake = true")
|
||||||
test_licenses_count = cur.fetchone()[0] if cur.rowcount > 0 else 0
|
test_licenses_count = cur.fetchone()[0] if cur.rowcount > 0 else 0
|
||||||
|
|
||||||
# Anzahl aktiver Sessions (Admin-Panel)
|
# Anzahl aktiver Sessions (Admin-Panel)
|
||||||
@@ -61,7 +61,7 @@ def dashboard():
|
|||||||
FROM license_heartbeats lh
|
FROM license_heartbeats lh
|
||||||
JOIN licenses l ON l.id = lh.license_id
|
JOIN licenses l ON l.id = lh.license_id
|
||||||
WHERE lh.timestamp > NOW() - INTERVAL '15 minutes'
|
WHERE lh.timestamp > NOW() - INTERVAL '15 minutes'
|
||||||
AND l.is_test = false
|
AND l.is_fake = false
|
||||||
""")
|
""")
|
||||||
active_usage = cur.fetchone()[0] if cur.rowcount > 0 else 0
|
active_usage = cur.fetchone()[0] if cur.rowcount > 0 else 0
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
@@ -82,7 +82,7 @@ def dashboard():
|
|||||||
FROM licenses l
|
FROM licenses l
|
||||||
LEFT JOIN customers c ON l.customer_id = c.id
|
LEFT JOIN customers c ON l.customer_id = c.id
|
||||||
LEFT JOIN sessions s ON l.id = s.license_id
|
LEFT JOIN sessions s ON l.id = s.license_id
|
||||||
WHERE l.is_test = false AND c.is_test = false
|
WHERE l.is_fake = false AND c.is_fake = false
|
||||||
GROUP BY l.license_key, c.name
|
GROUP BY l.license_key, c.name
|
||||||
ORDER BY session_count DESC
|
ORDER BY session_count DESC
|
||||||
LIMIT 10
|
LIMIT 10
|
||||||
@@ -109,7 +109,7 @@ def dashboard():
|
|||||||
cur.execute("""
|
cur.execute("""
|
||||||
SELECT COUNT(*) as full_licenses
|
SELECT COUNT(*) as full_licenses
|
||||||
FROM licenses
|
FROM licenses
|
||||||
WHERE is_test = false
|
WHERE is_fake = false
|
||||||
""")
|
""")
|
||||||
license_count = cur.fetchone()
|
license_count = cur.fetchone()
|
||||||
full_licenses = license_count[0] if license_count and license_count[0] else 0
|
full_licenses = license_count[0] if license_count and license_count[0] else 0
|
||||||
@@ -123,7 +123,7 @@ def dashboard():
|
|||||||
COUNT(CASE WHEN valid_until < NOW() THEN 1 END) as expired,
|
COUNT(CASE WHEN valid_until < NOW() THEN 1 END) as expired,
|
||||||
COUNT(CASE WHEN is_active = false THEN 1 END) as inactive
|
COUNT(CASE WHEN is_active = false THEN 1 END) as inactive
|
||||||
FROM licenses
|
FROM licenses
|
||||||
WHERE is_test = false
|
WHERE is_fake = false
|
||||||
""")
|
""")
|
||||||
license_status = cur.fetchone()
|
license_status = cur.fetchone()
|
||||||
active_licenses_count = license_status[0] if license_status and license_status[0] else 0
|
active_licenses_count = license_status[0] if license_status and license_status[0] else 0
|
||||||
@@ -140,8 +140,8 @@ def dashboard():
|
|||||||
EXTRACT(DAY FROM (l.valid_until - NOW())) as days_remaining
|
EXTRACT(DAY FROM (l.valid_until - NOW())) as days_remaining
|
||||||
FROM licenses l
|
FROM licenses l
|
||||||
JOIN customers c ON l.customer_id = c.id
|
JOIN customers c ON l.customer_id = c.id
|
||||||
WHERE l.is_test = false
|
WHERE l.is_fake = false
|
||||||
AND c.is_test = false
|
AND c.is_fake = false
|
||||||
AND l.is_active = true
|
AND l.is_active = true
|
||||||
AND l.valid_until IS NOT NULL
|
AND l.valid_until IS NOT NULL
|
||||||
AND l.valid_until > NOW()
|
AND l.valid_until > NOW()
|
||||||
@@ -166,8 +166,8 @@ def dashboard():
|
|||||||
END as status
|
END as status
|
||||||
FROM licenses l
|
FROM licenses l
|
||||||
JOIN customers c ON l.customer_id = c.id
|
JOIN customers c ON l.customer_id = c.id
|
||||||
WHERE l.is_test = false
|
WHERE l.is_fake = false
|
||||||
AND c.is_test = false
|
AND c.is_fake = false
|
||||||
ORDER BY l.created_at DESC
|
ORDER BY l.created_at DESC
|
||||||
LIMIT 5
|
LIMIT 5
|
||||||
""")
|
""")
|
||||||
@@ -176,15 +176,15 @@ def dashboard():
|
|||||||
# Stats Objekt für Template erstellen
|
# Stats Objekt für Template erstellen
|
||||||
stats = {
|
stats = {
|
||||||
'total_customers': total_customers,
|
'total_customers': total_customers,
|
||||||
'total_licenses': active_licenses, # This was already filtered for is_test = false
|
'total_licenses': active_licenses, # This was already filtered for is_fake = false
|
||||||
'active_sessions': active_sessions, # Admin-Panel Sessions
|
'active_sessions': active_sessions, # Admin-Panel Sessions
|
||||||
'active_usage': active_usage, # Aktive Kunden-Nutzung
|
'active_usage': active_usage, # Aktive Kunden-Nutzung
|
||||||
'active_licenses': active_licenses_count,
|
'active_licenses': active_licenses_count,
|
||||||
'full_licenses': full_licenses,
|
'full_licenses': full_licenses,
|
||||||
'test_licenses': test_version_licenses, # Test versions, not test data
|
'test_licenses': test_version_licenses, # Test versions, not test data
|
||||||
'test_data_count': test_licenses_count, # Actual test data count
|
'fake_data_count': test_licenses_count, # Actual test data count
|
||||||
'test_customers_count': test_customers_count,
|
'fake_customers_count': fake_customers_count,
|
||||||
'test_resources_count': 0,
|
'fake_resources_count': 0,
|
||||||
'expired_licenses': expired_licenses,
|
'expired_licenses': expired_licenses,
|
||||||
'inactive_licenses': inactive_licenses,
|
'inactive_licenses': inactive_licenses,
|
||||||
'last_backup': None,
|
'last_backup': None,
|
||||||
@@ -210,7 +210,7 @@ def dashboard():
|
|||||||
COUNT(CASE WHEN status = 'quarantine' THEN 1 END) as quarantine,
|
COUNT(CASE WHEN status = 'quarantine' THEN 1 END) as quarantine,
|
||||||
COUNT(*) as total
|
COUNT(*) as total
|
||||||
FROM resource_pool
|
FROM resource_pool
|
||||||
WHERE type = %s AND is_test = false
|
WHERE type = %s AND is_fake = false
|
||||||
""", (resource_type,))
|
""", (resource_type,))
|
||||||
|
|
||||||
result = cur.fetchone()
|
result = cur.fetchone()
|
||||||
@@ -249,9 +249,9 @@ def dashboard():
|
|||||||
|
|
||||||
# Count test resources separately
|
# Count test resources separately
|
||||||
try:
|
try:
|
||||||
cur.execute("SELECT COUNT(*) FROM resource_pool WHERE is_test = true")
|
cur.execute("SELECT COUNT(*) FROM resource_pool WHERE is_fake = true")
|
||||||
test_resources_count = cur.fetchone()[0] if cur.rowcount > 0 else 0
|
fake_resources_count = cur.fetchone()[0] if cur.rowcount > 0 else 0
|
||||||
stats['test_resources_count'] = test_resources_count
|
stats['fake_resources_count'] = fake_resources_count
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ def api_customers():
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
# Get all customers (with optional search)
|
# Get all customers (with optional search)
|
||||||
customers = get_customers(show_test=True, search=search)
|
customers = get_customers(show_fake=True, search=search)
|
||||||
|
|
||||||
# Pagination
|
# Pagination
|
||||||
start = (page - 1) * per_page
|
start = (page - 1) * per_page
|
||||||
@@ -396,7 +396,7 @@ def bulk_delete_licenses():
|
|||||||
for license_id in license_ids:
|
for license_id in license_ids:
|
||||||
# Hole vollständige Lizenz-Info
|
# Hole vollständige Lizenz-Info
|
||||||
cur.execute("""
|
cur.execute("""
|
||||||
SELECT l.id, l.license_key, l.is_active, l.is_test,
|
SELECT l.id, l.license_key, l.is_active, l.is_fake,
|
||||||
c.name as customer_name
|
c.name as customer_name
|
||||||
FROM licenses l
|
FROM licenses l
|
||||||
LEFT JOIN customers c ON l.customer_id = c.id
|
LEFT JOIN customers c ON l.customer_id = c.id
|
||||||
@@ -407,7 +407,7 @@ def bulk_delete_licenses():
|
|||||||
if not result:
|
if not result:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
license_id, license_key, is_active, is_test, customer_name = result
|
license_id, license_key, is_active, is_fake, customer_name = result
|
||||||
|
|
||||||
# Safety check: Don't delete active licenses unless forced
|
# Safety check: Don't delete active licenses unless forced
|
||||||
if is_active and not force_delete:
|
if is_active and not force_delete:
|
||||||
@@ -601,7 +601,7 @@ def get_license_resources(license_id):
|
|||||||
rp.id,
|
rp.id,
|
||||||
rp.resource_type,
|
rp.resource_type,
|
||||||
rp.resource_value,
|
rp.resource_value,
|
||||||
rp.is_test,
|
rp.is_fake,
|
||||||
rp.status_changed_at,
|
rp.status_changed_at,
|
||||||
lr.assigned_at,
|
lr.assigned_at,
|
||||||
lr.assigned_by
|
lr.assigned_by
|
||||||
@@ -617,7 +617,7 @@ def get_license_resources(license_id):
|
|||||||
'id': row[0],
|
'id': row[0],
|
||||||
'type': row[1],
|
'type': row[1],
|
||||||
'value': row[2],
|
'value': row[2],
|
||||||
'is_test': row[3],
|
'is_fake': row[3],
|
||||||
'status_changed_at': row[4].isoformat() if row[4] else None,
|
'status_changed_at': row[4].isoformat() if row[4] else None,
|
||||||
'assigned_at': row[5].isoformat() if row[5] else None,
|
'assigned_at': row[5].isoformat() if row[5] else None,
|
||||||
'assigned_by': row[6]
|
'assigned_by': row[6]
|
||||||
@@ -675,7 +675,7 @@ def allocate_resources():
|
|||||||
try:
|
try:
|
||||||
# Prüfe ob Ressource verfügbar ist
|
# Prüfe ob Ressource verfügbar ist
|
||||||
cur.execute("""
|
cur.execute("""
|
||||||
SELECT resource_value, status, is_test
|
SELECT resource_value, status, is_fake
|
||||||
FROM resource_pools
|
FROM resource_pools
|
||||||
WHERE id = %s
|
WHERE id = %s
|
||||||
""", (resource_id,))
|
""", (resource_id,))
|
||||||
@@ -690,8 +690,8 @@ def allocate_resources():
|
|||||||
continue
|
continue
|
||||||
|
|
||||||
# Prüfe Test/Produktion Kompatibilität
|
# Prüfe Test/Produktion Kompatibilität
|
||||||
if resource[2] != license_data['is_test']:
|
if resource[2] != license_data['is_fake']:
|
||||||
errors.append(f"Ressource {resource[0]} ist {'Test' if resource[2] else 'Produktion'}, Lizenz ist {'Test' if license_data['is_test'] else 'Produktion'}")
|
errors.append(f"Ressource {resource[0]} ist {'Test' if resource[2] else 'Produktion'}, Lizenz ist {'Test' if license_data['is_fake'] else 'Produktion'}")
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# Weise Ressource zu
|
# Weise Ressource zu
|
||||||
@@ -751,32 +751,32 @@ def check_resource_availability():
|
|||||||
resource_type = request.args.get('type')
|
resource_type = request.args.get('type')
|
||||||
if resource_type:
|
if resource_type:
|
||||||
count = int(request.args.get('count', 1))
|
count = int(request.args.get('count', 1))
|
||||||
is_test = request.args.get('is_test', 'false') == 'true'
|
is_fake = request.args.get('is_fake', 'false') == 'true'
|
||||||
show_test = request.args.get('show_test', 'false') == 'true'
|
show_fake = request.args.get('show_fake', 'false') == 'true'
|
||||||
|
|
||||||
conn = get_connection()
|
conn = get_connection()
|
||||||
cur = conn.cursor()
|
cur = conn.cursor()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# Hole verfügbare Ressourcen mit Details
|
# Hole verfügbare Ressourcen mit Details
|
||||||
if show_test:
|
if show_fake:
|
||||||
# Zeige alle verfügbaren Ressourcen (Test und Produktion)
|
# Zeige alle verfügbaren Ressourcen (Test und Produktion)
|
||||||
cur.execute("""
|
cur.execute("""
|
||||||
SELECT id, resource_value, is_test
|
SELECT id, resource_value, is_fake
|
||||||
FROM resource_pools
|
FROM resource_pools
|
||||||
WHERE resource_type = %s
|
WHERE resource_type = %s
|
||||||
AND status = 'available'
|
AND status = 'available'
|
||||||
ORDER BY is_test, resource_value
|
ORDER BY is_fake, resource_value
|
||||||
LIMIT %s
|
LIMIT %s
|
||||||
""", (resource_type, count))
|
""", (resource_type, count))
|
||||||
else:
|
else:
|
||||||
# Zeige nur Produktions-Ressourcen
|
# Zeige nur Produktions-Ressourcen
|
||||||
cur.execute("""
|
cur.execute("""
|
||||||
SELECT id, resource_value, is_test
|
SELECT id, resource_value, is_fake
|
||||||
FROM resource_pools
|
FROM resource_pools
|
||||||
WHERE resource_type = %s
|
WHERE resource_type = %s
|
||||||
AND status = 'available'
|
AND status = 'available'
|
||||||
AND is_test = false
|
AND is_fake = false
|
||||||
ORDER BY resource_value
|
ORDER BY resource_value
|
||||||
LIMIT %s
|
LIMIT %s
|
||||||
""", (resource_type, count))
|
""", (resource_type, count))
|
||||||
@@ -786,7 +786,7 @@ def check_resource_availability():
|
|||||||
available_resources.append({
|
available_resources.append({
|
||||||
'id': row[0],
|
'id': row[0],
|
||||||
'value': row[1],
|
'value': row[1],
|
||||||
'is_test': row[2]
|
'is_fake': row[2]
|
||||||
})
|
})
|
||||||
|
|
||||||
return jsonify({
|
return jsonify({
|
||||||
@@ -794,7 +794,7 @@ def check_resource_availability():
|
|||||||
'requested': count,
|
'requested': count,
|
||||||
'available': available_resources,
|
'available': available_resources,
|
||||||
'sufficient': len(available_resources) >= count,
|
'sufficient': len(available_resources) >= count,
|
||||||
'show_test': show_test
|
'show_fake': show_fake
|
||||||
})
|
})
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
@@ -808,7 +808,7 @@ def check_resource_availability():
|
|||||||
domain_count = int(request.args.get('domain', 0))
|
domain_count = int(request.args.get('domain', 0))
|
||||||
ipv4_count = int(request.args.get('ipv4', 0))
|
ipv4_count = int(request.args.get('ipv4', 0))
|
||||||
phone_count = int(request.args.get('phone', 0))
|
phone_count = int(request.args.get('phone', 0))
|
||||||
is_test = request.args.get('is_test', 'false') == 'true'
|
is_fake = request.args.get('is_fake', 'false') == 'true'
|
||||||
|
|
||||||
conn = get_connection()
|
conn = get_connection()
|
||||||
cur = conn.cursor()
|
cur = conn.cursor()
|
||||||
@@ -823,8 +823,8 @@ def check_resource_availability():
|
|||||||
FROM resource_pools
|
FROM resource_pools
|
||||||
WHERE resource_type = 'domain'
|
WHERE resource_type = 'domain'
|
||||||
AND status = 'available'
|
AND status = 'available'
|
||||||
AND is_test = %s
|
AND is_fake = %s
|
||||||
""", (is_test,))
|
""", (is_fake,))
|
||||||
domain_available = cur.fetchone()[0]
|
domain_available = cur.fetchone()[0]
|
||||||
|
|
||||||
# IPv4
|
# IPv4
|
||||||
@@ -833,8 +833,8 @@ def check_resource_availability():
|
|||||||
FROM resource_pools
|
FROM resource_pools
|
||||||
WHERE resource_type = 'ipv4'
|
WHERE resource_type = 'ipv4'
|
||||||
AND status = 'available'
|
AND status = 'available'
|
||||||
AND is_test = %s
|
AND is_fake = %s
|
||||||
""", (is_test,))
|
""", (is_fake,))
|
||||||
ipv4_available = cur.fetchone()[0]
|
ipv4_available = cur.fetchone()[0]
|
||||||
|
|
||||||
# Phones
|
# Phones
|
||||||
@@ -843,8 +843,8 @@ def check_resource_availability():
|
|||||||
FROM resource_pools
|
FROM resource_pools
|
||||||
WHERE resource_type = 'phone'
|
WHERE resource_type = 'phone'
|
||||||
AND status = 'available'
|
AND status = 'available'
|
||||||
AND is_test = %s
|
AND is_fake = %s
|
||||||
""", (is_test,))
|
""", (is_fake,))
|
||||||
phone_available = cur.fetchone()[0]
|
phone_available = cur.fetchone()[0]
|
||||||
|
|
||||||
return jsonify({
|
return jsonify({
|
||||||
@@ -862,7 +862,7 @@ def check_resource_availability():
|
|||||||
ipv4_available >= ipv4_count and
|
ipv4_available >= ipv4_count and
|
||||||
phone_available >= phone_count
|
phone_available >= phone_count
|
||||||
),
|
),
|
||||||
'is_test': is_test
|
'is_fake': is_fake
|
||||||
})
|
})
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ def batch_create():
|
|||||||
valid_from = request.form['valid_from']
|
valid_from = request.form['valid_from']
|
||||||
valid_until = request.form['valid_until']
|
valid_until = request.form['valid_until']
|
||||||
device_limit = int(request.form['device_limit'])
|
device_limit = int(request.form['device_limit'])
|
||||||
is_test = 'is_test' in request.form
|
is_fake = 'is_fake' in request.form
|
||||||
|
|
||||||
# Validierung
|
# Validierung
|
||||||
if count < 1 or count > 100:
|
if count < 1 or count > 100:
|
||||||
@@ -74,13 +74,13 @@ def batch_create():
|
|||||||
INSERT INTO licenses (
|
INSERT INTO licenses (
|
||||||
license_key, customer_id,
|
license_key, customer_id,
|
||||||
license_type, valid_from, valid_until, device_limit,
|
license_type, valid_from, valid_until, device_limit,
|
||||||
is_test, created_at
|
is_fake, created_at
|
||||||
) VALUES (%s, %s, %s, %s, %s, %s, %s, %s)
|
) VALUES (%s, %s, %s, %s, %s, %s, %s, %s)
|
||||||
RETURNING id
|
RETURNING id
|
||||||
""", (
|
""", (
|
||||||
license_key, customer_id,
|
license_key, customer_id,
|
||||||
license_type, valid_from, valid_until, device_limit,
|
license_type, valid_from, valid_until, device_limit,
|
||||||
is_test, datetime.now()
|
is_fake, datetime.now()
|
||||||
))
|
))
|
||||||
|
|
||||||
license_id = cur.fetchone()[0]
|
license_id = cur.fetchone()[0]
|
||||||
@@ -141,7 +141,7 @@ def batch_export():
|
|||||||
SELECT
|
SELECT
|
||||||
l.license_key, c.name, c.email,
|
l.license_key, c.name, c.email,
|
||||||
l.license_type, l.valid_from, l.valid_until,
|
l.license_type, l.valid_from, l.valid_until,
|
||||||
l.device_limit, l.is_test, l.created_at
|
l.device_limit, l.is_fake, l.created_at
|
||||||
FROM licenses l
|
FROM licenses l
|
||||||
JOIN customers c ON l.customer_id = c.id
|
JOIN customers c ON l.customer_id = c.id
|
||||||
WHERE l.id = ANY(%s)
|
WHERE l.id = ANY(%s)
|
||||||
@@ -158,7 +158,7 @@ def batch_export():
|
|||||||
'valid_from': row[4],
|
'valid_from': row[4],
|
||||||
'valid_until': row[5],
|
'valid_until': row[5],
|
||||||
'device_limit': row[6],
|
'device_limit': row[6],
|
||||||
'is_test': row[7],
|
'is_fake': row[7],
|
||||||
'created_at': row[8]
|
'created_at': row[8]
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -334,13 +334,13 @@ def batch_import():
|
|||||||
INSERT INTO licenses (
|
INSERT INTO licenses (
|
||||||
license_key, customer_id,
|
license_key, customer_id,
|
||||||
license_type, valid_from, valid_until, device_limit,
|
license_type, valid_from, valid_until, device_limit,
|
||||||
is_test, created_at
|
is_fake, created_at
|
||||||
) VALUES (%s, %s, %s, %s, %s, %s, %s, %s)
|
) VALUES (%s, %s, %s, %s, %s, %s, %s, %s)
|
||||||
RETURNING id
|
RETURNING id
|
||||||
""", (
|
""", (
|
||||||
license_key, customer_id,
|
license_key, customer_id,
|
||||||
row['license_type'], row['valid_from'], row['valid_until'],
|
row['license_type'], row['valid_from'], row['valid_until'],
|
||||||
int(row['device_limit']), row.get('is_test', False),
|
int(row['device_limit']), row.get('is_fake', False),
|
||||||
datetime.now()
|
datetime.now()
|
||||||
))
|
))
|
||||||
|
|
||||||
|
|||||||
@@ -22,14 +22,14 @@ def test_customers():
|
|||||||
@customer_bp.route("/customers")
|
@customer_bp.route("/customers")
|
||||||
@login_required
|
@login_required
|
||||||
def customers():
|
def customers():
|
||||||
show_test = request.args.get('show_test', 'false').lower() == 'true'
|
show_fake = request.args.get('show_fake', 'false').lower() == 'true'
|
||||||
search = request.args.get('search', '').strip()
|
search = request.args.get('search', '').strip()
|
||||||
page = request.args.get('page', 1, type=int)
|
page = request.args.get('page', 1, type=int)
|
||||||
per_page = 20
|
per_page = 20
|
||||||
sort = request.args.get('sort', 'name')
|
sort = request.args.get('sort', 'name')
|
||||||
order = request.args.get('order', 'asc')
|
order = request.args.get('order', 'asc')
|
||||||
|
|
||||||
customers_list = get_customers(show_test=show_test, search=search)
|
customers_list = get_customers(show_fake=show_fake, search=search)
|
||||||
|
|
||||||
# Sortierung
|
# Sortierung
|
||||||
if sort == 'name':
|
if sort == 'name':
|
||||||
@@ -48,7 +48,7 @@ def customers():
|
|||||||
|
|
||||||
return render_template("customers.html",
|
return render_template("customers.html",
|
||||||
customers=paginated_customers,
|
customers=paginated_customers,
|
||||||
show_test=show_test,
|
show_fake=show_fake,
|
||||||
search=search,
|
search=search,
|
||||||
page=page,
|
page=page,
|
||||||
per_page=per_page,
|
per_page=per_page,
|
||||||
@@ -77,17 +77,17 @@ def edit_customer(customer_id):
|
|||||||
new_values = {
|
new_values = {
|
||||||
'name': request.form['name'],
|
'name': request.form['name'],
|
||||||
'email': request.form['email'],
|
'email': request.form['email'],
|
||||||
'is_test': 'is_test' in request.form
|
'is_fake': 'is_fake' in request.form
|
||||||
}
|
}
|
||||||
|
|
||||||
cur.execute("""
|
cur.execute("""
|
||||||
UPDATE customers
|
UPDATE customers
|
||||||
SET name = %s, email = %s, is_test = %s
|
SET name = %s, email = %s, is_fake = %s
|
||||||
WHERE id = %s
|
WHERE id = %s
|
||||||
""", (
|
""", (
|
||||||
new_values['name'],
|
new_values['name'],
|
||||||
new_values['email'],
|
new_values['email'],
|
||||||
new_values['is_test'],
|
new_values['is_fake'],
|
||||||
customer_id
|
customer_id
|
||||||
))
|
))
|
||||||
|
|
||||||
@@ -98,16 +98,16 @@ def edit_customer(customer_id):
|
|||||||
old_values={
|
old_values={
|
||||||
'name': current_customer['name'],
|
'name': current_customer['name'],
|
||||||
'email': current_customer['email'],
|
'email': current_customer['email'],
|
||||||
'is_test': current_customer.get('is_test', False)
|
'is_fake': current_customer.get('is_fake', False)
|
||||||
},
|
},
|
||||||
new_values=new_values)
|
new_values=new_values)
|
||||||
|
|
||||||
flash('Kunde erfolgreich aktualisiert!', 'success')
|
flash('Kunde erfolgreich aktualisiert!', 'success')
|
||||||
|
|
||||||
# Redirect mit show_test Parameter wenn nötig
|
# Redirect mit show_fake Parameter wenn nötig
|
||||||
redirect_url = url_for('customers.customers_licenses')
|
redirect_url = url_for('customers.customers_licenses')
|
||||||
if request.form.get('show_test') == 'true':
|
if request.form.get('show_fake') == 'true':
|
||||||
redirect_url += '?show_test=true'
|
redirect_url += '?show_fake=true'
|
||||||
return redirect(redirect_url)
|
return redirect(redirect_url)
|
||||||
finally:
|
finally:
|
||||||
cur.close()
|
cur.close()
|
||||||
@@ -137,13 +137,13 @@ def create_customer():
|
|||||||
# Insert new customer
|
# Insert new customer
|
||||||
name = request.form['name']
|
name = request.form['name']
|
||||||
email = request.form['email']
|
email = request.form['email']
|
||||||
is_test = 'is_test' in request.form # Checkbox ist nur vorhanden wenn angekreuzt
|
is_fake = 'is_fake' in request.form # Checkbox ist nur vorhanden wenn angekreuzt
|
||||||
|
|
||||||
cur.execute("""
|
cur.execute("""
|
||||||
INSERT INTO customers (name, email, is_test, created_at)
|
INSERT INTO customers (name, email, is_fake, created_at)
|
||||||
VALUES (%s, %s, %s, %s)
|
VALUES (%s, %s, %s, %s)
|
||||||
RETURNING id
|
RETURNING id
|
||||||
""", (name, email, is_test, datetime.now()))
|
""", (name, email, is_fake, datetime.now()))
|
||||||
|
|
||||||
customer_id = cur.fetchone()[0]
|
customer_id = cur.fetchone()[0]
|
||||||
conn.commit()
|
conn.commit()
|
||||||
@@ -153,17 +153,17 @@ def create_customer():
|
|||||||
new_values={
|
new_values={
|
||||||
'name': name,
|
'name': name,
|
||||||
'email': email,
|
'email': email,
|
||||||
'is_test': is_test
|
'is_fake': is_fake
|
||||||
})
|
})
|
||||||
|
|
||||||
if is_test:
|
if is_fake:
|
||||||
flash(f'Testkunde {name} erfolgreich erstellt!', 'success')
|
flash(f'Fake-Kunde {name} erfolgreich erstellt!', 'success')
|
||||||
else:
|
else:
|
||||||
flash(f'Kunde {name} erfolgreich erstellt!', 'success')
|
flash(f'Kunde {name} erfolgreich erstellt!', 'success')
|
||||||
|
|
||||||
# Redirect mit show_test=true wenn Testkunde erstellt wurde
|
# Redirect mit show_fake=true wenn Fake-Kunde erstellt wurde
|
||||||
if is_test:
|
if is_fake:
|
||||||
return redirect(url_for('customers.customers_licenses', show_test='true'))
|
return redirect(url_for('customers.customers_licenses', show_fake='true'))
|
||||||
else:
|
else:
|
||||||
return redirect(url_for('customers.customers_licenses'))
|
return redirect(url_for('customers.customers_licenses'))
|
||||||
|
|
||||||
@@ -232,9 +232,9 @@ def customers_licenses():
|
|||||||
import psycopg2
|
import psycopg2
|
||||||
logging.info("=== CUSTOMERS-LICENSES ROUTE CALLED ===")
|
logging.info("=== CUSTOMERS-LICENSES ROUTE CALLED ===")
|
||||||
|
|
||||||
# Get show_test parameter from URL
|
# Get show_fake parameter from URL
|
||||||
show_test = request.args.get('show_test', 'false').lower() == 'true'
|
show_fake = request.args.get('show_fake', 'false').lower() == 'true'
|
||||||
logging.info(f"show_test parameter: {show_test}")
|
logging.info(f"show_fake parameter: {show_fake}")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# Direkte Verbindung ohne Helper-Funktionen
|
# Direkte Verbindung ohne Helper-Funktionen
|
||||||
@@ -250,7 +250,7 @@ def customers_licenses():
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
# Hole alle Kunden mit ihren Lizenzen
|
# Hole alle Kunden mit ihren Lizenzen
|
||||||
# Wenn show_test=false, zeige nur Nicht-Test-Kunden
|
# Wenn show_fake=false, zeige nur Nicht-Test-Kunden
|
||||||
query = """
|
query = """
|
||||||
SELECT
|
SELECT
|
||||||
c.id,
|
c.id,
|
||||||
@@ -259,17 +259,17 @@ def customers_licenses():
|
|||||||
c.created_at,
|
c.created_at,
|
||||||
COUNT(l.id),
|
COUNT(l.id),
|
||||||
COUNT(CASE WHEN l.is_active = true THEN 1 END),
|
COUNT(CASE WHEN l.is_active = true THEN 1 END),
|
||||||
COUNT(CASE WHEN l.is_test = true THEN 1 END),
|
COUNT(CASE WHEN l.is_fake = true THEN 1 END),
|
||||||
MAX(l.created_at),
|
MAX(l.created_at),
|
||||||
c.is_test
|
c.is_fake
|
||||||
FROM customers c
|
FROM customers c
|
||||||
LEFT JOIN licenses l ON c.id = l.customer_id
|
LEFT JOIN licenses l ON c.id = l.customer_id
|
||||||
WHERE (%s OR c.is_test = false)
|
WHERE (%s OR c.is_fake = false)
|
||||||
GROUP BY c.id, c.name, c.email, c.created_at, c.is_test
|
GROUP BY c.id, c.name, c.email, c.created_at, c.is_fake
|
||||||
ORDER BY c.name
|
ORDER BY c.name
|
||||||
"""
|
"""
|
||||||
|
|
||||||
cur.execute(query, (show_test,))
|
cur.execute(query, (show_fake,))
|
||||||
|
|
||||||
customers = []
|
customers = []
|
||||||
results = cur.fetchall()
|
results = cur.fetchall()
|
||||||
@@ -286,12 +286,12 @@ def customers_licenses():
|
|||||||
'active_licenses': row[5],
|
'active_licenses': row[5],
|
||||||
'test_licenses': row[6],
|
'test_licenses': row[6],
|
||||||
'last_license_created': row[7],
|
'last_license_created': row[7],
|
||||||
'is_test': row[8]
|
'is_fake': row[8]
|
||||||
})
|
})
|
||||||
|
|
||||||
return render_template("customers_licenses.html",
|
return render_template("customers_licenses.html",
|
||||||
customers=customers,
|
customers=customers,
|
||||||
show_test=show_test)
|
show_fake=show_fake)
|
||||||
|
|
||||||
finally:
|
finally:
|
||||||
cur.close()
|
cur.close()
|
||||||
@@ -325,7 +325,7 @@ def api_customer_licenses(customer_id):
|
|||||||
l.license_key,
|
l.license_key,
|
||||||
l.license_type,
|
l.license_type,
|
||||||
l.is_active,
|
l.is_active,
|
||||||
l.is_test,
|
l.is_fake,
|
||||||
l.valid_from,
|
l.valid_from,
|
||||||
l.valid_until,
|
l.valid_until,
|
||||||
l.device_limit,
|
l.device_limit,
|
||||||
@@ -387,7 +387,7 @@ def api_customer_licenses(customer_id):
|
|||||||
'license_key': row[1],
|
'license_key': row[1],
|
||||||
'license_type': row[2],
|
'license_type': row[2],
|
||||||
'is_active': row[3],
|
'is_active': row[3],
|
||||||
'is_test': row[4],
|
'is_fake': row[4],
|
||||||
'valid_from': row[5].strftime('%Y-%m-%d') if row[5] else None,
|
'valid_from': row[5].strftime('%Y-%m-%d') if row[5] else None,
|
||||||
'valid_until': row[6].strftime('%Y-%m-%d') if row[6] else None,
|
'valid_until': row[6].strftime('%Y-%m-%d') if row[6] else None,
|
||||||
'device_limit': row[7],
|
'device_limit': row[7],
|
||||||
@@ -442,7 +442,7 @@ def api_customer_quick_stats(customer_id):
|
|||||||
SELECT
|
SELECT
|
||||||
COUNT(l.id) as total_licenses,
|
COUNT(l.id) as total_licenses,
|
||||||
COUNT(CASE WHEN l.is_active = true THEN 1 END) as active_licenses,
|
COUNT(CASE WHEN l.is_active = true THEN 1 END) as active_licenses,
|
||||||
COUNT(CASE WHEN l.is_test = true THEN 1 END) as test_licenses,
|
COUNT(CASE WHEN l.is_fake = true THEN 1 END) as test_licenses,
|
||||||
SUM(l.device_limit) as total_device_limit
|
SUM(l.device_limit) as total_device_limit
|
||||||
FROM licenses l
|
FROM licenses l
|
||||||
WHERE l.customer_id = %s
|
WHERE l.customer_id = %s
|
||||||
|
|||||||
@@ -21,10 +21,10 @@ def export_licenses():
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
# Filter aus Request
|
# Filter aus Request
|
||||||
show_test = request.args.get('show_test', 'false') == 'true'
|
show_fake = request.args.get('show_fake', 'false') == 'true'
|
||||||
|
|
||||||
# SQL Query mit optionalem Test-Filter
|
# SQL Query mit optionalem Test-Filter
|
||||||
if show_test:
|
if show_fake:
|
||||||
query = """
|
query = """
|
||||||
SELECT
|
SELECT
|
||||||
l.id,
|
l.id,
|
||||||
@@ -37,7 +37,7 @@ def export_licenses():
|
|||||||
l.is_active,
|
l.is_active,
|
||||||
l.device_limit,
|
l.device_limit,
|
||||||
l.created_at,
|
l.created_at,
|
||||||
l.is_test,
|
l.is_fake,
|
||||||
CASE
|
CASE
|
||||||
WHEN l.valid_until < CURRENT_DATE THEN 'Abgelaufen'
|
WHEN l.valid_until < CURRENT_DATE THEN 'Abgelaufen'
|
||||||
WHEN l.is_active = false THEN 'Deaktiviert'
|
WHEN l.is_active = false THEN 'Deaktiviert'
|
||||||
@@ -62,7 +62,7 @@ def export_licenses():
|
|||||||
l.is_active,
|
l.is_active,
|
||||||
l.device_limit,
|
l.device_limit,
|
||||||
l.created_at,
|
l.created_at,
|
||||||
l.is_test,
|
l.is_fake,
|
||||||
CASE
|
CASE
|
||||||
WHEN l.valid_until < CURRENT_DATE THEN 'Abgelaufen'
|
WHEN l.valid_until < CURRENT_DATE THEN 'Abgelaufen'
|
||||||
WHEN l.is_active = false THEN 'Deaktiviert'
|
WHEN l.is_active = false THEN 'Deaktiviert'
|
||||||
@@ -72,7 +72,7 @@ def export_licenses():
|
|||||||
(SELECT COUNT(DISTINCT hardware_id) FROM sessions s WHERE s.license_key = l.license_key) as registered_devices
|
(SELECT COUNT(DISTINCT hardware_id) FROM sessions s WHERE s.license_key = l.license_key) as registered_devices
|
||||||
FROM licenses l
|
FROM licenses l
|
||||||
LEFT JOIN customers c ON l.customer_id = c.id
|
LEFT JOIN customers c ON l.customer_id = c.id
|
||||||
WHERE l.is_test = false
|
WHERE l.is_fake = false
|
||||||
ORDER BY l.created_at DESC
|
ORDER BY l.created_at DESC
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@@ -81,7 +81,7 @@ def export_licenses():
|
|||||||
# Daten für Export vorbereiten
|
# Daten für Export vorbereiten
|
||||||
data = []
|
data = []
|
||||||
columns = ['ID', 'Lizenzschlüssel', 'Kunde', 'E-Mail', 'Typ', 'Gültig von',
|
columns = ['ID', 'Lizenzschlüssel', 'Kunde', 'E-Mail', 'Typ', 'Gültig von',
|
||||||
'Gültig bis', 'Aktiv', 'Gerätelimit', 'Erstellt am', 'Test-Lizenz',
|
'Gültig bis', 'Aktiv', 'Gerätelimit', 'Erstellt am', 'Fake-Lizenz',
|
||||||
'Status', 'Aktive Sessions', 'Registrierte Geräte']
|
'Status', 'Aktive Sessions', 'Registrierte Geräte']
|
||||||
|
|
||||||
for row in cur.fetchall():
|
for row in cur.fetchall():
|
||||||
@@ -163,13 +163,13 @@ def export_customers():
|
|||||||
c.phone,
|
c.phone,
|
||||||
c.address,
|
c.address,
|
||||||
c.created_at,
|
c.created_at,
|
||||||
c.is_test,
|
c.is_fake,
|
||||||
COUNT(l.id) as license_count,
|
COUNT(l.id) as license_count,
|
||||||
COUNT(CASE WHEN l.is_active = true THEN 1 END) as active_licenses,
|
COUNT(CASE WHEN l.is_active = true THEN 1 END) as active_licenses,
|
||||||
COUNT(CASE WHEN l.valid_until < CURRENT_DATE THEN 1 END) as expired_licenses
|
COUNT(CASE WHEN l.valid_until < CURRENT_DATE THEN 1 END) as expired_licenses
|
||||||
FROM customers c
|
FROM customers c
|
||||||
LEFT JOIN licenses l ON c.id = l.customer_id
|
LEFT JOIN licenses l ON c.id = l.customer_id
|
||||||
GROUP BY c.id, c.name, c.email, c.phone, c.address, c.created_at, c.is_test
|
GROUP BY c.id, c.name, c.email, c.phone, c.address, c.created_at, c.is_fake
|
||||||
ORDER BY c.name
|
ORDER BY c.name
|
||||||
""")
|
""")
|
||||||
|
|
||||||
@@ -227,7 +227,7 @@ def export_sessions():
|
|||||||
s.last_heartbeat,
|
s.last_heartbeat,
|
||||||
s.is_active,
|
s.is_active,
|
||||||
l.license_type,
|
l.license_type,
|
||||||
l.is_test
|
l.is_fake
|
||||||
FROM sessions s
|
FROM sessions s
|
||||||
LEFT JOIN licenses l ON s.license_key = l.license_key
|
LEFT JOIN licenses l ON s.license_key = l.license_key
|
||||||
WHERE s.is_active = true
|
WHERE s.is_active = true
|
||||||
@@ -247,7 +247,7 @@ def export_sessions():
|
|||||||
s.last_heartbeat,
|
s.last_heartbeat,
|
||||||
s.is_active,
|
s.is_active,
|
||||||
l.license_type,
|
l.license_type,
|
||||||
l.is_test
|
l.is_fake
|
||||||
FROM sessions s
|
FROM sessions s
|
||||||
LEFT JOIN licenses l ON s.license_key = l.license_key
|
LEFT JOIN licenses l ON s.license_key = l.license_key
|
||||||
WHERE s.started_at >= CURRENT_TIMESTAMP - INTERVAL '%s days'
|
WHERE s.started_at >= CURRENT_TIMESTAMP - INTERVAL '%s days'
|
||||||
@@ -259,7 +259,7 @@ def export_sessions():
|
|||||||
data = []
|
data = []
|
||||||
columns = ['ID', 'Lizenzschlüssel', 'Kunde', 'Benutzer', 'Geräte-ID',
|
columns = ['ID', 'Lizenzschlüssel', 'Kunde', 'Benutzer', 'Geräte-ID',
|
||||||
'Login-Zeit', 'Logout-Zeit', 'Letzte Aktivität', 'Aktiv',
|
'Login-Zeit', 'Logout-Zeit', 'Letzte Aktivität', 'Aktiv',
|
||||||
'Lizenztyp', 'Test-Lizenz']
|
'Lizenztyp', 'Fake-Lizenz']
|
||||||
|
|
||||||
for row in cur.fetchall():
|
for row in cur.fetchall():
|
||||||
data.append(list(row))
|
data.append(list(row))
|
||||||
@@ -295,7 +295,7 @@ def export_resources():
|
|||||||
# Filter aus Request
|
# Filter aus Request
|
||||||
resource_type = request.args.get('type', 'all')
|
resource_type = request.args.get('type', 'all')
|
||||||
status_filter = request.args.get('status', 'all')
|
status_filter = request.args.get('status', 'all')
|
||||||
show_test = request.args.get('show_test', 'false') == 'true'
|
show_fake = request.args.get('show_fake', 'false') == 'true'
|
||||||
|
|
||||||
# SQL Query aufbauen
|
# SQL Query aufbauen
|
||||||
query = """
|
query = """
|
||||||
@@ -304,7 +304,7 @@ def export_resources():
|
|||||||
rp.resource_type,
|
rp.resource_type,
|
||||||
rp.resource_value,
|
rp.resource_value,
|
||||||
rp.status,
|
rp.status,
|
||||||
rp.is_test,
|
rp.is_fake,
|
||||||
l.license_key,
|
l.license_key,
|
||||||
c.name as customer_name,
|
c.name as customer_name,
|
||||||
rp.created_at,
|
rp.created_at,
|
||||||
@@ -328,8 +328,8 @@ def export_resources():
|
|||||||
query += " AND rp.status = %s"
|
query += " AND rp.status = %s"
|
||||||
params.append(status_filter)
|
params.append(status_filter)
|
||||||
|
|
||||||
if not show_test:
|
if not show_fake:
|
||||||
query += " AND rp.is_test = false"
|
query += " AND rp.is_fake = false"
|
||||||
|
|
||||||
query += " ORDER BY rp.resource_type, rp.resource_value"
|
query += " ORDER BY rp.resource_type, rp.resource_value"
|
||||||
|
|
||||||
|
|||||||
@@ -24,43 +24,47 @@ def licenses():
|
|||||||
|
|
||||||
# Get filter parameters
|
# Get filter parameters
|
||||||
search = request.args.get('search', '').strip()
|
search = request.args.get('search', '').strip()
|
||||||
filter_type = request.args.get('type', '')
|
filter_types = request.args.getlist('types[]') # Multi-select for types
|
||||||
filter_status = request.args.get('status', '')
|
filter_statuses = request.args.getlist('statuses[]') # Multi-select for statuses
|
||||||
sort = request.args.get('sort', 'created_at')
|
sort = request.args.get('sort', 'created_at')
|
||||||
order = request.args.get('order', 'desc')
|
order = request.args.get('order', 'desc')
|
||||||
page = request.args.get('page', 1, type=int)
|
page = request.args.get('page', 1, type=int)
|
||||||
per_page = 50
|
per_page = 50
|
||||||
|
|
||||||
# Process type filter to determine show_test
|
# Get all licenses (both fake and real data)
|
||||||
# Default: show only real data unless test_data is explicitly selected
|
licenses_list = get_licenses(show_fake=True)
|
||||||
show_test = filter_type == 'test_data'
|
|
||||||
|
|
||||||
# Get licenses based on filters
|
# Type filtering with OR logic
|
||||||
licenses_list = get_licenses(show_test=show_test)
|
if filter_types:
|
||||||
|
filtered_by_type = []
|
||||||
|
for license in licenses_list:
|
||||||
|
# Check if license matches any selected type
|
||||||
|
if 'full' in filter_types and license.get('license_type') == 'full' and not license.get('is_fake'):
|
||||||
|
filtered_by_type.append(license)
|
||||||
|
elif 'test' in filter_types and license.get('license_type') == 'test' and not license.get('is_fake'):
|
||||||
|
filtered_by_type.append(license)
|
||||||
|
licenses_list = filtered_by_type
|
||||||
|
else:
|
||||||
|
# If no types selected, show only real data by default
|
||||||
|
licenses_list = [l for l in licenses_list if not l.get('is_fake')]
|
||||||
|
|
||||||
# Additional filtering based on type and status
|
# Status filtering with OR logic
|
||||||
if filter_type:
|
if filter_statuses:
|
||||||
if filter_type == 'full':
|
|
||||||
licenses_list = [l for l in licenses_list if l.get('license_type') == 'full' and not l.get('is_test')]
|
|
||||||
elif filter_type == 'test':
|
|
||||||
licenses_list = [l for l in licenses_list if l.get('license_type') == 'test' and not l.get('is_test')]
|
|
||||||
elif filter_type == 'test_data':
|
|
||||||
licenses_list = [l for l in licenses_list if l.get('is_test')]
|
|
||||||
elif filter_type == 'live_data':
|
|
||||||
licenses_list = [l for l in licenses_list if not l.get('is_test')]
|
|
||||||
|
|
||||||
# Status filtering
|
|
||||||
if filter_status:
|
|
||||||
now = datetime.now()
|
now = datetime.now()
|
||||||
if filter_status == 'active':
|
filtered_by_status = []
|
||||||
licenses_list = [l for l in licenses_list if l.get('is_active') and l.get('valid_until') and l.get('valid_until') > now]
|
for license in licenses_list:
|
||||||
elif filter_status == 'expiring':
|
# Check if license matches any selected status
|
||||||
|
if 'active' in filter_statuses and license.get('is_active') and license.get('valid_until') and license.get('valid_until') > now:
|
||||||
|
filtered_by_status.append(license)
|
||||||
|
elif 'expiring' in filter_statuses:
|
||||||
expiry_threshold = now + timedelta(days=30)
|
expiry_threshold = now + timedelta(days=30)
|
||||||
licenses_list = [l for l in licenses_list if l.get('valid_until') and now < l.get('valid_until') <= expiry_threshold]
|
if license.get('valid_until') and now < license.get('valid_until') <= expiry_threshold:
|
||||||
elif filter_status == 'expired':
|
filtered_by_status.append(license)
|
||||||
licenses_list = [l for l in licenses_list if l.get('valid_until') and l.get('valid_until') <= now]
|
elif 'expired' in filter_statuses and license.get('valid_until') and license.get('valid_until') <= now:
|
||||||
elif filter_status == 'inactive':
|
filtered_by_status.append(license)
|
||||||
licenses_list = [l for l in licenses_list if not l.get('is_active')]
|
elif 'inactive' in filter_statuses and not license.get('is_active'):
|
||||||
|
filtered_by_status.append(license)
|
||||||
|
licenses_list = filtered_by_status
|
||||||
|
|
||||||
# Search filtering
|
# Search filtering
|
||||||
if search:
|
if search:
|
||||||
@@ -79,10 +83,9 @@ def licenses():
|
|||||||
|
|
||||||
return render_template("licenses.html",
|
return render_template("licenses.html",
|
||||||
licenses=licenses_list,
|
licenses=licenses_list,
|
||||||
show_test=show_test,
|
|
||||||
search=search,
|
search=search,
|
||||||
filter_type=filter_type,
|
filter_types=filter_types,
|
||||||
filter_status=filter_status,
|
filter_statuses=filter_statuses,
|
||||||
sort=sort,
|
sort=sort,
|
||||||
order=order,
|
order=order,
|
||||||
page=page,
|
page=page,
|
||||||
@@ -114,14 +117,14 @@ def edit_license(license_id):
|
|||||||
'valid_from': request.form['valid_from'],
|
'valid_from': request.form['valid_from'],
|
||||||
'valid_until': request.form['valid_until'],
|
'valid_until': request.form['valid_until'],
|
||||||
'is_active': 'is_active' in request.form,
|
'is_active': 'is_active' in request.form,
|
||||||
'is_test': 'is_test' in request.form,
|
'is_fake': 'is_fake' in request.form,
|
||||||
'device_limit': int(request.form.get('device_limit', 3))
|
'device_limit': int(request.form.get('device_limit', 3))
|
||||||
}
|
}
|
||||||
|
|
||||||
cur.execute("""
|
cur.execute("""
|
||||||
UPDATE licenses
|
UPDATE licenses
|
||||||
SET license_key = %s, license_type = %s, valid_from = %s,
|
SET license_key = %s, license_type = %s, valid_from = %s,
|
||||||
valid_until = %s, is_active = %s, is_test = %s, device_limit = %s
|
valid_until = %s, is_active = %s, is_fake = %s, device_limit = %s
|
||||||
WHERE id = %s
|
WHERE id = %s
|
||||||
""", (
|
""", (
|
||||||
new_values['license_key'],
|
new_values['license_key'],
|
||||||
@@ -129,7 +132,7 @@ def edit_license(license_id):
|
|||||||
new_values['valid_from'],
|
new_values['valid_from'],
|
||||||
new_values['valid_until'],
|
new_values['valid_until'],
|
||||||
new_values['is_active'],
|
new_values['is_active'],
|
||||||
new_values['is_test'],
|
new_values['is_fake'],
|
||||||
new_values['device_limit'],
|
new_values['device_limit'],
|
||||||
license_id
|
license_id
|
||||||
))
|
))
|
||||||
@@ -144,7 +147,7 @@ def edit_license(license_id):
|
|||||||
'valid_from': str(current_license.get('valid_from', '')),
|
'valid_from': str(current_license.get('valid_from', '')),
|
||||||
'valid_until': str(current_license.get('valid_until', '')),
|
'valid_until': str(current_license.get('valid_until', '')),
|
||||||
'is_active': current_license.get('is_active'),
|
'is_active': current_license.get('is_active'),
|
||||||
'is_test': current_license.get('is_test'),
|
'is_fake': current_license.get('is_fake'),
|
||||||
'device_limit': current_license.get('device_limit', 3)
|
'device_limit': current_license.get('device_limit', 3)
|
||||||
},
|
},
|
||||||
new_values=new_values)
|
new_values=new_values)
|
||||||
@@ -283,7 +286,7 @@ def create_license():
|
|||||||
license_key = request.form["license_key"].upper() # Immer Großbuchstaben
|
license_key = request.form["license_key"].upper() # Immer Großbuchstaben
|
||||||
license_type = request.form["license_type"]
|
license_type = request.form["license_type"]
|
||||||
valid_from = request.form["valid_from"]
|
valid_from = request.form["valid_from"]
|
||||||
is_test = request.form.get("is_test") == "on" # Checkbox value
|
is_fake = request.form.get("is_fake") == "on" # Checkbox value
|
||||||
|
|
||||||
# Berechne valid_until basierend auf Laufzeit
|
# Berechne valid_until basierend auf Laufzeit
|
||||||
duration = int(request.form.get("duration", 1))
|
duration = int(request.form.get("duration", 1))
|
||||||
@@ -337,19 +340,19 @@ def create_license():
|
|||||||
|
|
||||||
# Kunde einfügen (erbt Test-Status von Lizenz)
|
# Kunde einfügen (erbt Test-Status von Lizenz)
|
||||||
cur.execute("""
|
cur.execute("""
|
||||||
INSERT INTO customers (name, email, is_test, created_at)
|
INSERT INTO customers (name, email, is_fake, created_at)
|
||||||
VALUES (%s, %s, %s, NOW())
|
VALUES (%s, %s, %s, NOW())
|
||||||
RETURNING id
|
RETURNING id
|
||||||
""", (name, email, is_test))
|
""", (name, email, is_fake))
|
||||||
customer_id = cur.fetchone()[0]
|
customer_id = cur.fetchone()[0]
|
||||||
customer_info = {'name': name, 'email': email, 'is_test': is_test}
|
customer_info = {'name': name, 'email': email, 'is_fake': is_fake}
|
||||||
|
|
||||||
# Audit-Log für neuen Kunden
|
# Audit-Log für neuen Kunden
|
||||||
log_audit('CREATE', 'customer', customer_id,
|
log_audit('CREATE', 'customer', customer_id,
|
||||||
new_values={'name': name, 'email': email, 'is_test': is_test})
|
new_values={'name': name, 'email': email, 'is_fake': is_fake})
|
||||||
else:
|
else:
|
||||||
# Bestehender Kunde - hole Infos für Audit-Log
|
# Bestehender Kunde - hole Infos für Audit-Log
|
||||||
cur.execute("SELECT name, email, is_test FROM customers WHERE id = %s", (customer_id,))
|
cur.execute("SELECT name, email, is_fake FROM customers WHERE id = %s", (customer_id,))
|
||||||
customer_data = cur.fetchone()
|
customer_data = cur.fetchone()
|
||||||
if not customer_data:
|
if not customer_data:
|
||||||
flash('Kunde nicht gefunden!', 'error')
|
flash('Kunde nicht gefunden!', 'error')
|
||||||
@@ -357,17 +360,17 @@ def create_license():
|
|||||||
customer_info = {'name': customer_data[0], 'email': customer_data[1]}
|
customer_info = {'name': customer_data[0], 'email': customer_data[1]}
|
||||||
|
|
||||||
# Wenn Kunde Test-Kunde ist, Lizenz auch als Test markieren
|
# Wenn Kunde Test-Kunde ist, Lizenz auch als Test markieren
|
||||||
if customer_data[2]: # is_test des Kunden
|
if customer_data[2]: # is_fake des Kunden
|
||||||
is_test = True
|
is_fake = True
|
||||||
|
|
||||||
# Lizenz hinzufügen
|
# Lizenz hinzufügen
|
||||||
cur.execute("""
|
cur.execute("""
|
||||||
INSERT INTO licenses (license_key, customer_id, license_type, valid_from, valid_until, is_active,
|
INSERT INTO licenses (license_key, customer_id, license_type, valid_from, valid_until, is_active,
|
||||||
domain_count, ipv4_count, phone_count, device_limit, is_test)
|
domain_count, ipv4_count, phone_count, device_limit, is_fake)
|
||||||
VALUES (%s, %s, %s, %s, %s, TRUE, %s, %s, %s, %s, %s)
|
VALUES (%s, %s, %s, %s, %s, TRUE, %s, %s, %s, %s, %s)
|
||||||
RETURNING id
|
RETURNING id
|
||||||
""", (license_key, customer_id, license_type, valid_from, valid_until,
|
""", (license_key, customer_id, license_type, valid_from, valid_until,
|
||||||
domain_count, ipv4_count, phone_count, device_limit, is_test))
|
domain_count, ipv4_count, phone_count, device_limit, is_fake))
|
||||||
license_id = cur.fetchone()[0]
|
license_id = cur.fetchone()[0]
|
||||||
|
|
||||||
# Ressourcen zuweisen
|
# Ressourcen zuweisen
|
||||||
@@ -375,10 +378,10 @@ def create_license():
|
|||||||
# Prüfe Verfügbarkeit
|
# Prüfe Verfügbarkeit
|
||||||
cur.execute("""
|
cur.execute("""
|
||||||
SELECT
|
SELECT
|
||||||
(SELECT COUNT(*) FROM resource_pools WHERE resource_type = 'domain' AND status = 'available' AND is_test = %s) as domains,
|
(SELECT COUNT(*) FROM resource_pools WHERE resource_type = 'domain' AND status = 'available' AND is_fake = %s) as domains,
|
||||||
(SELECT COUNT(*) FROM resource_pools WHERE resource_type = 'ipv4' AND status = 'available' AND is_test = %s) as ipv4s,
|
(SELECT COUNT(*) FROM resource_pools WHERE resource_type = 'ipv4' AND status = 'available' AND is_fake = %s) as ipv4s,
|
||||||
(SELECT COUNT(*) FROM resource_pools WHERE resource_type = 'phone' AND status = 'available' AND is_test = %s) as phones
|
(SELECT COUNT(*) FROM resource_pools WHERE resource_type = 'phone' AND status = 'available' AND is_fake = %s) as phones
|
||||||
""", (is_test, is_test, is_test))
|
""", (is_fake, is_fake, is_fake))
|
||||||
available = cur.fetchone()
|
available = cur.fetchone()
|
||||||
|
|
||||||
if available[0] < domain_count:
|
if available[0] < domain_count:
|
||||||
@@ -392,9 +395,9 @@ def create_license():
|
|||||||
if domain_count > 0:
|
if domain_count > 0:
|
||||||
cur.execute("""
|
cur.execute("""
|
||||||
SELECT id FROM resource_pools
|
SELECT id FROM resource_pools
|
||||||
WHERE resource_type = 'domain' AND status = 'available' AND is_test = %s
|
WHERE resource_type = 'domain' AND status = 'available' AND is_fake = %s
|
||||||
LIMIT %s FOR UPDATE
|
LIMIT %s FOR UPDATE
|
||||||
""", (is_test, domain_count))
|
""", (is_fake, domain_count))
|
||||||
for (resource_id,) in cur.fetchall():
|
for (resource_id,) in cur.fetchall():
|
||||||
cur.execute("""
|
cur.execute("""
|
||||||
UPDATE resource_pools
|
UPDATE resource_pools
|
||||||
@@ -417,9 +420,9 @@ def create_license():
|
|||||||
if ipv4_count > 0:
|
if ipv4_count > 0:
|
||||||
cur.execute("""
|
cur.execute("""
|
||||||
SELECT id FROM resource_pools
|
SELECT id FROM resource_pools
|
||||||
WHERE resource_type = 'ipv4' AND status = 'available' AND is_test = %s
|
WHERE resource_type = 'ipv4' AND status = 'available' AND is_fake = %s
|
||||||
LIMIT %s FOR UPDATE
|
LIMIT %s FOR UPDATE
|
||||||
""", (is_test, ipv4_count))
|
""", (is_fake, ipv4_count))
|
||||||
for (resource_id,) in cur.fetchall():
|
for (resource_id,) in cur.fetchall():
|
||||||
cur.execute("""
|
cur.execute("""
|
||||||
UPDATE resource_pools
|
UPDATE resource_pools
|
||||||
@@ -442,9 +445,9 @@ def create_license():
|
|||||||
if phone_count > 0:
|
if phone_count > 0:
|
||||||
cur.execute("""
|
cur.execute("""
|
||||||
SELECT id FROM resource_pools
|
SELECT id FROM resource_pools
|
||||||
WHERE resource_type = 'phone' AND status = 'available' AND is_test = %s
|
WHERE resource_type = 'phone' AND status = 'available' AND is_fake = %s
|
||||||
LIMIT %s FOR UPDATE
|
LIMIT %s FOR UPDATE
|
||||||
""", (is_test, phone_count))
|
""", (is_fake, phone_count))
|
||||||
for (resource_id,) in cur.fetchall():
|
for (resource_id,) in cur.fetchall():
|
||||||
cur.execute("""
|
cur.execute("""
|
||||||
UPDATE resource_pools
|
UPDATE resource_pools
|
||||||
@@ -480,7 +483,7 @@ def create_license():
|
|||||||
'valid_from': valid_from,
|
'valid_from': valid_from,
|
||||||
'valid_until': valid_until,
|
'valid_until': valid_until,
|
||||||
'device_limit': device_limit,
|
'device_limit': device_limit,
|
||||||
'is_test': is_test
|
'is_fake': is_fake
|
||||||
})
|
})
|
||||||
|
|
||||||
flash(f'Lizenz {license_key} erfolgreich erstellt!', 'success')
|
flash(f'Lizenz {license_key} erfolgreich erstellt!', 'success')
|
||||||
|
|||||||
@@ -28,9 +28,9 @@ def resources():
|
|||||||
resource_type = request.args.get('type', 'all')
|
resource_type = request.args.get('type', 'all')
|
||||||
status_filter = request.args.get('status', 'all')
|
status_filter = request.args.get('status', 'all')
|
||||||
search_query = request.args.get('search', '')
|
search_query = request.args.get('search', '')
|
||||||
show_test = request.args.get('show_test', 'false') == 'true'
|
show_fake = request.args.get('show_fake', 'false') == 'true'
|
||||||
|
|
||||||
logging.info(f"Filters: type={resource_type}, status={status_filter}, search={search_query}, show_test={show_test}")
|
logging.info(f"Filters: type={resource_type}, status={status_filter}, search={search_query}, show_fake={show_fake}")
|
||||||
|
|
||||||
# Basis-Query
|
# Basis-Query
|
||||||
query = """
|
query = """
|
||||||
@@ -39,7 +39,7 @@ def resources():
|
|||||||
rp.resource_type,
|
rp.resource_type,
|
||||||
rp.resource_value,
|
rp.resource_value,
|
||||||
rp.status,
|
rp.status,
|
||||||
rp.is_test,
|
rp.is_fake,
|
||||||
rp.allocated_to_license,
|
rp.allocated_to_license,
|
||||||
rp.created_at,
|
rp.created_at,
|
||||||
rp.status_changed_at,
|
rp.status_changed_at,
|
||||||
@@ -67,8 +67,8 @@ def resources():
|
|||||||
query += " AND (rp.resource_value ILIKE %s OR c.name ILIKE %s)"
|
query += " AND (rp.resource_value ILIKE %s OR c.name ILIKE %s)"
|
||||||
params.extend([f'%{search_query}%', f'%{search_query}%'])
|
params.extend([f'%{search_query}%', f'%{search_query}%'])
|
||||||
|
|
||||||
if not show_test:
|
if not show_fake:
|
||||||
query += " AND rp.is_test = false"
|
query += " AND rp.is_fake = false"
|
||||||
|
|
||||||
query += " ORDER BY rp.resource_type, rp.resource_value"
|
query += " ORDER BY rp.resource_type, rp.resource_value"
|
||||||
|
|
||||||
@@ -84,7 +84,7 @@ def resources():
|
|||||||
'resource_type': row[1],
|
'resource_type': row[1],
|
||||||
'resource_value': row[2],
|
'resource_value': row[2],
|
||||||
'status': row[3],
|
'status': row[3],
|
||||||
'is_test': row[4],
|
'is_fake': row[4],
|
||||||
'allocated_to_license': row[5],
|
'allocated_to_license': row[5],
|
||||||
'created_at': row[6],
|
'created_at': row[6],
|
||||||
'status_changed_at': row[7],
|
'status_changed_at': row[7],
|
||||||
@@ -98,16 +98,16 @@ def resources():
|
|||||||
SELECT
|
SELECT
|
||||||
resource_type,
|
resource_type,
|
||||||
status,
|
status,
|
||||||
is_test,
|
is_fake,
|
||||||
COUNT(*) as count
|
COUNT(*) as count
|
||||||
FROM resource_pools
|
FROM resource_pools
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# Apply test filter to statistics as well
|
# Apply test filter to statistics as well
|
||||||
if not show_test:
|
if not show_fake:
|
||||||
stats_query += " WHERE is_test = false"
|
stats_query += " WHERE is_fake = false"
|
||||||
|
|
||||||
stats_query += " GROUP BY resource_type, status, is_test"
|
stats_query += " GROUP BY resource_type, status, is_fake"
|
||||||
|
|
||||||
cur.execute(stats_query)
|
cur.execute(stats_query)
|
||||||
|
|
||||||
@@ -115,7 +115,7 @@ def resources():
|
|||||||
for row in cur.fetchall():
|
for row in cur.fetchall():
|
||||||
res_type = row[0]
|
res_type = row[0]
|
||||||
status = row[1]
|
status = row[1]
|
||||||
is_test = row[2]
|
is_fake = row[2]
|
||||||
count = row[3]
|
count = row[3]
|
||||||
|
|
||||||
if res_type not in stats:
|
if res_type not in stats:
|
||||||
@@ -131,7 +131,7 @@ def resources():
|
|||||||
|
|
||||||
stats[res_type]['total'] += count
|
stats[res_type]['total'] += count
|
||||||
stats[res_type][status] = stats[res_type].get(status, 0) + count
|
stats[res_type][status] = stats[res_type].get(status, 0) + count
|
||||||
if is_test:
|
if is_fake:
|
||||||
stats[res_type]['test'] += count
|
stats[res_type]['test'] += count
|
||||||
else:
|
else:
|
||||||
stats[res_type]['prod'] += count
|
stats[res_type]['prod'] += count
|
||||||
@@ -160,7 +160,7 @@ def resources():
|
|||||||
resource_type=resource_type,
|
resource_type=resource_type,
|
||||||
status_filter=status_filter,
|
status_filter=status_filter,
|
||||||
search=search_query, # Changed from search_query to search
|
search=search_query, # Changed from search_query to search
|
||||||
show_test=show_test,
|
show_fake=show_fake,
|
||||||
total=total,
|
total=total,
|
||||||
page=page,
|
page=page,
|
||||||
total_pages=total_pages,
|
total_pages=total_pages,
|
||||||
@@ -325,7 +325,7 @@ def resource_history(resource_id):
|
|||||||
try:
|
try:
|
||||||
# Hole Ressourcen-Info
|
# Hole Ressourcen-Info
|
||||||
cur.execute("""
|
cur.execute("""
|
||||||
SELECT resource_type, resource_value, status, is_test
|
SELECT resource_type, resource_value, status, is_fake
|
||||||
FROM resource_pools WHERE id = %s
|
FROM resource_pools WHERE id = %s
|
||||||
""", (resource_id,))
|
""", (resource_id,))
|
||||||
resource = cur.fetchone()
|
resource = cur.fetchone()
|
||||||
@@ -369,7 +369,7 @@ def resource_history(resource_id):
|
|||||||
'type': resource[0],
|
'type': resource[0],
|
||||||
'value': resource[1],
|
'value': resource[1],
|
||||||
'status': resource[2],
|
'status': resource[2],
|
||||||
'is_test': resource[3]
|
'is_fake': resource[3]
|
||||||
},
|
},
|
||||||
history=history)
|
history=history)
|
||||||
|
|
||||||
@@ -395,10 +395,10 @@ def resource_metrics():
|
|||||||
SELECT
|
SELECT
|
||||||
resource_type,
|
resource_type,
|
||||||
status,
|
status,
|
||||||
is_test,
|
is_fake,
|
||||||
COUNT(*) as count
|
COUNT(*) as count
|
||||||
FROM resource_pools
|
FROM resource_pools
|
||||||
GROUP BY resource_type, status, is_test
|
GROUP BY resource_type, status, is_fake
|
||||||
ORDER BY resource_type, status
|
ORDER BY resource_type, status
|
||||||
""")
|
""")
|
||||||
|
|
||||||
@@ -539,8 +539,8 @@ def resources_report():
|
|||||||
COUNT(CASE WHEN status = 'available' THEN 1 END) as available,
|
COUNT(CASE WHEN status = 'available' THEN 1 END) as available,
|
||||||
COUNT(CASE WHEN status = 'allocated' THEN 1 END) as allocated,
|
COUNT(CASE WHEN status = 'allocated' THEN 1 END) as allocated,
|
||||||
COUNT(CASE WHEN status = 'quarantined' THEN 1 END) as quarantined,
|
COUNT(CASE WHEN status = 'quarantined' THEN 1 END) as quarantined,
|
||||||
COUNT(CASE WHEN is_test = true THEN 1 END) as test,
|
COUNT(CASE WHEN is_fake = true THEN 1 END) as test,
|
||||||
COUNT(CASE WHEN is_test = false THEN 1 END) as production
|
COUNT(CASE WHEN is_fake = false THEN 1 END) as production
|
||||||
FROM resource_pools
|
FROM resource_pools
|
||||||
GROUP BY resource_type
|
GROUP BY resource_type
|
||||||
ORDER BY resource_type
|
ORDER BY resource_type
|
||||||
@@ -566,7 +566,7 @@ def resources_report():
|
|||||||
rp.resource_type,
|
rp.resource_type,
|
||||||
rp.resource_value,
|
rp.resource_value,
|
||||||
rp.status,
|
rp.status,
|
||||||
rp.is_test,
|
rp.is_fake,
|
||||||
c.name as customer_name,
|
c.name as customer_name,
|
||||||
l.license_key,
|
l.license_key,
|
||||||
rp.status_changed_at,
|
rp.status_changed_at,
|
||||||
@@ -628,7 +628,7 @@ def add_resources():
|
|||||||
try:
|
try:
|
||||||
resource_type = request.form.get('resource_type')
|
resource_type = request.form.get('resource_type')
|
||||||
resources_text = request.form.get('resources_text', '')
|
resources_text = request.form.get('resources_text', '')
|
||||||
is_test = request.form.get('is_test', 'false') == 'true'
|
is_fake = request.form.get('is_fake', 'false') == 'true'
|
||||||
|
|
||||||
if not resource_type or not resources_text.strip():
|
if not resource_type or not resources_text.strip():
|
||||||
flash('Bitte Ressourcentyp und Ressourcen angeben!', 'error')
|
flash('Bitte Ressourcentyp und Ressourcen angeben!', 'error')
|
||||||
@@ -686,9 +686,9 @@ def add_resources():
|
|||||||
for resource in new_resources:
|
for resource in new_resources:
|
||||||
cur.execute("""
|
cur.execute("""
|
||||||
INSERT INTO resource_pools
|
INSERT INTO resource_pools
|
||||||
(resource_type, resource_value, status, is_test, created_by)
|
(resource_type, resource_value, status, is_fake, created_by)
|
||||||
VALUES (%s, %s, 'available', %s, %s)
|
VALUES (%s, %s, 'available', %s, %s)
|
||||||
""", (resource_type, resource, is_test, session['username']))
|
""", (resource_type, resource, is_fake, session['username']))
|
||||||
added_count += 1
|
added_count += 1
|
||||||
|
|
||||||
conn.commit()
|
conn.commit()
|
||||||
@@ -706,7 +706,7 @@ def add_resources():
|
|||||||
if invalid_resources:
|
if invalid_resources:
|
||||||
flash(f'❌ {len(invalid_resources)} ungültige Ressourcen wurden ignoriert.', 'error')
|
flash(f'❌ {len(invalid_resources)} ungültige Ressourcen wurden ignoriert.', 'error')
|
||||||
|
|
||||||
return redirect(url_for('resources.resources', show_test=request.form.get('show_test', 'false')))
|
return redirect(url_for('resources.resources', show_fake=request.form.get('show_fake', 'false')))
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
conn.rollback()
|
conn.rollback()
|
||||||
@@ -717,5 +717,5 @@ def add_resources():
|
|||||||
conn.close()
|
conn.close()
|
||||||
|
|
||||||
# GET request - show form
|
# GET request - show form
|
||||||
show_test = request.args.get('show_test', 'false') == 'true'
|
show_fake = request.args.get('show_fake', 'false') == 'true'
|
||||||
return render_template('add_resources.html', show_test=show_test)
|
return render_template('add_resources.html', show_fake=show_fake)
|
||||||
@@ -175,9 +175,9 @@
|
|||||||
|
|
||||||
<!-- Test Data Checkbox -->
|
<!-- Test Data Checkbox -->
|
||||||
<div class="form-check mt-3">
|
<div class="form-check mt-3">
|
||||||
<input class="form-check-input" type="checkbox" id="isTest" name="is_test">
|
<input class="form-check-input" type="checkbox" id="isFake" name="is_fake">
|
||||||
<label class="form-check-label" for="isTest">
|
<label class="form-check-label" for="isFake">
|
||||||
<i class="fas fa-flask"></i> Als Testdaten markieren
|
<i class="fas fa-flask"></i> Als Fake-Daten markieren
|
||||||
<small class="text-muted">(wird von der Software ignoriert)</small>
|
<small class="text-muted">(wird von der Software ignoriert)</small>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -30,9 +30,9 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-check mt-3">
|
<div class="form-check mt-3">
|
||||||
<input class="form-check-input" type="checkbox" id="isTest" name="is_test">
|
<input class="form-check-input" type="checkbox" id="isFake" name="is_fake">
|
||||||
<label class="form-check-label" for="isTest">
|
<label class="form-check-label" for="isFake">
|
||||||
<i class="fas fa-flask"></i> Als Testdaten markieren
|
<i class="fas fa-flask"></i> Als Fake-Daten markieren
|
||||||
<small class="text-muted">(Kunde wird von der Software ignoriert)</small>
|
<small class="text-muted">(Kunde wird von der Software ignoriert)</small>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -5,10 +5,10 @@
|
|||||||
{% macro sortable_header(label, field, current_sort, current_order) %}
|
{% macro sortable_header(label, field, current_sort, current_order) %}
|
||||||
<th>
|
<th>
|
||||||
{% if current_sort == field %}
|
{% if current_sort == field %}
|
||||||
<a href="{{ url_for('customers.customers', sort=field, order='desc' if current_order == 'asc' else 'asc', search=search, show_test=show_test, page=1) }}"
|
<a href="{{ url_for('customers.customers', sort=field, order='desc' if current_order == 'asc' else 'asc', search=search, show_fake=show_fake, page=1) }}"
|
||||||
class="server-sortable">
|
class="server-sortable">
|
||||||
{% else %}
|
{% else %}
|
||||||
<a href="{{ url_for('customers.customers', sort=field, order='asc', search=search, show_test=show_test, page=1) }}"
|
<a href="{{ url_for('customers.customers', sort=field, order='asc', search=search, show_fake=show_fake, page=1) }}"
|
||||||
class="server-sortable">
|
class="server-sortable">
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{{ label }}
|
{{ label }}
|
||||||
@@ -41,10 +41,10 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="col-md-2">
|
<div class="col-md-2">
|
||||||
<div class="form-check mt-4">
|
<div class="form-check mt-4">
|
||||||
<input class="form-check-input" type="checkbox" id="show_test" name="show_test" value="true"
|
<input class="form-check-input" type="checkbox" id="show_fake" name="show_fake" value="true"
|
||||||
{% if show_test %}checked{% endif %} onchange="this.form.submit()">
|
{% if show_fake %}checked{% endif %} onchange="this.form.submit()">
|
||||||
<label class="form-check-label" for="show_test">
|
<label class="form-check-label" for="show_fake">
|
||||||
🧪 Testdaten anzeigen
|
🧪 Fake-Daten anzeigen
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -126,31 +126,31 @@
|
|||||||
<ul class="pagination justify-content-center">
|
<ul class="pagination justify-content-center">
|
||||||
<!-- Erste Seite -->
|
<!-- Erste Seite -->
|
||||||
<li class="page-item {% if page == 1 %}disabled{% endif %}">
|
<li class="page-item {% if page == 1 %}disabled{% endif %}">
|
||||||
<a class="page-link" href="{{ url_for('customers.customers', page=1, search=search, sort=sort, order=order, show_test=show_test) }}">Erste</a>
|
<a class="page-link" href="{{ url_for('customers.customers', page=1, search=search, sort=sort, order=order, show_fake=show_fake) }}">Erste</a>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
<!-- Vorherige Seite -->
|
<!-- Vorherige Seite -->
|
||||||
<li class="page-item {% if page == 1 %}disabled{% endif %}">
|
<li class="page-item {% if page == 1 %}disabled{% endif %}">
|
||||||
<a class="page-link" href="{{ url_for('customers.customers', page=page-1, search=search, sort=sort, order=order, show_test=show_test) }}">←</a>
|
<a class="page-link" href="{{ url_for('customers.customers', page=page-1, search=search, sort=sort, order=order, show_fake=show_fake) }}">←</a>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
<!-- Seitenzahlen -->
|
<!-- Seitenzahlen -->
|
||||||
{% for p in range(1, total_pages + 1) %}
|
{% for p in range(1, total_pages + 1) %}
|
||||||
{% if p >= page - 2 and p <= page + 2 %}
|
{% if p >= page - 2 and p <= page + 2 %}
|
||||||
<li class="page-item {% if p == page %}active{% endif %}">
|
<li class="page-item {% if p == page %}active{% endif %}">
|
||||||
<a class="page-link" href="{{ url_for('customers.customers', page=p, search=search, sort=sort, order=order, show_test=show_test) }}">{{ p }}</a>
|
<a class="page-link" href="{{ url_for('customers.customers', page=p, search=search, sort=sort, order=order, show_fake=show_fake) }}">{{ p }}</a>
|
||||||
</li>
|
</li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|
||||||
<!-- Nächste Seite -->
|
<!-- Nächste Seite -->
|
||||||
<li class="page-item {% if page == total_pages %}disabled{% endif %}">
|
<li class="page-item {% if page == total_pages %}disabled{% endif %}">
|
||||||
<a class="page-link" href="{{ url_for('customers.customers', page=page+1, search=search, sort=sort, order=order, show_test=show_test) }}">→</a>
|
<a class="page-link" href="{{ url_for('customers.customers', page=page+1, search=search, sort=sort, order=order, show_fake=show_fake) }}">→</a>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
<!-- Letzte Seite -->
|
<!-- Letzte Seite -->
|
||||||
<li class="page-item {% if page == total_pages %}disabled{% endif %}">
|
<li class="page-item {% if page == total_pages %}disabled{% endif %}">
|
||||||
<a class="page-link" href="{{ url_for('customers.customers', page=total_pages, search=search, sort=sort, order=order, show_test=show_test) }}">Letzte</a>
|
<a class="page-link" href="{{ url_for('customers.customers', page=total_pages, search=search, sort=sort, order=order, show_fake=show_fake) }}">Letzte</a>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
<p class="text-center text-muted">
|
<p class="text-center text-muted">
|
||||||
|
|||||||
@@ -17,14 +17,14 @@
|
|||||||
<i class="bi bi-download"></i> Export
|
<i class="bi bi-download"></i> Export
|
||||||
</button>
|
</button>
|
||||||
<ul class="dropdown-menu">
|
<ul class="dropdown-menu">
|
||||||
<li><a class="dropdown-item" href="{{ url_for('export.export_customers', format='excel', include_test=request.args.get('show_test')) }}">
|
<li><a class="dropdown-item" href="{{ url_for('export.export_customers', format='excel', include_test=request.args.get('show_fake')) }}">
|
||||||
<i class="bi bi-file-earmark-excel text-success"></i> Kunden (Excel)</a></li>
|
<i class="bi bi-file-earmark-excel text-success"></i> Kunden (Excel)</a></li>
|
||||||
<li><a class="dropdown-item" href="{{ url_for('export.export_customers', format='csv', include_test=request.args.get('show_test')) }}">
|
<li><a class="dropdown-item" href="{{ url_for('export.export_customers', format='csv', include_test=request.args.get('show_fake')) }}">
|
||||||
<i class="bi bi-file-earmark-text"></i> Kunden (CSV)</a></li>
|
<i class="bi bi-file-earmark-text"></i> Kunden (CSV)</a></li>
|
||||||
<li><hr class="dropdown-divider"></li>
|
<li><hr class="dropdown-divider"></li>
|
||||||
<li><a class="dropdown-item" href="{{ url_for('export.export_licenses', format='excel', include_test=request.args.get('show_test')) }}">
|
<li><a class="dropdown-item" href="{{ url_for('export.export_licenses', format='excel', include_test=request.args.get('show_fake')) }}">
|
||||||
<i class="bi bi-file-earmark-excel text-success"></i> Lizenzen (Excel)</a></li>
|
<i class="bi bi-file-earmark-excel text-success"></i> Lizenzen (Excel)</a></li>
|
||||||
<li><a class="dropdown-item" href="{{ url_for('export.export_licenses', format='csv', include_test=request.args.get('show_test')) }}">
|
<li><a class="dropdown-item" href="{{ url_for('export.export_licenses', format='csv', include_test=request.args.get('show_fake')) }}">
|
||||||
<i class="bi bi-file-earmark-text"></i> Lizenzen (CSV)</a></li>
|
<i class="bi bi-file-earmark-text"></i> Lizenzen (CSV)</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
@@ -47,11 +47,11 @@
|
|||||||
<input type="text" class="form-control mb-2" id="customerSearch"
|
<input type="text" class="form-control mb-2" id="customerSearch"
|
||||||
placeholder="Kunde suchen..." autocomplete="off">
|
placeholder="Kunde suchen..." autocomplete="off">
|
||||||
<div class="form-check">
|
<div class="form-check">
|
||||||
<input class="form-check-input" type="checkbox" id="showTestCustomers"
|
<input class="form-check-input" type="checkbox" id="showFakeCustomers"
|
||||||
{% if request.args.get('show_test', 'false').lower() == 'true' %}checked{% endif %}
|
{% if request.args.get('show_fake', 'false').lower() == 'true' %}checked{% endif %}
|
||||||
onchange="toggleTestCustomers()">
|
onchange="toggleFakeCustomers()">
|
||||||
<label class="form-check-label" for="showTestCustomers">
|
<label class="form-check-label" for="showFakeCustomers">
|
||||||
<small class="text-muted">Testkunden anzeigen</small>
|
<small class="text-muted">Fake-Kunden anzeigen</small>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -289,7 +289,7 @@ function loadCustomerLicenses(customerId) {
|
|||||||
});
|
});
|
||||||
document.querySelector(`[data-customer-id="${customerId}"]`).classList.add('active');
|
document.querySelector(`[data-customer-id="${customerId}"]`).classList.add('active');
|
||||||
|
|
||||||
// URL aktualisieren ohne Reload (behalte show_test Parameter)
|
// URL aktualisieren ohne Reload (behalte show_fake Parameter)
|
||||||
const currentUrl = new URL(window.location);
|
const currentUrl = new URL(window.location);
|
||||||
currentUrl.searchParams.set('customer_id', customerId);
|
currentUrl.searchParams.set('customer_id', customerId);
|
||||||
window.history.pushState({}, '', currentUrl.toString());
|
window.history.pushState({}, '', currentUrl.toString());
|
||||||
@@ -522,10 +522,10 @@ function copyToClipboard(text) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Toggle Testkunden
|
// Toggle Testkunden
|
||||||
function toggleTestCustomers() {
|
function toggleFakeCustomers() {
|
||||||
const showTest = document.getElementById('showTestCustomers').checked;
|
const showTest = document.getElementById('showFakeCustomers').checked;
|
||||||
const currentUrl = new URL(window.location);
|
const currentUrl = new URL(window.location);
|
||||||
currentUrl.searchParams.set('show_test', showTest);
|
currentUrl.searchParams.set('show_fake', showTest);
|
||||||
window.location.href = currentUrl.toString();
|
window.location.href = currentUrl.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -854,12 +854,12 @@ function quarantineResource(resourceId, resourceValue) {
|
|||||||
|
|
||||||
// Lade verfügbare Ressourcen
|
// Lade verfügbare Ressourcen
|
||||||
function loadAvailableResources(licenseId) {
|
function loadAvailableResources(licenseId) {
|
||||||
// Hole show_test Parameter aus der URL
|
// Hole show_fake Parameter aus der URL
|
||||||
const urlParams = new URLSearchParams(window.location.search);
|
const urlParams = new URLSearchParams(window.location.search);
|
||||||
const showTest = urlParams.get('show_test') === 'true';
|
const showTest = urlParams.get('show_fake') === 'true';
|
||||||
|
|
||||||
// Lade verfügbare Domains
|
// Lade verfügbare Domains
|
||||||
fetch(`/api/resources/check-availability?type=domain&count=200&show_test=${showTest}`)
|
fetch(`/api/resources/check-availability?type=domain&count=200&show_fake=${showTest}`)
|
||||||
.then(response => response.json())
|
.then(response => response.json())
|
||||||
.then(data => {
|
.then(data => {
|
||||||
const select = document.getElementById('availableDomains');
|
const select = document.getElementById('availableDomains');
|
||||||
@@ -880,7 +880,7 @@ function loadAvailableResources(licenseId) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Lade verfügbare IPv4s
|
// Lade verfügbare IPv4s
|
||||||
fetch(`/api/resources/check-availability?type=ipv4&count=200&show_test=${showTest}`)
|
fetch(`/api/resources/check-availability?type=ipv4&count=200&show_fake=${showTest}`)
|
||||||
.then(response => response.json())
|
.then(response => response.json())
|
||||||
.then(data => {
|
.then(data => {
|
||||||
const select = document.getElementById('availableIpv4s');
|
const select = document.getElementById('availableIpv4s');
|
||||||
@@ -901,7 +901,7 @@ function loadAvailableResources(licenseId) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Lade verfügbare Telefonnummern
|
// Lade verfügbare Telefonnummern
|
||||||
fetch(`/api/resources/check-availability?type=phone&count=200&show_test=${showTest}`)
|
fetch(`/api/resources/check-availability?type=phone&count=200&show_fake=${showTest}`)
|
||||||
.then(response => response.json())
|
.then(response => response.json())
|
||||||
.then(data => {
|
.then(data => {
|
||||||
const select = document.getElementById('availablePhones');
|
const select = document.getElementById('availablePhones');
|
||||||
|
|||||||
@@ -116,17 +116,17 @@
|
|||||||
<p class="text-muted">Vollversionen</p>
|
<p class="text-muted">Vollversionen</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-6 text-center">
|
<div class="col-6 text-center">
|
||||||
<h3 class="text-warning">{{ stats.test_licenses }}</h3>
|
<h3 class="text-warning">{{ stats.fake_licenses }}</h3>
|
||||||
<p class="text-muted">Testversionen</p>
|
<p class="text-muted">Testversionen</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% if stats.test_data_count > 0 or stats.test_customers_count > 0 or stats.test_resources_count > 0 %}
|
{% if stats.fake_data_count > 0 or stats.fake_customers_count > 0 or stats.fake_resources_count > 0 %}
|
||||||
<div class="alert alert-info mt-3 mb-0">
|
<div class="alert alert-info mt-3 mb-0">
|
||||||
<small>
|
<small>
|
||||||
<i class="fas fa-flask"></i> Testdaten:
|
<i class="fas fa-flask"></i> Fake-Daten:
|
||||||
{{ stats.test_data_count }} Lizenzen,
|
{{ stats.fake_data_count }} Lizenzen,
|
||||||
{{ stats.test_customers_count }} Kunden,
|
{{ stats.fake_customers_count }} Kunden,
|
||||||
{{ stats.test_resources_count }} Ressourcen
|
{{ stats.fake_resources_count }} Ressourcen
|
||||||
</small>
|
</small>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|||||||
@@ -7,15 +7,15 @@
|
|||||||
<div class="d-flex justify-content-between align-items-center mb-4">
|
<div class="d-flex justify-content-between align-items-center mb-4">
|
||||||
<h2>Kunde bearbeiten</h2>
|
<h2>Kunde bearbeiten</h2>
|
||||||
<div>
|
<div>
|
||||||
<a href="{{ url_for('customers.customers_licenses', show_test=request.args.get('show_test')) }}" class="btn btn-secondary">👥 Zurück zur Übersicht</a>
|
<a href="{{ url_for('customers.customers_licenses', show_fake=request.args.get('show_fake')) }}" class="btn btn-secondary">👥 Zurück zur Übersicht</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="card mb-4">
|
<div class="card mb-4">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<form method="post" action="{{ url_for('customers.edit_customer', customer_id=customer.id) }}" accept-charset="UTF-8">
|
<form method="post" action="{{ url_for('customers.edit_customer', customer_id=customer.id) }}" accept-charset="UTF-8">
|
||||||
{% if request.args.get('show_test') == 'true' %}
|
{% if request.args.get('show_fake') == 'true' %}
|
||||||
<input type="hidden" name="show_test" value="true">
|
<input type="hidden" name="show_fake" value="true">
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<div class="row g-3">
|
<div class="row g-3">
|
||||||
<div class="col-md-6">
|
<div class="col-md-6">
|
||||||
@@ -33,16 +33,16 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-check mt-3">
|
<div class="form-check mt-3">
|
||||||
<input class="form-check-input" type="checkbox" id="isTest" name="is_test" {% if customer.is_test %}checked{% endif %}>
|
<input class="form-check-input" type="checkbox" id="isTest" name="is_fake" {% if customer.is_fake %}checked{% endif %}>
|
||||||
<label class="form-check-label" for="isTest">
|
<label class="form-check-label" for="isTest">
|
||||||
<i class="fas fa-flask"></i> Als Testdaten markieren
|
<i class="fas fa-flask"></i> Als Fake-Daten markieren
|
||||||
<small class="text-muted">(Kunde und seine Lizenzen werden von der Software ignoriert)</small>
|
<small class="text-muted">(Kunde und seine Lizenzen werden von der Software ignoriert)</small>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="mt-4">
|
<div class="mt-4">
|
||||||
<button type="submit" class="btn btn-primary">💾 Änderungen speichern</button>
|
<button type="submit" class="btn btn-primary">💾 Änderungen speichern</button>
|
||||||
<a href="{{ url_for('customers.customers_licenses', show_test=request.args.get('show_test')) }}" class="btn btn-secondary">Abbrechen</a>
|
<a href="{{ url_for('customers.customers_licenses', show_fake=request.args.get('show_fake')) }}" class="btn btn-secondary">Abbrechen</a>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -7,15 +7,15 @@
|
|||||||
<div class="d-flex justify-content-between align-items-center mb-4">
|
<div class="d-flex justify-content-between align-items-center mb-4">
|
||||||
<h2>Lizenz bearbeiten</h2>
|
<h2>Lizenz bearbeiten</h2>
|
||||||
<div>
|
<div>
|
||||||
<a href="{{ url_for('customers.customers_licenses', show_test=request.args.get('show_test')) }}" class="btn btn-secondary">📋 Zurück zur Übersicht</a>
|
<a href="{{ url_for('customers.customers_licenses', show_fake=request.args.get('show_fake')) }}" class="btn btn-secondary">📋 Zurück zur Übersicht</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<form method="post" action="{{ url_for('licenses.edit_license', license_id=license.id) }}" accept-charset="UTF-8">
|
<form method="post" action="{{ url_for('licenses.edit_license', license_id=license.id) }}" accept-charset="UTF-8">
|
||||||
{% if request.args.get('show_test') == 'true' %}
|
{% if request.args.get('show_fake') == 'true' %}
|
||||||
<input type="hidden" name="show_test" value="true">
|
<input type="hidden" name="show_fake" value="true">
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<div class="row g-3">
|
<div class="row g-3">
|
||||||
<div class="col-md-6">
|
<div class="col-md-6">
|
||||||
@@ -66,16 +66,16 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-check mt-3">
|
<div class="form-check mt-3">
|
||||||
<input class="form-check-input" type="checkbox" id="isTest" name="is_test" {% if license.is_test %}checked{% endif %}>
|
<input class="form-check-input" type="checkbox" id="isTest" name="is_fake" {% if license.is_fake %}checked{% endif %}>
|
||||||
<label class="form-check-label" for="isTest">
|
<label class="form-check-label" for="isTest">
|
||||||
<i class="fas fa-flask"></i> Als Testdaten markieren
|
<i class="fas fa-flask"></i> Als Fake-Daten markieren
|
||||||
<small class="text-muted">(wird von der Software ignoriert)</small>
|
<small class="text-muted">(wird von der Software ignoriert)</small>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="mt-4">
|
<div class="mt-4">
|
||||||
<button type="submit" class="btn btn-primary">💾 Änderungen speichern</button>
|
<button type="submit" class="btn btn-primary">💾 Änderungen speichern</button>
|
||||||
<a href="{{ url_for('customers.customers_licenses', show_test=request.args.get('show_test')) }}" class="btn btn-secondary">Abbrechen</a>
|
<a href="{{ url_for('customers.customers_licenses', show_fake=request.args.get('show_fake')) }}" class="btn btn-secondary">Abbrechen</a>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -154,9 +154,9 @@
|
|||||||
|
|
||||||
<!-- Test Data Checkbox -->
|
<!-- Test Data Checkbox -->
|
||||||
<div class="form-check mt-3">
|
<div class="form-check mt-3">
|
||||||
<input class="form-check-input" type="checkbox" id="isTest" name="is_test">
|
<input class="form-check-input" type="checkbox" id="isTest" name="is_fake">
|
||||||
<label class="form-check-label" for="isTest">
|
<label class="form-check-label" for="isTest">
|
||||||
<i class="fas fa-flask"></i> Als Testdaten markieren
|
<i class="fas fa-flask"></i> Als Fake-Daten markieren
|
||||||
<small class="text-muted">(wird von der Software ignoriert)</small>
|
<small class="text-muted">(wird von der Software ignoriert)</small>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -4,13 +4,20 @@
|
|||||||
|
|
||||||
{% macro sortable_header(label, field, current_sort, current_order) %}
|
{% macro sortable_header(label, field, current_sort, current_order) %}
|
||||||
<th>
|
<th>
|
||||||
|
{% set base_url = url_for('licenses.licenses') %}
|
||||||
|
{% set params = [] %}
|
||||||
|
{% if search %}{% set _ = params.append('search=' + search|urlencode) %}{% endif %}
|
||||||
|
{% for type in filter_types %}{% set _ = params.append('types[]=' + type|urlencode) %}{% endfor %}
|
||||||
|
{% for status in filter_statuses %}{% set _ = params.append('statuses[]=' + status|urlencode) %}{% endfor %}
|
||||||
|
{% set _ = params.append('sort=' + field) %}
|
||||||
{% if current_sort == field %}
|
{% if current_sort == field %}
|
||||||
<a href="{{ url_for('licenses.licenses', sort=field, order='desc' if current_order == 'asc' else 'asc', search=search, type=filter_type, status=filter_status, page=1) }}"
|
{% set _ = params.append('order=' + ('desc' if current_order == 'asc' else 'asc')) %}
|
||||||
class="server-sortable">
|
|
||||||
{% else %}
|
{% else %}
|
||||||
<a href="{{ url_for('licenses.licenses', sort=field, order='asc', search=search, type=filter_type, status=filter_status, page=1) }}"
|
{% set _ = params.append('order=asc') %}
|
||||||
class="server-sortable">
|
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
{% set _ = params.append('page=1') %}
|
||||||
|
|
||||||
|
<a href="{{ base_url }}?{{ params|join('&') }}" class="server-sortable">
|
||||||
{{ label }}
|
{{ label }}
|
||||||
<span class="sort-indicator{% if current_sort == field %} active{% endif %}">
|
<span class="sort-indicator{% if current_sort == field %} active{% endif %}">
|
||||||
{% if current_sort == field %}
|
{% if current_sort == field %}
|
||||||
@@ -24,6 +31,46 @@
|
|||||||
{% endmacro %}
|
{% endmacro %}
|
||||||
|
|
||||||
{% block extra_css %}
|
{% block extra_css %}
|
||||||
|
<style>
|
||||||
|
.filter-group {
|
||||||
|
background-color: #f8f9fa;
|
||||||
|
padding: 15px;
|
||||||
|
border-radius: 8px;
|
||||||
|
margin-bottom: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.filter-group h6 {
|
||||||
|
color: #495057;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.badge.bg-info {
|
||||||
|
background-color: #0dcaf0 !important;
|
||||||
|
font-size: 0.75rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.active-filters .badge {
|
||||||
|
font-size: 0.875rem;
|
||||||
|
padding: 0.35em 0.65em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.active-filters a {
|
||||||
|
text-decoration: none;
|
||||||
|
opacity: 0.8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.active-filters a:hover {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#advancedFilters {
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-sm {
|
||||||
|
padding: 0.375rem 0.75rem;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
@@ -36,46 +83,162 @@
|
|||||||
<div class="card mb-3">
|
<div class="card mb-3">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<form method="get" action="{{ url_for('licenses.licenses') }}" id="filterForm">
|
<form method="get" action="{{ url_for('licenses.licenses') }}" id="filterForm">
|
||||||
<div class="row g-3 align-items-end">
|
<!-- Suchfeld -->
|
||||||
<div class="col-md-4">
|
<div class="row g-3 mb-3">
|
||||||
|
<div class="col-md-8">
|
||||||
<label for="search" class="form-label">🔍 Suchen</label>
|
<label for="search" class="form-label">🔍 Suchen</label>
|
||||||
<input type="text" class="form-control" id="search" name="search"
|
<input type="text" class="form-control" id="search" name="search"
|
||||||
placeholder="Lizenzschlüssel, Kunde, E-Mail..."
|
placeholder="Lizenzschlüssel, Kunde, E-Mail..."
|
||||||
value="{{ search }}">
|
value="{{ search }}">
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-2">
|
<div class="col-md-4 text-end">
|
||||||
<label for="type" class="form-label">Typ</label>
|
<label class="form-label d-block"> </label>
|
||||||
<select class="form-select" id="type" name="type">
|
<button type="button" class="btn btn-outline-primary me-2" onclick="toggleFilters()">
|
||||||
<option value="">Alle Typen</option>
|
<i class="bi bi-funnel"></i> Filter
|
||||||
<option value="full" {% if filter_type == 'full' %}selected{% endif %}>Vollversion</option>
|
</button>
|
||||||
<option value="test" {% if filter_type == 'test' %}selected{% endif %}>Testversion</option>
|
<a href="{{ url_for('licenses.licenses') }}" class="btn btn-outline-secondary">
|
||||||
<option value="test_data" {% if filter_type == 'test_data' %}selected{% endif %}>🧪 Testdaten</option>
|
<i class="bi bi-arrow-clockwise"></i> Zurücksetzen
|
||||||
<option value="live_data" {% if filter_type == 'live_data' %}selected{% endif %}>🚀 Live-Daten</option>
|
</a>
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
<div class="col-md-3">
|
|
||||||
<label for="status" class="form-label">Status</label>
|
|
||||||
<select class="form-select" id="status" name="status">
|
|
||||||
<option value="">Alle Status</option>
|
|
||||||
<option value="active" {% if filter_status == 'active' %}selected{% endif %}>✅ Aktiv</option>
|
|
||||||
<option value="expiring" {% if filter_status == 'expiring' %}selected{% endif %}>⏰ Läuft bald ab</option>
|
|
||||||
<option value="expired" {% if filter_status == 'expired' %}selected{% endif %}>⚠️ Abgelaufen</option>
|
|
||||||
<option value="inactive" {% if filter_status == 'inactive' %}selected{% endif %}>❌ Deaktiviert</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
<div class="col-md-3">
|
|
||||||
<a href="{{ url_for('licenses.licenses') }}" class="btn btn-outline-secondary">Zurücksetzen</a>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Erweiterter Filterbereich -->
|
||||||
|
<div id="advancedFilters" class="collapse {{ 'show' if filter_types or filter_status else '' }}">
|
||||||
|
<hr class="my-3">
|
||||||
|
|
||||||
|
<!-- Lizenztyp Filter (OR Logic) -->
|
||||||
|
<div class="filter-group mb-3">
|
||||||
|
<div class="d-flex align-items-center mb-2">
|
||||||
|
<h6 class="mb-0 me-2">Lizenztyp</h6>
|
||||||
|
<span class="badge bg-info">ODER</span>
|
||||||
|
</div>
|
||||||
|
<div class="row g-2">
|
||||||
|
<div class="col-auto">
|
||||||
|
<div class="form-check">
|
||||||
|
<input class="form-check-input" type="checkbox" name="types[]" value="full" id="typeFullversion"
|
||||||
|
{% if 'full' in (filter_types or []) %}checked{% endif %}>
|
||||||
|
<label class="form-check-label" for="typeFullversion">
|
||||||
|
<span class="badge bg-success">Vollversion</span>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-auto">
|
||||||
|
<div class="form-check">
|
||||||
|
<input class="form-check-input" type="checkbox" name="types[]" value="test" id="typeTestversion"
|
||||||
|
{% if 'test' in (filter_types or []) %}checked{% endif %}>
|
||||||
|
<label class="form-check-label" for="typeTestversion">
|
||||||
|
<span class="badge bg-warning">Testversion</span>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Status Filter (OR Logic) -->
|
||||||
|
<div class="filter-group mb-3">
|
||||||
|
<div class="d-flex align-items-center mb-2">
|
||||||
|
<h6 class="mb-0 me-2">Status</h6>
|
||||||
|
<span class="badge bg-info">ODER</span>
|
||||||
|
</div>
|
||||||
|
<div class="row g-2">
|
||||||
|
<div class="col-auto">
|
||||||
|
<div class="form-check">
|
||||||
|
<input class="form-check-input" type="checkbox" name="statuses[]" value="active" id="statusActive"
|
||||||
|
{% if 'active' in (filter_statuses or []) %}checked{% endif %}>
|
||||||
|
<label class="form-check-label" for="statusActive">
|
||||||
|
✅ Aktiv
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-auto">
|
||||||
|
<div class="form-check">
|
||||||
|
<input class="form-check-input" type="checkbox" name="statuses[]" value="expiring" id="statusExpiring"
|
||||||
|
{% if 'expiring' in (filter_statuses or []) %}checked{% endif %}>
|
||||||
|
<label class="form-check-label" for="statusExpiring">
|
||||||
|
⏰ Läuft bald ab
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-auto">
|
||||||
|
<div class="form-check">
|
||||||
|
<input class="form-check-input" type="checkbox" name="statuses[]" value="expired" id="statusExpired"
|
||||||
|
{% if 'expired' in (filter_statuses or []) %}checked{% endif %}>
|
||||||
|
<label class="form-check-label" for="statusExpired">
|
||||||
|
⚠️ Abgelaufen
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-auto">
|
||||||
|
<div class="form-check">
|
||||||
|
<input class="form-check-input" type="checkbox" name="statuses[]" value="inactive" id="statusInactive"
|
||||||
|
{% if 'inactive' in (filter_statuses or []) %}checked{% endif %}>
|
||||||
|
<label class="form-check-label" for="statusInactive">
|
||||||
|
❌ Deaktiviert
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Quick Filters / Presets -->
|
||||||
|
<div class="filter-group">
|
||||||
|
<h6 class="mb-2">Schnellfilter</h6>
|
||||||
|
<div class="row g-2">
|
||||||
|
<div class="col-auto">
|
||||||
|
<button type="button" class="btn btn-sm btn-outline-primary" onclick="applyPreset('expiring_soon')">
|
||||||
|
<i class="bi bi-clock-history"></i> Läuft in 7 Tagen ab
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div class="col-auto">
|
||||||
|
<button type="button" class="btn btn-sm btn-outline-primary" onclick="applyPreset('all_test')">
|
||||||
|
<i class="bi bi-bug"></i> Alle Testversionen
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div class="col-auto">
|
||||||
|
<button type="button" class="btn btn-sm btn-outline-primary" onclick="applyPreset('active_full')">
|
||||||
|
<i class="bi bi-shield-check"></i> Aktive Vollversionen
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Hidden fields for sorting -->
|
||||||
|
<input type="hidden" name="sort" value="{{ sort }}">
|
||||||
|
<input type="hidden" name="order" value="{{ order }}">
|
||||||
</form>
|
</form>
|
||||||
{% if search or filter_type or filter_status %}
|
{% if search or filter_types or filter_statuses %}
|
||||||
<div class="mt-2">
|
<div class="mt-2">
|
||||||
|
<div class="d-flex align-items-center justify-content-between">
|
||||||
<small class="text-muted">
|
<small class="text-muted">
|
||||||
Gefiltert: {{ total }} Ergebnisse
|
Gefiltert: {{ total }} Ergebnisse
|
||||||
{% if search %} | Suche: <strong>{{ search }}</strong>{% endif %}
|
|
||||||
{% if filter_type %} | Typ: <strong>{{ 'Vollversion' if filter_type == 'full' else 'Testversion' }}</strong>{% endif %}
|
|
||||||
{% if filter_status %} | Status: <strong>{{ filter_status }}</strong>{% endif %}
|
|
||||||
</small>
|
</small>
|
||||||
|
<div class="active-filters">
|
||||||
|
{% if search %}
|
||||||
|
<span class="badge bg-secondary me-1">
|
||||||
|
<i class="bi bi-search"></i> {{ search }}
|
||||||
|
{% set clear_search_params = [] %}
|
||||||
|
{% for type in filter_types %}{% set _ = clear_search_params.append('types[]=' + type|urlencode) %}{% endfor %}
|
||||||
|
{% for status in filter_statuses %}{% set _ = clear_search_params.append('statuses[]=' + status|urlencode) %}{% endfor %}
|
||||||
|
{% set _ = clear_search_params.append('sort=' + sort) %}
|
||||||
|
{% set _ = clear_search_params.append('order=' + order) %}
|
||||||
|
<a href="{{ url_for('licenses.licenses') }}?{{ clear_search_params|join('&') }}" class="text-white ms-1">×</a>
|
||||||
|
</span>
|
||||||
|
{% endif %}
|
||||||
|
{% for type in (filter_types or []) %}
|
||||||
|
<span class="badge bg-primary me-1">
|
||||||
|
{{ 'Vollversion' if type == 'full' else 'Testversion' }}
|
||||||
|
<a href="#" onclick="removeFilter('type', '{{ type }}')" class="text-white ms-1">×</a>
|
||||||
|
</span>
|
||||||
|
{% endfor %}
|
||||||
|
{% for status in (filter_statuses or []) %}
|
||||||
|
<span class="badge bg-info me-1">
|
||||||
|
{% if status == 'active' %}✅ Aktiv{% elif status == 'expiring' %}⏰ Läuft bald ab{% elif status == 'expired' %}⚠️ Abgelaufen{% else %}❌ Deaktiviert{% endif %}
|
||||||
|
<a href="#" onclick="removeFilter('status', '{{ status }}')" class="text-white ms-1">×</a>
|
||||||
|
</span>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
@@ -119,8 +282,8 @@
|
|||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
{{ license.customer_name }}
|
{{ license.customer_name }}
|
||||||
{% if license.is_test %}
|
{% if license.is_fake %}
|
||||||
<span class="badge bg-secondary ms-1" title="Testdaten">🧪</span>
|
<span class="badge bg-secondary ms-1" title="Fake-Daten">🧪</span>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</td>
|
</td>
|
||||||
<td>-</td>
|
<td>-</td>
|
||||||
@@ -182,33 +345,41 @@
|
|||||||
{% if total_pages > 1 %}
|
{% if total_pages > 1 %}
|
||||||
<nav aria-label="Seitennavigation" class="mt-3">
|
<nav aria-label="Seitennavigation" class="mt-3">
|
||||||
<ul class="pagination justify-content-center">
|
<ul class="pagination justify-content-center">
|
||||||
|
{% set base_url = url_for('licenses.licenses') %}
|
||||||
|
{% set base_params = [] %}
|
||||||
|
{% if search %}{% set _ = base_params.append('search=' + search|urlencode) %}{% endif %}
|
||||||
|
{% for type in filter_types %}{% set _ = base_params.append('types[]=' + type|urlencode) %}{% endfor %}
|
||||||
|
{% for status in filter_statuses %}{% set _ = base_params.append('statuses[]=' + status|urlencode) %}{% endfor %}
|
||||||
|
{% set _ = base_params.append('sort=' + sort) %}
|
||||||
|
{% set _ = base_params.append('order=' + order) %}
|
||||||
|
|
||||||
<!-- Erste Seite -->
|
<!-- Erste Seite -->
|
||||||
<li class="page-item {% if page == 1 %}disabled{% endif %}">
|
<li class="page-item {% if page == 1 %}disabled{% endif %}">
|
||||||
<a class="page-link" href="{{ url_for('licenses.licenses', page=1, search=search, type=filter_type, status=filter_status, sort=sort, order=order) }}">Erste</a>
|
<a class="page-link" href="{{ base_url }}?{{ base_params|join('&') }}&page=1">Erste</a>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
<!-- Vorherige Seite -->
|
<!-- Vorherige Seite -->
|
||||||
<li class="page-item {% if page == 1 %}disabled{% endif %}">
|
<li class="page-item {% if page == 1 %}disabled{% endif %}">
|
||||||
<a class="page-link" href="{{ url_for('licenses.licenses', page=page-1, search=search, type=filter_type, status=filter_status, sort=sort, order=order) }}">←</a>
|
<a class="page-link" href="{{ base_url }}?{{ base_params|join('&') }}&page={{ page-1 }}">←</a>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
<!-- Seitenzahlen -->
|
<!-- Seitenzahlen -->
|
||||||
{% for p in range(1, total_pages + 1) %}
|
{% for p in range(1, total_pages + 1) %}
|
||||||
{% if p >= page - 2 and p <= page + 2 %}
|
{% if p >= page - 2 and p <= page + 2 %}
|
||||||
<li class="page-item {% if p == page %}active{% endif %}">
|
<li class="page-item {% if p == page %}active{% endif %}">
|
||||||
<a class="page-link" href="{{ url_for('licenses.licenses', page=p, search=search, type=filter_type, status=filter_status, sort=sort, order=order) }}">{{ p }}</a>
|
<a class="page-link" href="{{ base_url }}?{{ base_params|join('&') }}&page={{ p }}">{{ p }}</a>
|
||||||
</li>
|
</li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|
||||||
<!-- Nächste Seite -->
|
<!-- Nächste Seite -->
|
||||||
<li class="page-item {% if page == total_pages %}disabled{% endif %}">
|
<li class="page-item {% if page == total_pages %}disabled{% endif %}">
|
||||||
<a class="page-link" href="{{ url_for('licenses.licenses', page=page+1, search=search, type=filter_type, status=filter_status, sort=sort, order=order) }}">→</a>
|
<a class="page-link" href="{{ base_url }}?{{ base_params|join('&') }}&page={{ page+1 }}">→</a>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
<!-- Letzte Seite -->
|
<!-- Letzte Seite -->
|
||||||
<li class="page-item {% if page == total_pages %}disabled{% endif %}">
|
<li class="page-item {% if page == total_pages %}disabled{% endif %}">
|
||||||
<a class="page-link" href="{{ url_for('licenses.licenses', page=total_pages, search=search, type=filter_type, status=filter_status, sort=sort, order=order) }}">Letzte</a>
|
<a class="page-link" href="{{ base_url }}?{{ base_params|join('&') }}&page={{ total_pages }}">Letzte</a>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
<p class="text-center text-muted">
|
<p class="text-center text-muted">
|
||||||
@@ -235,12 +406,58 @@
|
|||||||
|
|
||||||
{% block extra_js %}
|
{% block extra_js %}
|
||||||
<script>
|
<script>
|
||||||
|
// Toggle Filter Panel
|
||||||
|
function toggleFilters() {
|
||||||
|
const filtersDiv = document.getElementById('advancedFilters');
|
||||||
|
const bsCollapse = new bootstrap.Collapse(filtersDiv, {
|
||||||
|
toggle: true
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply Preset Filters
|
||||||
|
function applyPreset(preset) {
|
||||||
|
const form = document.getElementById('filterForm');
|
||||||
|
|
||||||
|
// Clear existing filters
|
||||||
|
document.querySelectorAll('input[name="types[]"]').forEach(cb => cb.checked = false);
|
||||||
|
document.querySelectorAll('input[name="statuses[]"]').forEach(cb => cb.checked = false);
|
||||||
|
|
||||||
|
switch(preset) {
|
||||||
|
case 'expiring_soon':
|
||||||
|
document.getElementById('statusExpiring').checked = true;
|
||||||
|
break;
|
||||||
|
case 'all_test':
|
||||||
|
document.getElementById('typeTestversion').checked = true;
|
||||||
|
break;
|
||||||
|
case 'active_full':
|
||||||
|
document.getElementById('typeFullversion').checked = true;
|
||||||
|
document.getElementById('statusActive').checked = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
form.submit();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove Individual Filter
|
||||||
|
function removeFilter(filterType, value) {
|
||||||
|
const form = document.getElementById('filterForm');
|
||||||
|
|
||||||
|
if (filterType === 'type') {
|
||||||
|
const checkbox = document.querySelector(`input[name="types[]"][value="${value}"]`);
|
||||||
|
if (checkbox) checkbox.checked = false;
|
||||||
|
} else if (filterType === 'status') {
|
||||||
|
const checkbox = document.querySelector(`input[name="statuses[]"][value="${value}"]`);
|
||||||
|
if (checkbox) checkbox.checked = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
form.submit();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// Live Filtering
|
// Live Filtering
|
||||||
document.addEventListener('DOMContentLoaded', function() {
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
const filterForm = document.getElementById('filterForm');
|
const filterForm = document.getElementById('filterForm');
|
||||||
const searchInput = document.getElementById('search');
|
const searchInput = document.getElementById('search');
|
||||||
const typeSelect = document.getElementById('type');
|
|
||||||
const statusSelect = document.getElementById('status');
|
|
||||||
|
|
||||||
// Debounce timer für Suchfeld
|
// Debounce timer für Suchfeld
|
||||||
let searchTimeout;
|
let searchTimeout;
|
||||||
@@ -253,13 +470,11 @@ document.addEventListener('DOMContentLoaded', function() {
|
|||||||
}, 300);
|
}, 300);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Live-Filter für Dropdowns (sofort)
|
// Live-Filter für Checkboxen
|
||||||
typeSelect.addEventListener('change', function() {
|
document.querySelectorAll('input[name="types[]"], input[name="statuses[]"]').forEach(checkbox => {
|
||||||
|
checkbox.addEventListener('change', function() {
|
||||||
filterForm.submit();
|
filterForm.submit();
|
||||||
});
|
});
|
||||||
|
|
||||||
statusSelect.addEventListener('change', function() {
|
|
||||||
filterForm.submit();
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -225,7 +225,7 @@
|
|||||||
<div class="card-body py-2">
|
<div class="card-body py-2">
|
||||||
<div class="form-check mb-0">
|
<div class="form-check mb-0">
|
||||||
<input class="form-check-input" type="checkbox" id="showTestResources"
|
<input class="form-check-input" type="checkbox" id="showTestResources"
|
||||||
{% if show_test %}checked{% endif %}
|
{% if show_fake %}checked{% endif %}
|
||||||
onchange="toggleTestResources()">
|
onchange="toggleTestResources()">
|
||||||
<label class="form-check-label" for="showTestResources">
|
<label class="form-check-label" for="showTestResources">
|
||||||
Testressourcen anzeigen
|
Testressourcen anzeigen
|
||||||
@@ -293,7 +293,7 @@
|
|||||||
<div class="card filter-card mb-4">
|
<div class="card filter-card mb-4">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<form method="get" action="{{ url_for('resources.resources') }}" id="filterForm">
|
<form method="get" action="{{ url_for('resources.resources') }}" id="filterForm">
|
||||||
<input type="hidden" name="show_test" value="{{ 'true' if show_test else 'false' }}">
|
<input type="hidden" name="show_fake" value="{{ 'true' if show_fake else 'false' }}">
|
||||||
<div class="row g-3">
|
<div class="row g-3">
|
||||||
<div class="col-md-3">
|
<div class="col-md-3">
|
||||||
<label for="type" class="form-label">🏷️ Typ</label>
|
<label for="type" class="form-label">🏷️ Typ</label>
|
||||||
@@ -320,7 +320,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="col-md-2">
|
<div class="col-md-2">
|
||||||
<label class="form-label"> </label>
|
<label class="form-label"> </label>
|
||||||
<a href="{{ url_for('resources.resources', show_test=show_test) }}" class="btn btn-secondary w-100">
|
<a href="{{ url_for('resources.resources', show_fake=show_fake) }}" class="btn btn-secondary w-100">
|
||||||
🔄 Zurücksetzen
|
🔄 Zurücksetzen
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
@@ -344,7 +344,7 @@
|
|||||||
<i class="bi bi-download"></i> Export
|
<i class="bi bi-download"></i> Export
|
||||||
</button>
|
</button>
|
||||||
<ul class="dropdown-menu" aria-labelledby="exportDropdown">
|
<ul class="dropdown-menu" aria-labelledby="exportDropdown">
|
||||||
<li><a class="dropdown-item" href="{{ url_for('resources.resources_report', format='excel', type=resource_type, status=status_filter, search=search, show_test=show_test) }}">
|
<li><a class="dropdown-item" href="{{ url_for('resources.resources_report', format='excel', type=resource_type, status=status_filter, search=search, show_fake=show_fake) }}">
|
||||||
<i class="bi bi-file-earmark-excel text-success"></i> Excel Export</a></li>
|
<i class="bi bi-file-earmark-excel text-success"></i> Excel Export</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
@@ -359,7 +359,7 @@
|
|||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th width="80">
|
<th width="80">
|
||||||
<a href="{{ url_for('resources.resources', sort='id', order='desc' if sort_by == 'id' and sort_order == 'asc' else 'asc', type=resource_type, status=status_filter, search=search, show_test=show_test) }}"
|
<a href="{{ url_for('resources.resources', sort='id', order='desc' if sort_by == 'id' and sort_order == 'asc' else 'asc', type=resource_type, status=status_filter, search=search, show_fake=show_fake) }}"
|
||||||
class="text-decoration-none text-dark sort-link">
|
class="text-decoration-none text-dark sort-link">
|
||||||
ID
|
ID
|
||||||
{% if sort_by == 'id' %}
|
{% if sort_by == 'id' %}
|
||||||
@@ -370,7 +370,7 @@
|
|||||||
</a>
|
</a>
|
||||||
</th>
|
</th>
|
||||||
<th width="120">
|
<th width="120">
|
||||||
<a href="{{ url_for('resources.resources', sort='type', order='desc' if sort_by == 'type' and sort_order == 'asc' else 'asc', type=resource_type, status=status_filter, search=search, show_test=show_test) }}"
|
<a href="{{ url_for('resources.resources', sort='type', order='desc' if sort_by == 'type' and sort_order == 'asc' else 'asc', type=resource_type, status=status_filter, search=search, show_fake=show_fake) }}"
|
||||||
class="text-decoration-none text-dark sort-link">
|
class="text-decoration-none text-dark sort-link">
|
||||||
Typ
|
Typ
|
||||||
{% if sort_by == 'type' %}
|
{% if sort_by == 'type' %}
|
||||||
@@ -381,7 +381,7 @@
|
|||||||
</a>
|
</a>
|
||||||
</th>
|
</th>
|
||||||
<th>
|
<th>
|
||||||
<a href="{{ url_for('resources.resources', sort='resource', order='desc' if sort_by == 'resource' and sort_order == 'asc' else 'asc', type=resource_type, status=status_filter, search=search, show_test=show_test) }}"
|
<a href="{{ url_for('resources.resources', sort='resource', order='desc' if sort_by == 'resource' and sort_order == 'asc' else 'asc', type=resource_type, status=status_filter, search=search, show_fake=show_fake) }}"
|
||||||
class="text-decoration-none text-dark sort-link">
|
class="text-decoration-none text-dark sort-link">
|
||||||
Ressource
|
Ressource
|
||||||
{% if sort_by == 'resource' %}
|
{% if sort_by == 'resource' %}
|
||||||
@@ -392,7 +392,7 @@
|
|||||||
</a>
|
</a>
|
||||||
</th>
|
</th>
|
||||||
<th width="140">
|
<th width="140">
|
||||||
<a href="{{ url_for('resources.resources', sort='status', order='desc' if sort_by == 'status' and sort_order == 'asc' else 'asc', type=resource_type, status=status_filter, search=search, show_test=show_test) }}"
|
<a href="{{ url_for('resources.resources', sort='status', order='desc' if sort_by == 'status' and sort_order == 'asc' else 'asc', type=resource_type, status=status_filter, search=search, show_fake=show_fake) }}"
|
||||||
class="text-decoration-none text-dark sort-link">
|
class="text-decoration-none text-dark sort-link">
|
||||||
Status
|
Status
|
||||||
{% if sort_by == 'status' %}
|
{% if sort_by == 'status' %}
|
||||||
@@ -403,7 +403,7 @@
|
|||||||
</a>
|
</a>
|
||||||
</th>
|
</th>
|
||||||
<th>
|
<th>
|
||||||
<a href="{{ url_for('resources.resources', sort='assigned', order='desc' if sort_by == 'assigned' and sort_order == 'asc' else 'asc', type=resource_type, status=status_filter, search=search, show_test=show_test) }}"
|
<a href="{{ url_for('resources.resources', sort='assigned', order='desc' if sort_by == 'assigned' and sort_order == 'asc' else 'asc', type=resource_type, status=status_filter, search=search, show_fake=show_fake) }}"
|
||||||
class="text-decoration-none text-dark sort-link">
|
class="text-decoration-none text-dark sort-link">
|
||||||
Zugewiesen an
|
Zugewiesen an
|
||||||
{% if sort_by == 'assigned' %}
|
{% if sort_by == 'assigned' %}
|
||||||
@@ -414,7 +414,7 @@
|
|||||||
</a>
|
</a>
|
||||||
</th>
|
</th>
|
||||||
<th width="180">
|
<th width="180">
|
||||||
<a href="{{ url_for('resources.resources', sort='changed', order='desc' if sort_by == 'changed' and sort_order == 'asc' else 'asc', type=resource_type, status=status_filter, search=search, show_test=show_test) }}"
|
<a href="{{ url_for('resources.resources', sort='changed', order='desc' if sort_by == 'changed' and sort_order == 'asc' else 'asc', type=resource_type, status=status_filter, search=search, show_fake=show_fake) }}"
|
||||||
class="text-decoration-none text-dark sort-link">
|
class="text-decoration-none text-dark sort-link">
|
||||||
Letzte Änderung
|
Letzte Änderung
|
||||||
{% if sort_by == 'changed' %}
|
{% if sort_by == 'changed' %}
|
||||||
@@ -474,13 +474,13 @@
|
|||||||
<td>
|
<td>
|
||||||
{% if resource.customer_name %}
|
{% if resource.customer_name %}
|
||||||
<div>
|
<div>
|
||||||
<a href="{{ url_for('customers.customers_licenses', show_test=show_test) }}"
|
<a href="{{ url_for('customers.customers_licenses', show_fake=show_fake) }}"
|
||||||
class="text-decoration-none">
|
class="text-decoration-none">
|
||||||
<strong>{{ resource.customer_name }}</strong>
|
<strong>{{ resource.customer_name }}</strong>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<div class="small text-muted">
|
<div class="small text-muted">
|
||||||
<a href="{{ url_for('licenses.edit_license', license_id=resource.allocated_to_license) }}?ref=resources{{ '&show_test=true' if show_test else '' }}"
|
<a href="{{ url_for('licenses.edit_license', license_id=resource.allocated_to_license) }}?ref=resources{{ '&show_fake=true' if show_fake else '' }}"
|
||||||
class="text-decoration-none text-muted">
|
class="text-decoration-none text-muted">
|
||||||
{{ resource.allocated_to_license }}
|
{{ resource.allocated_to_license }}
|
||||||
</a>
|
</a>
|
||||||
@@ -502,10 +502,10 @@
|
|||||||
<td class="text-center">
|
<td class="text-center">
|
||||||
{% if resource.status == 'quarantine' %}
|
{% if resource.status == 'quarantine' %}
|
||||||
<!-- Quick Action für Quarantäne -->
|
<!-- Quick Action für Quarantäne -->
|
||||||
<form method="post" action="{{ url_for('resources.release', show_test=show_test, type=resource_type, status=status_filter, search=search) }}"
|
<form method="post" action="{{ url_for('resources.release', show_fake=show_fake, type=resource_type, status=status_filter, search=search) }}"
|
||||||
style="display: inline-block; margin-right: 5px;">
|
style="display: inline-block; margin-right: 5px;">
|
||||||
<input type="hidden" name="resource_ids" value="{{ resource.id }}">
|
<input type="hidden" name="resource_ids" value="{{ resource.id }}">
|
||||||
<input type="hidden" name="show_test" value="{{ show_test }}">
|
<input type="hidden" name="show_fake" value="{{ show_fake }}">
|
||||||
<button type="submit"
|
<button type="submit"
|
||||||
class="btn btn-sm btn-success">
|
class="btn btn-sm btn-success">
|
||||||
<i class="bi bi-check-circle"></i> Freigeben
|
<i class="bi bi-check-circle"></i> Freigeben
|
||||||
@@ -546,7 +546,7 @@
|
|||||||
{% if resource.allocated_to_license %}
|
{% if resource.allocated_to_license %}
|
||||||
<li>
|
<li>
|
||||||
<a class="dropdown-item"
|
<a class="dropdown-item"
|
||||||
href="{{ url_for('licenses.edit_license', license_id=resource.allocated_to_license) }}?ref=resources{{ '&show_test=true' if show_test else '' }}">
|
href="{{ url_for('licenses.edit_license', license_id=resource.allocated_to_license) }}?ref=resources{{ '&show_fake=true' if show_fake else '' }}">
|
||||||
<i class="bi bi-file-text text-primary"></i> Lizenz bearbeiten
|
<i class="bi bi-file-text text-primary"></i> Lizenz bearbeiten
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
@@ -554,7 +554,7 @@
|
|||||||
{% if resource.id %}
|
{% if resource.id %}
|
||||||
<li>
|
<li>
|
||||||
<a class="dropdown-item"
|
<a class="dropdown-item"
|
||||||
href="{{ url_for('customers.customers_licenses', customer_id=resource.id, show_test=show_test) }}">
|
href="{{ url_for('customers.customers_licenses', customer_id=resource.id, show_fake=show_fake) }}">
|
||||||
<i class="bi bi-person text-primary"></i> Kunde anzeigen
|
<i class="bi bi-person text-primary"></i> Kunde anzeigen
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
@@ -562,10 +562,10 @@
|
|||||||
{% elif resource.status == 'quarantine' %}
|
{% elif resource.status == 'quarantine' %}
|
||||||
<!-- Aktionen für Quarantäne-Ressourcen -->
|
<!-- Aktionen für Quarantäne-Ressourcen -->
|
||||||
<li>
|
<li>
|
||||||
<form method="post" action="{{ url_for('resources.release', show_test=show_test, type=resource_type, status=status_filter, search=search) }}"
|
<form method="post" action="{{ url_for('resources.release', show_fake=show_fake, type=resource_type, status=status_filter, search=search) }}"
|
||||||
style="display: contents;">
|
style="display: contents;">
|
||||||
<input type="hidden" name="resource_ids" value="{{ resource.id }}">
|
<input type="hidden" name="resource_ids" value="{{ resource.id }}">
|
||||||
<input type="hidden" name="show_test" value="{{ show_test }}">
|
<input type="hidden" name="show_fake" value="{{ show_fake }}">
|
||||||
<button type="submit" class="dropdown-item">
|
<button type="submit" class="dropdown-item">
|
||||||
<i class="bi bi-check-circle text-success"></i> Ressource freigeben
|
<i class="bi bi-check-circle text-success"></i> Ressource freigeben
|
||||||
</button>
|
</button>
|
||||||
@@ -614,13 +614,13 @@
|
|||||||
<ul class="pagination justify-content-center">
|
<ul class="pagination justify-content-center">
|
||||||
<li class="page-item {% if page == 1 %}disabled{% endif %}">
|
<li class="page-item {% if page == 1 %}disabled{% endif %}">
|
||||||
<a class="page-link"
|
<a class="page-link"
|
||||||
href="{{ url_for('resources.resources', page=1, type=resource_type, status=status_filter, search=search, show_test=show_test, sort=sort_by, order=sort_order) }}">
|
href="{{ url_for('resources.resources', page=1, type=resource_type, status=status_filter, search=search, show_fake=show_fake, sort=sort_by, order=sort_order) }}">
|
||||||
<i class="bi bi-chevron-double-left"></i> Erste
|
<i class="bi bi-chevron-double-left"></i> Erste
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="page-item {% if page == 1 %}disabled{% endif %}">
|
<li class="page-item {% if page == 1 %}disabled{% endif %}">
|
||||||
<a class="page-link"
|
<a class="page-link"
|
||||||
href="{{ url_for('resources.resources', page=page-1, type=resource_type, status=status_filter, search=search, show_test=show_test, sort=sort_by, order=sort_order) }}">
|
href="{{ url_for('resources.resources', page=page-1, type=resource_type, status=status_filter, search=search, show_fake=show_fake, sort=sort_by, order=sort_order) }}">
|
||||||
<i class="bi bi-chevron-left"></i> Zurück
|
<i class="bi bi-chevron-left"></i> Zurück
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
@@ -629,7 +629,7 @@
|
|||||||
{% if p == page or (p >= page - 2 and p <= page + 2) %}
|
{% if p == page or (p >= page - 2 and p <= page + 2) %}
|
||||||
<li class="page-item {% if p == page %}active{% endif %}">
|
<li class="page-item {% if p == page %}active{% endif %}">
|
||||||
<a class="page-link"
|
<a class="page-link"
|
||||||
href="{{ url_for('resources.resources', page=p, type=resource_type, status=status_filter, search=search, show_test=show_test, sort=sort_by, order=sort_order) }}">
|
href="{{ url_for('resources.resources', page=p, type=resource_type, status=status_filter, search=search, show_fake=show_fake, sort=sort_by, order=sort_order) }}">
|
||||||
{{ p }}
|
{{ p }}
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
@@ -638,13 +638,13 @@
|
|||||||
|
|
||||||
<li class="page-item {% if page == total_pages %}disabled{% endif %}">
|
<li class="page-item {% if page == total_pages %}disabled{% endif %}">
|
||||||
<a class="page-link"
|
<a class="page-link"
|
||||||
href="{{ url_for('resources.resources', page=page+1, type=resource_type, status=status_filter, search=search, show_test=show_test, sort=sort_by, order=sort_order) }}">
|
href="{{ url_for('resources.resources', page=page+1, type=resource_type, status=status_filter, search=search, show_fake=show_fake, sort=sort_by, order=sort_order) }}">
|
||||||
Weiter <i class="bi bi-chevron-right"></i>
|
Weiter <i class="bi bi-chevron-right"></i>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="page-item {% if page == total_pages %}disabled{% endif %}">
|
<li class="page-item {% if page == total_pages %}disabled{% endif %}">
|
||||||
<a class="page-link"
|
<a class="page-link"
|
||||||
href="{{ url_for('resources.resources', page=total_pages, type=resource_type, status=status_filter, search=search, show_test=show_test, sort=sort_by, order=sort_order) }}">
|
href="{{ url_for('resources.resources', page=total_pages, type=resource_type, status=status_filter, search=search, show_fake=show_fake, sort=sort_by, order=sort_order) }}">
|
||||||
Letzte <i class="bi bi-chevron-double-right"></i>
|
Letzte <i class="bi bi-chevron-double-right"></i>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
@@ -702,7 +702,7 @@
|
|||||||
<div class="modal-content">
|
<div class="modal-content">
|
||||||
<form method="post" id="quarantineForm">
|
<form method="post" id="quarantineForm">
|
||||||
<!-- Filter-Parameter als Hidden Fields -->
|
<!-- Filter-Parameter als Hidden Fields -->
|
||||||
<input type="hidden" name="show_test" value="{{ show_test }}">
|
<input type="hidden" name="show_fake" value="{{ show_fake }}">
|
||||||
<input type="hidden" name="type" value="{{ resource_type }}">
|
<input type="hidden" name="type" value="{{ resource_type }}">
|
||||||
<input type="hidden" name="status" value="{{ status_filter }}">
|
<input type="hidden" name="status" value="{{ status_filter }}">
|
||||||
<input type="hidden" name="search" value="{{ search }}">
|
<input type="hidden" name="search" value="{{ search }}">
|
||||||
@@ -852,7 +852,7 @@ function showQuarantineModal(resourceId) {
|
|||||||
function toggleTestResources() {
|
function toggleTestResources() {
|
||||||
const showTest = document.getElementById('showTestResources').checked;
|
const showTest = document.getElementById('showTestResources').checked;
|
||||||
const currentUrl = new URL(window.location);
|
const currentUrl = new URL(window.location);
|
||||||
currentUrl.searchParams.set('show_test', showTest);
|
currentUrl.searchParams.set('show_fake', showTest);
|
||||||
window.location.href = currentUrl.toString();
|
window.location.href = currentUrl.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -63,7 +63,7 @@ def prepare_license_export_data(licenses):
|
|||||||
format_datetime_for_export(license[8]), # Created At
|
format_datetime_for_export(license[8]), # Created At
|
||||||
license[9], # Device Limit
|
license[9], # Device Limit
|
||||||
license[10] or 0, # Current Devices
|
license[10] or 0, # Current Devices
|
||||||
'Test' if license[11] else 'Full' # Is Test License
|
'Fake' if license[11] else 'Full' # Is Test License
|
||||||
])
|
])
|
||||||
return export_data
|
return export_data
|
||||||
|
|
||||||
@@ -141,7 +141,7 @@ def create_batch_export(licenses):
|
|||||||
'Gültig von': format_datetime_for_export(license.get('valid_from')),
|
'Gültig von': format_datetime_for_export(license.get('valid_from')),
|
||||||
'Gültig bis': format_datetime_for_export(license.get('valid_until')),
|
'Gültig bis': format_datetime_for_export(license.get('valid_until')),
|
||||||
'Status': 'Aktiv' if license.get('is_active', True) else 'Inaktiv',
|
'Status': 'Aktiv' if license.get('is_active', True) else 'Inaktiv',
|
||||||
'Test-Lizenz': 'Ja' if license.get('is_test', False) else 'Nein'
|
'Fake-Lizenz': 'Ja' if license.get('is_test', False) else 'Nein'
|
||||||
})
|
})
|
||||||
|
|
||||||
df = pd.DataFrame(export_data)
|
df = pd.DataFrame(export_data)
|
||||||
|
|||||||
In neuem Issue referenzieren
Einen Benutzer sperren