From e8ee829577841630adf2ccf808f945e97f8e8f69 Mon Sep 17 00:00:00 2001 From: CanbiZ <47820557+MickLesk@users.noreply.github.com> Date: Fri, 28 Nov 2025 13:50:44 +0100 Subject: [PATCH] Add explicit type annotations and return types This commit adds TypeScript type definitions for database entities and updates all methods in DatabaseServicePrisma to use explicit type annotations and return types. This improves type safety, code clarity, and maintainability by ensuring consistent return values and better integration with Prisma-generated types. --- src/server/database-prisma.ts | 280 +++++++++++++++++++++++----------- 1 file changed, 190 insertions(+), 90 deletions(-) diff --git a/src/server/database-prisma.ts b/src/server/database-prisma.ts index dcbee5a..b7de9ac 100644 --- a/src/server/database-prisma.ts +++ b/src/server/database-prisma.ts @@ -1,16 +1,117 @@ - import { prisma } from './db'; import { join } from 'path'; import { writeFileSync, unlinkSync, chmodSync, mkdirSync } from 'fs'; import { existsSync } from 'fs'; import type { CreateServerData } from '../types/server'; +import type { Prisma } from '../../prisma/generated/prisma/client'; + +// Type definitions based on Prisma schema +type Server = { + id: number; + name: string; + ip: string; + user: string; + password: string | null; + auth_type: string | null; + ssh_key: string | null; + ssh_key_passphrase: string | null; + ssh_port: number | null; + color: string | null; + created_at: Date | null; + updated_at: Date | null; + ssh_key_path: string | null; + key_generated: boolean | null; +}; + +type InstalledScript = { + id: number; + script_name: string; + script_path: string; + container_id: string | null; + server_id: number | null; + execution_mode: string; + installation_date: Date | null; + status: string; + output_log: string | null; + web_ui_ip: string | null; + web_ui_port: number | null; +}; + +type InstalledScriptWithServer = InstalledScript & { + server: Server | null; +}; + +type LXCConfig = { + id: number; + installed_script_id: number; + arch: string | null; + cores: number | null; + memory: number | null; + hostname: string | null; + swap: number | null; + onboot: number | null; + ostype: string | null; + unprivileged: number | null; + net_name: string | null; + net_bridge: string | null; + net_hwaddr: string | null; + net_ip_type: string | null; + net_ip: string | null; + net_gateway: string | null; + net_type: string | null; + net_vlan: number | null; + rootfs_storage: string | null; + rootfs_size: string | null; + feature_keyctl: number | null; + feature_nesting: number | null; + feature_fuse: number | null; + feature_mount: string | null; + tags: string | null; + advanced_config: string | null; + synced_at: Date | null; + config_hash: string | null; + created_at: Date; + updated_at: Date; +}; + +type Backup = { + id: number; + container_id: string; + server_id: number; + hostname: string; + backup_name: string; + backup_path: string; + size: bigint | null; + created_at: Date | null; + storage_name: string; + storage_type: string; + discovered_at: Date; +}; + +type BackupWithServer = Backup & { + server: Server | null; +}; + +type PBSStorageCredential = { + id: number; + server_id: number; + storage_name: string; + pbs_ip: string; + pbs_datastore: string; + pbs_password: string; + pbs_fingerprint: string; + created_at: Date; + updated_at: Date; +}; + +type LXCConfigInput = Partial>; class DatabaseServicePrisma { constructor() { this.init(); } - init() { + init(): void { // Ensure data/ssh-keys directory exists (recursive to create parent dirs) const sshKeysDir = join(process.cwd(), 'data', 'ssh-keys'); if (!existsSync(sshKeysDir)) { @@ -19,11 +120,11 @@ class DatabaseServicePrisma { } // Server CRUD operations - async createServer(serverData: CreateServerData) { + async createServer(serverData: CreateServerData): Promise { const { name, ip, user, password, auth_type, ssh_key, ssh_key_passphrase, ssh_port, color, key_generated } = serverData; const normalizedPort = ssh_port !== undefined ? parseInt(String(ssh_port), 10) : 22; - let ssh_key_path = null; + let ssh_key_path: string | null = null; // If using SSH key authentication, create persistent key file if (auth_type === 'key' && ssh_key) { @@ -31,7 +132,7 @@ class DatabaseServicePrisma { ssh_key_path = this.createSSHKeyFile(serverId, ssh_key); } - return await prisma.server.create({ + const result = await prisma.server.create({ data: { name, ip, @@ -46,27 +147,30 @@ class DatabaseServicePrisma { color, } }); + return result as Server; } - async getAllServers() { - return await prisma.server.findMany({ + async getAllServers(): Promise { + const result = await prisma.server.findMany({ orderBy: { created_at: 'desc' } }); + return result as Server[]; } - async getServerById(id: number) { - return await prisma.server.findUnique({ + async getServerById(id: number): Promise { + const result = await prisma.server.findUnique({ where: { id } }); + return result as Server | null; } - async updateServer(id: number, serverData: CreateServerData) { + async updateServer(id: number, serverData: CreateServerData): Promise { const { name, ip, user, password, auth_type, ssh_key, ssh_key_passphrase, ssh_port, color, key_generated } = serverData; const normalizedPort = ssh_port !== undefined ? parseInt(String(ssh_port), 10) : undefined; // Get existing server to check for key changes const existingServer = await this.getServerById(id); - let ssh_key_path = existingServer?.ssh_key_path; + let ssh_key_path = existingServer?.ssh_key_path ?? null; // Handle SSH key changes if (auth_type === 'key' && ssh_key) { @@ -102,7 +206,7 @@ class DatabaseServicePrisma { ssh_key_path = null; } - return await prisma.server.update({ + const result = await prisma.server.update({ where: { id }, data: { name, @@ -118,9 +222,10 @@ class DatabaseServicePrisma { color, } }); + return result as Server; } - async deleteServer(id: number) { + async deleteServer(id: number): Promise { // Get server info before deletion to clean up key files const server = await this.getServerById(id); @@ -137,9 +242,10 @@ class DatabaseServicePrisma { } } - return await prisma.server.delete({ + const result = await prisma.server.delete({ where: { id } }); + return result as Server; } // Installed Scripts CRUD operations @@ -153,10 +259,10 @@ class DatabaseServicePrisma { output_log?: string; web_ui_ip?: string; web_ui_port?: number; - }) { + }): Promise { const { script_name, script_path, container_id, server_id, execution_mode, status, output_log, web_ui_ip, web_ui_port } = scriptData; - return await prisma.installedScript.create({ + const result = await prisma.installedScript.create({ data: { script_name, script_path, @@ -169,34 +275,38 @@ class DatabaseServicePrisma { web_ui_port: web_ui_port ?? null, } }); + return result as InstalledScript; } - async getAllInstalledScripts() { - return await prisma.installedScript.findMany({ + async getAllInstalledScripts(): Promise { + const result = await prisma.installedScript.findMany({ include: { server: true }, orderBy: { installation_date: 'desc' } }); + return result as InstalledScriptWithServer[]; } - async getInstalledScriptById(id: number) { - return await prisma.installedScript.findUnique({ + async getInstalledScriptById(id: number): Promise { + const result = await prisma.installedScript.findUnique({ where: { id }, include: { server: true } }); + return result as InstalledScriptWithServer | null; } - async getInstalledScriptsByServer(server_id: number) { - return await prisma.installedScript.findMany({ + async getInstalledScriptsByServer(server_id: number): Promise { + const result = await prisma.installedScript.findMany({ where: { server_id }, include: { server: true }, orderBy: { installation_date: 'desc' } }); + return result as InstalledScriptWithServer[]; } async updateInstalledScript(id: number, updateData: { @@ -206,17 +316,10 @@ class DatabaseServicePrisma { output_log?: string; web_ui_ip?: string; web_ui_port?: number; - }) { + }): Promise { const { script_name, container_id, status, output_log, web_ui_ip, web_ui_port } = updateData; - const updateFields: { - script_name?: string; - container_id?: string; - status?: 'in_progress' | 'success' | 'failed'; - output_log?: string; - web_ui_ip?: string; - web_ui_port?: number; - } = {}; + const updateFields: Prisma.InstalledScriptUpdateInput = {}; if (script_name !== undefined) updateFields.script_name = script_name; if (container_id !== undefined) updateFields.container_id = container_id; if (status !== undefined) updateFields.status = status; @@ -228,33 +331,36 @@ class DatabaseServicePrisma { return { changes: 0 }; } - return await prisma.installedScript.update({ + const result = await prisma.installedScript.update({ where: { id }, data: updateFields }); + return result as InstalledScript; } - async deleteInstalledScript(id: number) { - return await prisma.installedScript.delete({ + async deleteInstalledScript(id: number): Promise { + const result = await prisma.installedScript.delete({ where: { id } }); + return result as InstalledScript; } - async deleteInstalledScriptsByServer(server_id: number) { - return await prisma.installedScript.deleteMany({ + async deleteInstalledScriptsByServer(server_id: number): Promise<{ count: number }> { + const result = await prisma.installedScript.deleteMany({ where: { server_id } }); + return result as { count: number }; } - async getNextServerId() { + async getNextServerId(): Promise { const result = await prisma.server.findFirst({ orderBy: { id: 'desc' }, select: { id: true } }); - return (result?.id ?? 0) + 1; + return ((result as { id: number } | null)?.id ?? 0) + 1; } - createSSHKeyFile(serverId: number, sshKey: string) { + createSSHKeyFile(serverId: number, sshKey: string): string { const sshKeysDir = join(process.cwd(), 'data', 'ssh-keys'); const keyPath = join(sshKeysDir, `server_${serverId}_key`); @@ -267,17 +373,18 @@ class DatabaseServicePrisma { } // LXC Config CRUD operations - async createLXCConfig(scriptId: number, configData: any) { - return await prisma.lXCConfig.create({ + async createLXCConfig(scriptId: number, configData: LXCConfigInput): Promise { + const result = await prisma.lXCConfig.create({ data: { installed_script_id: scriptId, ...configData } }); + return result as LXCConfig; } - async updateLXCConfig(scriptId: number, configData: any) { - return await prisma.lXCConfig.upsert({ + async updateLXCConfig(scriptId: number, configData: LXCConfigInput): Promise { + const result = await prisma.lXCConfig.upsert({ where: { installed_script_id: scriptId }, update: configData, create: { @@ -285,16 +392,18 @@ class DatabaseServicePrisma { ...configData } }); + return result as LXCConfig; } - async getLXCConfigByScriptId(scriptId: number) { - return await prisma.lXCConfig.findUnique({ + async getLXCConfigByScriptId(scriptId: number): Promise { + const result = await prisma.lXCConfig.findUnique({ where: { installed_script_id: scriptId } }); + return result as LXCConfig | null; } - async deleteLXCConfig(scriptId: number) { - return await prisma.lXCConfig.delete({ + async deleteLXCConfig(scriptId: number): Promise { + await prisma.lXCConfig.delete({ where: { installed_script_id: scriptId } }); } @@ -310,7 +419,7 @@ class DatabaseServicePrisma { created_at?: Date; storage_name: string; storage_type: 'local' | 'storage' | 'pbs'; - }) { + }): Promise { // Find existing backup by container_id, server_id, and backup_path const existing = await prisma.backup.findFirst({ where: { @@ -318,11 +427,11 @@ class DatabaseServicePrisma { server_id: backupData.server_id, backup_path: backupData.backup_path, }, - }); + }) as Backup | null; if (existing) { // Update existing backup - return await prisma.backup.update({ + const result = await prisma.backup.update({ where: { id: existing.id }, data: { hostname: backupData.hostname, @@ -334,9 +443,10 @@ class DatabaseServicePrisma { discovered_at: new Date(), }, }); + return result as Backup; } else { // Create new backup - return await prisma.backup.create({ + const result = await prisma.backup.create({ data: { container_id: backupData.container_id, server_id: backupData.server_id, @@ -350,11 +460,12 @@ class DatabaseServicePrisma { discovered_at: new Date(), }, }); + return result as Backup; } } - async getAllBackups() { - return await prisma.backup.findMany({ + async getAllBackups(): Promise { + const result = await prisma.backup.findMany({ include: { server: true, }, @@ -363,58 +474,43 @@ class DatabaseServicePrisma { { created_at: 'desc' }, ], }); + return result as BackupWithServer[]; } - async getBackupById(id: number) { - return await prisma.backup.findUnique({ + async getBackupById(id: number): Promise { + const result = await prisma.backup.findUnique({ where: { id }, include: { server: true, }, }); + return result as BackupWithServer | null; } - async getBackupsByContainerId(containerId: string) { - return await prisma.backup.findMany({ + async getBackupsByContainerId(containerId: string): Promise { + const result = await prisma.backup.findMany({ where: { container_id: containerId }, include: { server: true, }, orderBy: { created_at: 'desc' }, }); + return result as BackupWithServer[]; } - async deleteBackupsForContainer(containerId: string, serverId: number) { - return await prisma.backup.deleteMany({ + async deleteBackupsForContainer(containerId: string, serverId: number): Promise<{ count: number }> { + const result = await prisma.backup.deleteMany({ where: { container_id: containerId, server_id: serverId, }, }); + return result as { count: number }; } - async getBackupsGroupedByContainer(): Promise>> { + async getBackupsGroupedByContainer(): Promise> { const backups = await this.getAllBackups(); - const grouped = new Map(); + const grouped = new Map(); for (const backup of backups) { const key = backup.container_id; @@ -435,8 +531,8 @@ class DatabaseServicePrisma { pbs_datastore: string; pbs_password: string; pbs_fingerprint: string; - }) { - return await prisma.pBSStorageCredential.upsert({ + }): Promise { + const result = await prisma.pBSStorageCredential.upsert({ where: { server_id_storage_name: { server_id: credentialData.server_id, @@ -459,10 +555,11 @@ class DatabaseServicePrisma { pbs_fingerprint: credentialData.pbs_fingerprint, }, }); + return result as PBSStorageCredential; } - async getPBSCredential(serverId: number, storageName: string) { - return await prisma.pBSStorageCredential.findUnique({ + async getPBSCredential(serverId: number, storageName: string): Promise { + const result = await prisma.pBSStorageCredential.findUnique({ where: { server_id_storage_name: { server_id: serverId, @@ -470,17 +567,19 @@ class DatabaseServicePrisma { }, }, }); + return result as PBSStorageCredential | null; } - async getPBSCredentialsByServer(serverId: number) { - return await prisma.pBSStorageCredential.findMany({ + async getPBSCredentialsByServer(serverId: number): Promise { + const result = await prisma.pBSStorageCredential.findMany({ where: { server_id: serverId }, orderBy: { storage_name: 'asc' }, }); + return result as PBSStorageCredential[]; } - async deletePBSCredential(serverId: number, storageName: string) { - return await prisma.pBSStorageCredential.delete({ + async deletePBSCredential(serverId: number, storageName: string): Promise { + const result = await prisma.pBSStorageCredential.delete({ where: { server_id_storage_name: { server_id: serverId, @@ -488,9 +587,10 @@ class DatabaseServicePrisma { }, }, }); + return result as PBSStorageCredential; } - async close() { + async close(): Promise { await prisma.$disconnect(); } } @@ -498,7 +598,7 @@ class DatabaseServicePrisma { // Singleton instance let dbInstance: DatabaseServicePrisma | null = null; -export function getDatabase() { +export function getDatabase(): DatabaseServicePrisma { dbInstance ??= new DatabaseServicePrisma(); return dbInstance; }