You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

101 lines
2.6 KiB

import { PrismaService } from '@ghostfolio/api/services/prisma/prisma.service';
import { HttpException, Injectable } from '@nestjs/common';
import { DocumentType } from '@prisma/client';
import { StatusCodes, getReasonPhrase } from 'http-status-codes';
import { createReadStream, existsSync } from 'node:fs';
import { mkdir } from 'node:fs/promises';
import { join } from 'node:path';
@Injectable()
export class UploadService {
private readonly uploadDir: string;
public constructor(private readonly prismaService: PrismaService) {
this.uploadDir = process.env.UPLOAD_DIR || join(process.cwd(), 'uploads');
}
public async ensureUploadDir(): Promise<void> {
if (!existsSync(this.uploadDir)) {
await mkdir(this.uploadDir, { recursive: true });
}
}
public getUploadDir(): string {
return this.uploadDir;
}
public async createDocument({
entityId,
file,
name,
partnershipId,
taxYear,
type
}: {
entityId?: string;
file: any;
name?: string;
partnershipId?: string;
taxYear?: number;
type: DocumentType;
}) {
await this.ensureUploadDir();
const now = new Date();
const yearDir = now.getFullYear().toString();
const monthDir = (now.getMonth() + 1).toString().padStart(2, '0');
const subDir = join(this.uploadDir, yearDir, monthDir);
if (!existsSync(subDir)) {
await mkdir(subDir, { recursive: true });
}
const relativePath = `${yearDir}/${monthDir}/${file.filename}`;
return this.prismaService.document.create({
data: {
entityId: entityId || undefined,
filePath: relativePath,
fileSize: file.size,
mimeType: file.mimetype,
name: name || file.originalname,
partnershipId: partnershipId || undefined,
taxYear: taxYear ? Number(taxYear) : undefined,
type
}
});
}
public async getDocumentById(documentId: string) {
const document = await this.prismaService.document.findUnique({
where: { id: documentId }
});
if (!document) {
throw new HttpException(
getReasonPhrase(StatusCodes.NOT_FOUND),
StatusCodes.NOT_FOUND
);
}
return document;
}
public async getDocumentStream(documentId: string) {
const document = await this.getDocumentById(documentId);
const fullPath = join(this.uploadDir, document.filePath);
if (!existsSync(fullPath)) {
throw new HttpException(
getReasonPhrase(StatusCodes.NOT_FOUND),
StatusCodes.NOT_FOUND
);
}
return {
document,
stream: createReadStream(fullPath)
};
}
}