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.
This commit is contained in:
CanbiZ
2025-11-28 13:50:44 +01:00
parent aebc8a6171
commit e8ee829577

View File

@@ -1,16 +1,117 @@
import { prisma } from './db'; import { prisma } from './db';
import { join } from 'path'; import { join } from 'path';
import { writeFileSync, unlinkSync, chmodSync, mkdirSync } from 'fs'; import { writeFileSync, unlinkSync, chmodSync, mkdirSync } from 'fs';
import { existsSync } from 'fs'; import { existsSync } from 'fs';
import type { CreateServerData } from '../types/server'; 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<Omit<LXCConfig, 'id' | 'installed_script_id' | 'created_at' | 'updated_at'>>;
class DatabaseServicePrisma { class DatabaseServicePrisma {
constructor() { constructor() {
this.init(); this.init();
} }
init() { init(): void {
// Ensure data/ssh-keys directory exists (recursive to create parent dirs) // Ensure data/ssh-keys directory exists (recursive to create parent dirs)
const sshKeysDir = join(process.cwd(), 'data', 'ssh-keys'); const sshKeysDir = join(process.cwd(), 'data', 'ssh-keys');
if (!existsSync(sshKeysDir)) { if (!existsSync(sshKeysDir)) {
@@ -19,11 +120,11 @@ class DatabaseServicePrisma {
} }
// Server CRUD operations // Server CRUD operations
async createServer(serverData: CreateServerData) { async createServer(serverData: CreateServerData): Promise<Server> {
const { name, ip, user, password, auth_type, ssh_key, ssh_key_passphrase, ssh_port, color, key_generated } = serverData; 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; 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 using SSH key authentication, create persistent key file
if (auth_type === 'key' && ssh_key) { if (auth_type === 'key' && ssh_key) {
@@ -31,7 +132,7 @@ class DatabaseServicePrisma {
ssh_key_path = this.createSSHKeyFile(serverId, ssh_key); ssh_key_path = this.createSSHKeyFile(serverId, ssh_key);
} }
return await prisma.server.create({ const result = await prisma.server.create({
data: { data: {
name, name,
ip, ip,
@@ -46,27 +147,30 @@ class DatabaseServicePrisma {
color, color,
} }
}); });
return result as Server;
} }
async getAllServers() { async getAllServers(): Promise<Server[]> {
return await prisma.server.findMany({ const result = await prisma.server.findMany({
orderBy: { created_at: 'desc' } orderBy: { created_at: 'desc' }
}); });
return result as Server[];
} }
async getServerById(id: number) { async getServerById(id: number): Promise<Server | null> {
return await prisma.server.findUnique({ const result = await prisma.server.findUnique({
where: { id } where: { id }
}); });
return result as Server | null;
} }
async updateServer(id: number, serverData: CreateServerData) { async updateServer(id: number, serverData: CreateServerData): Promise<Server> {
const { name, ip, user, password, auth_type, ssh_key, ssh_key_passphrase, ssh_port, color, key_generated } = serverData; 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; const normalizedPort = ssh_port !== undefined ? parseInt(String(ssh_port), 10) : undefined;
// Get existing server to check for key changes // Get existing server to check for key changes
const existingServer = await this.getServerById(id); 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 // Handle SSH key changes
if (auth_type === 'key' && ssh_key) { if (auth_type === 'key' && ssh_key) {
@@ -102,7 +206,7 @@ class DatabaseServicePrisma {
ssh_key_path = null; ssh_key_path = null;
} }
return await prisma.server.update({ const result = await prisma.server.update({
where: { id }, where: { id },
data: { data: {
name, name,
@@ -118,9 +222,10 @@ class DatabaseServicePrisma {
color, color,
} }
}); });
return result as Server;
} }
async deleteServer(id: number) { async deleteServer(id: number): Promise<Server> {
// Get server info before deletion to clean up key files // Get server info before deletion to clean up key files
const server = await this.getServerById(id); 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 } where: { id }
}); });
return result as Server;
} }
// Installed Scripts CRUD operations // Installed Scripts CRUD operations
@@ -153,10 +259,10 @@ class DatabaseServicePrisma {
output_log?: string; output_log?: string;
web_ui_ip?: string; web_ui_ip?: string;
web_ui_port?: number; web_ui_port?: number;
}) { }): Promise<InstalledScript> {
const { script_name, script_path, container_id, server_id, execution_mode, status, output_log, web_ui_ip, web_ui_port } = scriptData; 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: { data: {
script_name, script_name,
script_path, script_path,
@@ -169,34 +275,38 @@ class DatabaseServicePrisma {
web_ui_port: web_ui_port ?? null, web_ui_port: web_ui_port ?? null,
} }
}); });
return result as InstalledScript;
} }
async getAllInstalledScripts() { async getAllInstalledScripts(): Promise<InstalledScriptWithServer[]> {
return await prisma.installedScript.findMany({ const result = await prisma.installedScript.findMany({
include: { include: {
server: true server: true
}, },
orderBy: { installation_date: 'desc' } orderBy: { installation_date: 'desc' }
}); });
return result as InstalledScriptWithServer[];
} }
async getInstalledScriptById(id: number) { async getInstalledScriptById(id: number): Promise<InstalledScriptWithServer | null> {
return await prisma.installedScript.findUnique({ const result = await prisma.installedScript.findUnique({
where: { id }, where: { id },
include: { include: {
server: true server: true
} }
}); });
return result as InstalledScriptWithServer | null;
} }
async getInstalledScriptsByServer(server_id: number) { async getInstalledScriptsByServer(server_id: number): Promise<InstalledScriptWithServer[]> {
return await prisma.installedScript.findMany({ const result = await prisma.installedScript.findMany({
where: { server_id }, where: { server_id },
include: { include: {
server: true server: true
}, },
orderBy: { installation_date: 'desc' } orderBy: { installation_date: 'desc' }
}); });
return result as InstalledScriptWithServer[];
} }
async updateInstalledScript(id: number, updateData: { async updateInstalledScript(id: number, updateData: {
@@ -206,17 +316,10 @@ class DatabaseServicePrisma {
output_log?: string; output_log?: string;
web_ui_ip?: string; web_ui_ip?: string;
web_ui_port?: number; web_ui_port?: number;
}) { }): Promise<InstalledScript | { changes: number }> {
const { script_name, container_id, status, output_log, web_ui_ip, web_ui_port } = updateData; const { script_name, container_id, status, output_log, web_ui_ip, web_ui_port } = updateData;
const updateFields: { const updateFields: Prisma.InstalledScriptUpdateInput = {};
script_name?: string;
container_id?: string;
status?: 'in_progress' | 'success' | 'failed';
output_log?: string;
web_ui_ip?: string;
web_ui_port?: number;
} = {};
if (script_name !== undefined) updateFields.script_name = script_name; if (script_name !== undefined) updateFields.script_name = script_name;
if (container_id !== undefined) updateFields.container_id = container_id; if (container_id !== undefined) updateFields.container_id = container_id;
if (status !== undefined) updateFields.status = status; if (status !== undefined) updateFields.status = status;
@@ -228,33 +331,36 @@ class DatabaseServicePrisma {
return { changes: 0 }; return { changes: 0 };
} }
return await prisma.installedScript.update({ const result = await prisma.installedScript.update({
where: { id }, where: { id },
data: updateFields data: updateFields
}); });
return result as InstalledScript;
} }
async deleteInstalledScript(id: number) { async deleteInstalledScript(id: number): Promise<InstalledScript> {
return await prisma.installedScript.delete({ const result = await prisma.installedScript.delete({
where: { id } where: { id }
}); });
return result as InstalledScript;
} }
async deleteInstalledScriptsByServer(server_id: number) { async deleteInstalledScriptsByServer(server_id: number): Promise<{ count: number }> {
return await prisma.installedScript.deleteMany({ const result = await prisma.installedScript.deleteMany({
where: { server_id } where: { server_id }
}); });
return result as { count: number };
} }
async getNextServerId() { async getNextServerId(): Promise<number> {
const result = await prisma.server.findFirst({ const result = await prisma.server.findFirst({
orderBy: { id: 'desc' }, orderBy: { id: 'desc' },
select: { id: true } 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 sshKeysDir = join(process.cwd(), 'data', 'ssh-keys');
const keyPath = join(sshKeysDir, `server_${serverId}_key`); const keyPath = join(sshKeysDir, `server_${serverId}_key`);
@@ -267,17 +373,18 @@ class DatabaseServicePrisma {
} }
// LXC Config CRUD operations // LXC Config CRUD operations
async createLXCConfig(scriptId: number, configData: any) { async createLXCConfig(scriptId: number, configData: LXCConfigInput): Promise<LXCConfig> {
return await prisma.lXCConfig.create({ const result = await prisma.lXCConfig.create({
data: { data: {
installed_script_id: scriptId, installed_script_id: scriptId,
...configData ...configData
} }
}); });
return result as LXCConfig;
} }
async updateLXCConfig(scriptId: number, configData: any) { async updateLXCConfig(scriptId: number, configData: LXCConfigInput): Promise<LXCConfig> {
return await prisma.lXCConfig.upsert({ const result = await prisma.lXCConfig.upsert({
where: { installed_script_id: scriptId }, where: { installed_script_id: scriptId },
update: configData, update: configData,
create: { create: {
@@ -285,16 +392,18 @@ class DatabaseServicePrisma {
...configData ...configData
} }
}); });
return result as LXCConfig;
} }
async getLXCConfigByScriptId(scriptId: number) { async getLXCConfigByScriptId(scriptId: number): Promise<LXCConfig | null> {
return await prisma.lXCConfig.findUnique({ const result = await prisma.lXCConfig.findUnique({
where: { installed_script_id: scriptId } where: { installed_script_id: scriptId }
}); });
return result as LXCConfig | null;
} }
async deleteLXCConfig(scriptId: number) { async deleteLXCConfig(scriptId: number): Promise<void> {
return await prisma.lXCConfig.delete({ await prisma.lXCConfig.delete({
where: { installed_script_id: scriptId } where: { installed_script_id: scriptId }
}); });
} }
@@ -310,7 +419,7 @@ class DatabaseServicePrisma {
created_at?: Date; created_at?: Date;
storage_name: string; storage_name: string;
storage_type: 'local' | 'storage' | 'pbs'; storage_type: 'local' | 'storage' | 'pbs';
}) { }): Promise<Backup> {
// Find existing backup by container_id, server_id, and backup_path // Find existing backup by container_id, server_id, and backup_path
const existing = await prisma.backup.findFirst({ const existing = await prisma.backup.findFirst({
where: { where: {
@@ -318,11 +427,11 @@ class DatabaseServicePrisma {
server_id: backupData.server_id, server_id: backupData.server_id,
backup_path: backupData.backup_path, backup_path: backupData.backup_path,
}, },
}); }) as Backup | null;
if (existing) { if (existing) {
// Update existing backup // Update existing backup
return await prisma.backup.update({ const result = await prisma.backup.update({
where: { id: existing.id }, where: { id: existing.id },
data: { data: {
hostname: backupData.hostname, hostname: backupData.hostname,
@@ -334,9 +443,10 @@ class DatabaseServicePrisma {
discovered_at: new Date(), discovered_at: new Date(),
}, },
}); });
return result as Backup;
} else { } else {
// Create new backup // Create new backup
return await prisma.backup.create({ const result = await prisma.backup.create({
data: { data: {
container_id: backupData.container_id, container_id: backupData.container_id,
server_id: backupData.server_id, server_id: backupData.server_id,
@@ -350,11 +460,12 @@ class DatabaseServicePrisma {
discovered_at: new Date(), discovered_at: new Date(),
}, },
}); });
return result as Backup;
} }
} }
async getAllBackups() { async getAllBackups(): Promise<BackupWithServer[]> {
return await prisma.backup.findMany({ const result = await prisma.backup.findMany({
include: { include: {
server: true, server: true,
}, },
@@ -363,58 +474,43 @@ class DatabaseServicePrisma {
{ created_at: 'desc' }, { created_at: 'desc' },
], ],
}); });
return result as BackupWithServer[];
} }
async getBackupById(id: number) { async getBackupById(id: number): Promise<BackupWithServer | null> {
return await prisma.backup.findUnique({ const result = await prisma.backup.findUnique({
where: { id }, where: { id },
include: { include: {
server: true, server: true,
}, },
}); });
return result as BackupWithServer | null;
} }
async getBackupsByContainerId(containerId: string) { async getBackupsByContainerId(containerId: string): Promise<BackupWithServer[]> {
return await prisma.backup.findMany({ const result = await prisma.backup.findMany({
where: { container_id: containerId }, where: { container_id: containerId },
include: { include: {
server: true, server: true,
}, },
orderBy: { created_at: 'desc' }, orderBy: { created_at: 'desc' },
}); });
return result as BackupWithServer[];
} }
async deleteBackupsForContainer(containerId: string, serverId: number) { async deleteBackupsForContainer(containerId: string, serverId: number): Promise<{ count: number }> {
return await prisma.backup.deleteMany({ const result = await prisma.backup.deleteMany({
where: { where: {
container_id: containerId, container_id: containerId,
server_id: serverId, server_id: serverId,
}, },
}); });
return result as { count: number };
} }
async getBackupsGroupedByContainer(): Promise<Map<string, Array<{ async getBackupsGroupedByContainer(): Promise<Map<string, BackupWithServer[]>> {
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;
server: {
id: number;
name: string;
ip: string;
user: string;
color: string | null;
} | null;
}>>> {
const backups = await this.getAllBackups(); const backups = await this.getAllBackups();
const grouped = new Map<string, typeof backups>(); const grouped = new Map<string, BackupWithServer[]>();
for (const backup of backups) { for (const backup of backups) {
const key = backup.container_id; const key = backup.container_id;
@@ -435,8 +531,8 @@ class DatabaseServicePrisma {
pbs_datastore: string; pbs_datastore: string;
pbs_password: string; pbs_password: string;
pbs_fingerprint: string; pbs_fingerprint: string;
}) { }): Promise<PBSStorageCredential> {
return await prisma.pBSStorageCredential.upsert({ const result = await prisma.pBSStorageCredential.upsert({
where: { where: {
server_id_storage_name: { server_id_storage_name: {
server_id: credentialData.server_id, server_id: credentialData.server_id,
@@ -459,10 +555,11 @@ class DatabaseServicePrisma {
pbs_fingerprint: credentialData.pbs_fingerprint, pbs_fingerprint: credentialData.pbs_fingerprint,
}, },
}); });
return result as PBSStorageCredential;
} }
async getPBSCredential(serverId: number, storageName: string) { async getPBSCredential(serverId: number, storageName: string): Promise<PBSStorageCredential | null> {
return await prisma.pBSStorageCredential.findUnique({ const result = await prisma.pBSStorageCredential.findUnique({
where: { where: {
server_id_storage_name: { server_id_storage_name: {
server_id: serverId, server_id: serverId,
@@ -470,17 +567,19 @@ class DatabaseServicePrisma {
}, },
}, },
}); });
return result as PBSStorageCredential | null;
} }
async getPBSCredentialsByServer(serverId: number) { async getPBSCredentialsByServer(serverId: number): Promise<PBSStorageCredential[]> {
return await prisma.pBSStorageCredential.findMany({ const result = await prisma.pBSStorageCredential.findMany({
where: { server_id: serverId }, where: { server_id: serverId },
orderBy: { storage_name: 'asc' }, orderBy: { storage_name: 'asc' },
}); });
return result as PBSStorageCredential[];
} }
async deletePBSCredential(serverId: number, storageName: string) { async deletePBSCredential(serverId: number, storageName: string): Promise<PBSStorageCredential> {
return await prisma.pBSStorageCredential.delete({ const result = await prisma.pBSStorageCredential.delete({
where: { where: {
server_id_storage_name: { server_id_storage_name: {
server_id: serverId, server_id: serverId,
@@ -488,9 +587,10 @@ class DatabaseServicePrisma {
}, },
}, },
}); });
return result as PBSStorageCredential;
} }
async close() { async close(): Promise<void> {
await prisma.$disconnect(); await prisma.$disconnect();
} }
} }
@@ -498,7 +598,7 @@ class DatabaseServicePrisma {
// Singleton instance // Singleton instance
let dbInstance: DatabaseServicePrisma | null = null; let dbInstance: DatabaseServicePrisma | null = null;
export function getDatabase() { export function getDatabase(): DatabaseServicePrisma {
dbInstance ??= new DatabaseServicePrisma(); dbInstance ??= new DatabaseServicePrisma();
return dbInstance; return dbInstance;
} }