204 lines
7.1 KiB
Python
204 lines
7.1 KiB
Python
import sqlite3
|
|
import os
|
|
import json
|
|
from datetime import datetime
|
|
|
|
class DatabaseManager:
|
|
def __init__(self, db_path='dashboard.db'):
|
|
self.db_path = db_path
|
|
self.init_database()
|
|
|
|
def init_database(self):
|
|
"""Initialize the database with required tables"""
|
|
conn = sqlite3.connect(self.db_path)
|
|
cursor = conn.cursor()
|
|
|
|
# Create applications table for storing custom app data
|
|
cursor.execute('''
|
|
CREATE TABLE IF NOT EXISTS applications (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
container_id TEXT UNIQUE,
|
|
container_name TEXT NOT NULL,
|
|
display_name TEXT,
|
|
icon TEXT DEFAULT 'fas fa-cube',
|
|
color TEXT DEFAULT 'gray',
|
|
description TEXT,
|
|
url TEXT,
|
|
status TEXT DEFAULT 'unknown',
|
|
custom_data TEXT, -- JSON for additional custom fields
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
)
|
|
''')
|
|
|
|
# Add status column if it doesn't exist (for backward compatibility)
|
|
try:
|
|
cursor.execute("ALTER TABLE applications ADD COLUMN status TEXT DEFAULT 'unknown'")
|
|
print("Added status column to applications table")
|
|
except sqlite3.OperationalError as e:
|
|
if "duplicate column name" not in str(e).lower():
|
|
print(f"Note: {e}")
|
|
|
|
# Create settings table for general configuration
|
|
cursor.execute('''
|
|
CREATE TABLE IF NOT EXISTS settings (
|
|
key TEXT PRIMARY KEY,
|
|
value TEXT,
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
)
|
|
''')
|
|
|
|
conn.commit()
|
|
conn.close()
|
|
|
|
def get_connection(self):
|
|
"""Get database connection"""
|
|
return sqlite3.connect(self.db_path)
|
|
|
|
def upsert_application(self, container_data):
|
|
"""Insert or update application data"""
|
|
conn = self.get_connection()
|
|
cursor = conn.cursor()
|
|
|
|
container_id = container_data.get('id')
|
|
container_name = container_data.get('name')
|
|
display_name = container_data.get('display_name', container_name)
|
|
icon = container_data.get('icon', 'fas fa-cube')
|
|
color = container_data.get('color', 'gray')
|
|
description = container_data.get('description', container_data.get('image', ''))
|
|
url = container_data.get('url', '#')
|
|
custom_data = json.dumps(container_data.get('custom_data', {}))
|
|
|
|
cursor.execute('''
|
|
INSERT OR REPLACE INTO applications
|
|
(container_id, container_name, display_name, icon, color, description, url, custom_data, updated_at)
|
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, CURRENT_TIMESTAMP)
|
|
''', (container_id, container_name, display_name, icon, color, description, url, custom_data))
|
|
|
|
conn.commit()
|
|
conn.close()
|
|
|
|
def get_applications(self):
|
|
"""Get all applications"""
|
|
conn = self.get_connection()
|
|
cursor = conn.cursor()
|
|
|
|
cursor.execute('''
|
|
SELECT container_id, container_name, display_name, icon, color, description, url, custom_data
|
|
FROM applications
|
|
ORDER BY display_name
|
|
''')
|
|
|
|
results = cursor.fetchall()
|
|
conn.close()
|
|
|
|
applications = []
|
|
for row in results:
|
|
app = {
|
|
'container_id': row[0],
|
|
'container_name': row[1],
|
|
'display_name': row[2],
|
|
'icon': row[3],
|
|
'color': row[4],
|
|
'description': row[5],
|
|
'url': row[6],
|
|
'custom_data': json.loads(row[7]) if row[7] else {}
|
|
}
|
|
applications.append(app)
|
|
|
|
return applications
|
|
|
|
def get_application(self, container_id):
|
|
"""Get specific application by container_id"""
|
|
conn = self.get_connection()
|
|
cursor = conn.cursor()
|
|
|
|
cursor.execute('''
|
|
SELECT container_id, container_name, display_name, icon, color, description, url, custom_data
|
|
FROM applications
|
|
WHERE container_id = ?
|
|
''', (container_id,))
|
|
|
|
result = cursor.fetchone()
|
|
conn.close()
|
|
|
|
if result:
|
|
return {
|
|
'container_id': result[0],
|
|
'container_name': result[1],
|
|
'display_name': result[2],
|
|
'icon': result[3],
|
|
'color': result[4],
|
|
'description': result[5],
|
|
'url': result[6],
|
|
'custom_data': json.loads(result[7]) if result[7] else {}
|
|
}
|
|
|
|
return None
|
|
|
|
def update_application(self, container_id, updates):
|
|
"""Update application data"""
|
|
conn = self.get_connection()
|
|
cursor = conn.cursor()
|
|
|
|
set_clause = []
|
|
values = []
|
|
|
|
for key, value in updates.items():
|
|
if key == 'custom_data':
|
|
value = json.dumps(value)
|
|
set_clause.append(f"{key} = ?")
|
|
values.append(value)
|
|
|
|
if set_clause:
|
|
set_clause.append("updated_at = CURRENT_TIMESTAMP")
|
|
values.append(container_id)
|
|
|
|
query = f"UPDATE applications SET {', '.join(set_clause)} WHERE container_id = ?"
|
|
cursor.execute(query, values)
|
|
conn.commit()
|
|
|
|
conn.close()
|
|
|
|
def delete_application(self, container_id):
|
|
"""Delete application"""
|
|
conn = self.get_connection()
|
|
cursor = conn.cursor()
|
|
|
|
cursor.execute('DELETE FROM applications WHERE container_id = ?', (container_id,))
|
|
conn.commit()
|
|
conn.close()
|
|
|
|
def sync_with_containers(self, containers):
|
|
"""Sync applications with current containers"""
|
|
conn = self.get_connection()
|
|
cursor = conn.cursor()
|
|
|
|
# Get existing container IDs
|
|
cursor.execute('SELECT container_id FROM applications')
|
|
existing_ids = {row[0] for row in cursor.fetchall()}
|
|
|
|
# Insert new containers
|
|
for container in containers:
|
|
container_id = container.get('id')
|
|
if container_id not in existing_ids:
|
|
self.upsert_application({
|
|
'id': container_id,
|
|
'name': container.get('name', ''),
|
|
'description': container.get('image', ''),
|
|
'url': self._generate_url_from_ports(container.get('ports', []))
|
|
})
|
|
|
|
conn.close()
|
|
|
|
def _generate_url_from_ports(self, ports):
|
|
"""Generate URL from container ports"""
|
|
if ports and len(ports) > 0:
|
|
port = ports[0]
|
|
return f"http://localhost:{port.get('host_port', port.get('private_port', 80))}"
|
|
return '#'
|
|
|
|
# Global database instance
|
|
db = DatabaseManager()
|