backup page - working 1 done
This commit is contained in:
116
apps/Backend/src/routes/database-management.ts
Normal file
116
apps/Backend/src/routes/database-management.ts
Normal file
@@ -0,0 +1,116 @@
|
||||
import { Router, Request, Response } from "express";
|
||||
import { spawn } from "child_process";
|
||||
import path from "path";
|
||||
import os from "os";
|
||||
import fs from "fs";
|
||||
import { prisma } from "@repo/db/client";
|
||||
|
||||
const router = Router();
|
||||
|
||||
/**
|
||||
* Create a database backup
|
||||
*/
|
||||
|
||||
router.post("/backup", async (req: Request, res: Response) => {
|
||||
try {
|
||||
const fileName = `dental_backup_${Date.now()}.dump`;
|
||||
const tmpFile = path.join(os.tmpdir(), fileName);
|
||||
|
||||
// Spawn pg_dump
|
||||
const pgDump = spawn(
|
||||
"pg_dump",
|
||||
[
|
||||
"-Fc", // custom format
|
||||
"--no-acl",
|
||||
"--no-owner",
|
||||
"-h",
|
||||
process.env.DB_HOST || "localhost",
|
||||
"-U",
|
||||
process.env.DB_USER || "postgres",
|
||||
process.env.DB_NAME || "dental_db",
|
||||
"-f",
|
||||
tmpFile, // write directly to temp file
|
||||
],
|
||||
{
|
||||
env: {
|
||||
...process.env,
|
||||
PGPASSWORD: process.env.DB_PASSWORD,
|
||||
},
|
||||
}
|
||||
);
|
||||
let errorMessage = "";
|
||||
|
||||
pgDump.stderr.on("data", (chunk) => {
|
||||
errorMessage += chunk.toString();
|
||||
});
|
||||
|
||||
pgDump.on("close", (code) => {
|
||||
if (code === 0) {
|
||||
// ✅ Send only if dump succeeded
|
||||
res.setHeader(
|
||||
"Content-Disposition",
|
||||
`attachment; filename=${fileName}`
|
||||
);
|
||||
res.setHeader("Content-Type", "application/octet-stream");
|
||||
|
||||
const fileStream = fs.createReadStream(tmpFile);
|
||||
fileStream.pipe(res);
|
||||
|
||||
fileStream.on("close", () => {
|
||||
fs.unlink(tmpFile, () => {}); // cleanup temp file
|
||||
});
|
||||
} else {
|
||||
console.error("pg_dump failed:", errorMessage);
|
||||
fs.unlink(tmpFile, () => {}); // cleanup
|
||||
res.status(500).json({
|
||||
error: "Backup failed",
|
||||
details: errorMessage || `pg_dump exited with code ${code}`,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
pgDump.on("error", (err) => {
|
||||
console.error("Failed to start pg_dump:", err);
|
||||
fs.unlink(tmpFile, () => {});
|
||||
res.status(500).json({
|
||||
error: "Failed to run pg_dump",
|
||||
details: err.message,
|
||||
});
|
||||
});
|
||||
} catch (err: any) {
|
||||
console.error("Unexpected error:", err);
|
||||
if (!res.headersSent) {
|
||||
res.status(500).json({
|
||||
message: "Internal server error",
|
||||
details: String(err),
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Get database status (connected, size, records count)
|
||||
*/
|
||||
router.get("/status", async (req: Request, res: Response) => {
|
||||
try {
|
||||
const size = await prisma.$queryRawUnsafe<{ size: string }[]>(
|
||||
"SELECT pg_size_pretty(pg_database_size(current_database())) as size"
|
||||
);
|
||||
|
||||
const patientsCount = await prisma.patient.count();
|
||||
|
||||
res.json({
|
||||
connected: true,
|
||||
size: size[0]?.size,
|
||||
patients: patientsCount,
|
||||
});
|
||||
} catch (err) {
|
||||
console.error("Status error:", err);
|
||||
res.status(500).json({
|
||||
connected: false,
|
||||
error: "Could not fetch database status",
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
export default router;
|
||||
@@ -1,26 +1,28 @@
|
||||
import { Router } from 'express';
|
||||
import patientsRoutes from './patients';
|
||||
import appointmentsRoutes from './appointments'
|
||||
import usersRoutes from './users'
|
||||
import staffsRoutes from './staffs'
|
||||
import pdfExtractionRoutes from './pdfExtraction';
|
||||
import claimsRoutes from './claims';
|
||||
import insuranceCredsRoutes from './insuranceCreds';
|
||||
import documentsRoutes from './documents';
|
||||
import insuranceEligibilityRoutes from './insuranceEligibility'
|
||||
import paymentsRoutes from './payments'
|
||||
import { Router } from "express";
|
||||
import patientsRoutes from "./patients";
|
||||
import appointmentsRoutes from "./appointments";
|
||||
import usersRoutes from "./users";
|
||||
import staffsRoutes from "./staffs";
|
||||
import pdfExtractionRoutes from "./pdfExtraction";
|
||||
import claimsRoutes from "./claims";
|
||||
import insuranceCredsRoutes from "./insuranceCreds";
|
||||
import documentsRoutes from "./documents";
|
||||
import insuranceEligibilityRoutes from "./insuranceEligibility";
|
||||
import paymentsRoutes from "./payments";
|
||||
import databaseManagementRoutes from "./database-management";
|
||||
|
||||
const router = Router();
|
||||
|
||||
router.use('/patients', patientsRoutes);
|
||||
router.use('/appointments', appointmentsRoutes);
|
||||
router.use('/users', usersRoutes);
|
||||
router.use('/staffs', staffsRoutes);
|
||||
router.use('/pdfExtraction', pdfExtractionRoutes);
|
||||
router.use('/claims', claimsRoutes);
|
||||
router.use('/insuranceCreds', insuranceCredsRoutes);
|
||||
router.use('/documents', documentsRoutes);
|
||||
router.use('/insuranceEligibility', insuranceEligibilityRoutes);
|
||||
router.use('/payments', paymentsRoutes);
|
||||
router.use("/patients", patientsRoutes);
|
||||
router.use("/appointments", appointmentsRoutes);
|
||||
router.use("/users", usersRoutes);
|
||||
router.use("/staffs", staffsRoutes);
|
||||
router.use("/pdfExtraction", pdfExtractionRoutes);
|
||||
router.use("/claims", claimsRoutes);
|
||||
router.use("/insuranceCreds", insuranceCredsRoutes);
|
||||
router.use("/documents", documentsRoutes);
|
||||
router.use("/insuranceEligibility", insuranceEligibilityRoutes);
|
||||
router.use("/payments", paymentsRoutes);
|
||||
router.use("/database-management", databaseManagementRoutes);
|
||||
|
||||
export default router;
|
||||
export default router;
|
||||
|
||||
Reference in New Issue
Block a user