Files
DentalManagement09/apps/Backend/src/storage/patientDocuments-storage.ts
T
2026-04-04 22:13:55 -04:00

180 lines
5.0 KiB
TypeScript
Executable File

import { PatientDocument, CreatePatientDocument } from "@repo/db/types";
import { prisma as db } from "@repo/db/client";
import path from "path";
import fs from "fs/promises";
import { randomBytes } from "crypto";
const UPLOAD_DIR = path.join(process.cwd(), "uploads", "patient-documents");
// Get local file path from URL
const getLocalFilePath = (fileUrl: string): string => {
const filename = fileUrl.split('/').pop() || '';
return path.join(UPLOAD_DIR, filename);
};
// Get the base URL for serving files
const getBaseUrl = (): string => {
// For development, use localhost instead of 0.0.0.0
const host = process.env.HOST === '0.0.0.0' ? 'localhost' : (process.env.HOST || 'localhost');
const port = process.env.PORT || '5000';
const protocol = process.env.NODE_ENV === 'production' ? 'https' : 'http';
return `${protocol}://${host}:${port}`;
};
// Ensure upload directory exists
const ensureUploadDir = async () => {
try {
await fs.access(UPLOAD_DIR);
} catch {
await fs.mkdir(UPLOAD_DIR, { recursive: true });
}
};
// Generate unique filename
const generateUniqueFilename = (originalName: string): string => {
const ext = path.extname(originalName);
const name = path.basename(originalName, ext);
const timestamp = Date.now();
const random = randomBytes(4).toString("hex");
return `${name}-${timestamp}-${random}${ext}`;
};
export const patientDocumentsStorage = {
// Create a new patient document
createPatientDocument: async (
patientId: number,
filename: string,
originalName: string,
mimeType: string,
fileSize: number,
buffer: Buffer
): Promise<PatientDocument> => {
await ensureUploadDir();
const uniqueFilename = generateUniqueFilename(filename);
const localFilePath = path.join(UPLOAD_DIR, uniqueFilename);
// Save file to disk
await fs.writeFile(localFilePath, buffer);
// Create the full URL for accessing the file using the uploads directory structure
const fileUrl = `${getBaseUrl()}/uploads/patient-documents/${uniqueFilename}`;
// Create database record with full URL
const document = await db.patientDocument.create({
data: {
patientId,
filename: uniqueFilename,
originalName,
mimeType,
fileSize: BigInt(fileSize),
filePath: fileUrl, // Store the full URL instead of local path
},
});
return document;
},
// Get all documents for a patient
getDocumentsByPatientId: async (patientId: number): Promise<PatientDocument[]> => {
return await db.patientDocument.findMany({
where: { patientId },
orderBy: { uploadedAt: "desc" },
});
},
// Get a specific document by ID
getDocumentById: async (id: number): Promise<PatientDocument | null> => {
return await db.patientDocument.findUnique({
where: { id },
include: {
patient: {
select: {
firstName: true,
lastName: true,
},
},
},
});
},
// Get document file content
getDocumentFile: async (id: number): Promise<{ buffer: Buffer; document: PatientDocument } | null> => {
const document = await db.patientDocument.findUnique({
where: { id },
});
if (!document) {
return null;
}
try {
// Get local file path from the stored URL
const localFilePath = getLocalFilePath(document.filePath);
const buffer = await fs.readFile(localFilePath);
return { buffer, document };
} catch (error) {
console.error("Error reading file:", error);
return null;
}
},
// Delete a document
deleteDocument: async (id: number): Promise<boolean> => {
const document = await db.patientDocument.findUnique({
where: { id },
});
if (!document) {
return false;
}
try {
// Get local file path from the stored URL
const localFilePath = getLocalFilePath(document.filePath);
// Delete file from disk
await fs.unlink(localFilePath);
// Delete database record
await db.patientDocument.delete({
where: { id },
});
return true;
} catch (error) {
console.error("Error deleting document:", error);
return false;
}
},
// Update document metadata
updateDocument: async (id: number, data: Partial<CreatePatientDocument>): Promise<PatientDocument | null> => {
return await db.patientDocument.update({
where: { id },
data,
});
},
// Get documents with pagination
getDocumentsByPatientIdPaginated: async (
patientId: number,
limit: number,
offset: number
): Promise<{ documents: PatientDocument[]; total: number }> => {
const [documents, total] = await Promise.all([
db.patientDocument.findMany({
where: { patientId },
orderBy: { uploadedAt: "desc" },
skip: offset,
take: limit,
}),
db.patientDocument.count({
where: { patientId },
}),
]);
return { documents, total };
},
};