"""Server records operations.""" from database_service import database_connection, dict_from_row import json from runtime_config import ( logger, ) from typing import Dict, List, Optional, Tuple from user_service import get_user_by_id import uuid __all__ = ['create_server_record', 'delete_server_record', 'get_all_servers', 'get_server_access_and_namespace', 'get_server_by_id', 'get_user_servers', 'update_server_status'] def create_server_record(server_data: Dict) -> Optional[Dict]: """Create server record""" try: with database_connection() as conn: cursor = conn.cursor() is_demo = server_data.get('is_demo', False) demo_expires_at = server_data.get('demo_expires_at') cursor.execute(''' INSERT INTO servers (id, name, type, image, version, status, cpu, ram, storage, ip, ports, owner_id, namespace, k8s_name, is_demo, demo_expires_at, java_version, loader, sftp_username, sftp_password, sftp_port) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) ''', ( server_data['id'], server_data['name'], server_data['type'], server_data['image'], server_data['version'], server_data.get('status', 'Creating'), server_data['cpu'], server_data['ram'], server_data['storage'], server_data['ip'], json.dumps(server_data['ports']), server_data['ownerId'], # This should match the key in server_data server_data.get('namespace', f"user-{server_data['ownerId']}".lower()), server_data.get('k8s_name', server_data['id']), is_demo, demo_expires_at, server_data.get('java_version'), server_data.get('loader'), server_data.get('sftp_username'), server_data.get('sftp_password'), server_data.get('sftp_port') )) conn.commit() # Return the server with owner_id field cursor.execute('SELECT * FROM servers WHERE id = ?', (server_data['id'],)) server = dict_from_row(cursor.fetchone()) if server and 'ports' in server: server['ports'] = json.loads(server['ports']) return server except Exception as e: logger.error(f"Error creating server record: {e}") return None def get_server_by_id(server_id: str) -> Optional[Dict]: """Get server by ID""" try: # Ensure server_id is a string server_id = str(server_id) with database_connection() as conn: cursor = conn.cursor() cursor.execute('SELECT * FROM servers WHERE id = ?', (server_id,)) server = dict_from_row(cursor.fetchone()) if server and 'ports' in server: server['ports'] = json.loads(server['ports']) # Add backward compatibility for ownerId field if server and 'owner_id' in server: server['ownerId'] = server['owner_id'] return server except Exception as e: return None def get_server_access_and_namespace(server_id: str, requester_id: str) -> Tuple[str, Dict]: """ Check if a user has access to a server and return the namespace and server record. Access is granted if user is the owner OR an admin. Returns (namespace, server_record) """ server = get_server_by_id(server_id) if not server: raise Exception("Server not found") requester = get_user_by_id(requester_id) if not requester: raise Exception("User not found") # Check access (ensure string comparison for IDs) # Handle both 'owner_id' and 'ownerId' keys for compatibility server_owner_id = str(server.get('owner_id') or server.get('ownerId', '')) req_id = str(requester_id) is_owner = server_owner_id == req_id is_admin = requester.get('role') == 'admin' if not is_owner and not is_admin: logger.warning(f"Access denied for user {requester_id} to server {server_id}. Owner: {server_owner_id}, Role: {requester.get('role')}") raise Exception("Access denied") # Get owner to determine namespace if is_owner: owner = requester else: owner = get_user_by_id(server_owner_id) if not owner: raise Exception("Server owner not found") namespace = f"user-{owner['username']}".lower() return namespace, server def get_user_servers(user_id: str) -> List[Dict]: """Get all servers for a user""" try: with database_connection() as conn: cursor = conn.cursor() cursor.execute('SELECT * FROM servers WHERE owner_id = ? ORDER BY created_at DESC', (user_id,)) servers = [dict_from_row(row) for row in cursor.fetchall()] for server in servers: if server and 'ports' in server: server['ports'] = json.loads(server['ports']) # Get database configuration for database servers if server and server['type'] == 'database': cursor.execute('SELECT * FROM database_configs WHERE server_id = ?', (server['id'],)) db_config = dict_from_row(cursor.fetchone()) if db_config: server['databaseConfig'] = db_config return servers except Exception as e: return [] def get_all_servers() -> List[Dict]: """Get all servers (admin only)""" try: with database_connection() as conn: cursor = conn.cursor() cursor.execute('SELECT * FROM servers ORDER BY created_at DESC') servers = [dict_from_row(row) for row in cursor.fetchall()] for server in servers: if server and 'ports' in server: try: if isinstance(server['ports'], str): server['ports'] = json.loads(server['ports']) except: server['ports'] = [] # Get database configuration for database servers if server and server['type'] == 'database': cursor.execute('SELECT * FROM database_configs WHERE server_id = ?', (server['id'],)) db_config = dict_from_row(cursor.fetchone()) if db_config: server['databaseConfig'] = db_config return servers except Exception as e: logger.error(f"Error getting all servers: {e}") return [] def update_server_status(server_id: str, status: str, message: str = "") -> bool: """Update server status""" try: with database_connection() as conn: cursor = conn.cursor() cursor.execute( 'UPDATE servers SET status = ?, updated_at = CURRENT_TIMESTAMP WHERE id = ?', (status, server_id) ) status_id = f"status-{str(uuid.uuid4())[:8]}" cursor.execute(''' INSERT INTO server_status_history (id, server_id, status, message) VALUES (?, ?, ?, ?) ''', (status_id, server_id, status, message)) conn.commit() return cursor.rowcount > 0 except Exception as e: return False def delete_server_record(server_id: str) -> bool: """Delete server record""" try: with database_connection() as conn: cursor = conn.cursor() # Delete database configuration first cursor.execute('DELETE FROM database_configs WHERE server_id = ?', (server_id,)) # Then delete server cursor.execute('DELETE FROM servers WHERE id = ?', (server_id,)) conn.commit() return cursor.rowcount > 0 except Exception as e: return False