feat(nestjs): migrate to NestJS

This commit is contained in:
Ahmed Bouhuolia
2025-04-07 11:51:24 +02:00
parent f068218a16
commit 55fcc908ef
3779 changed files with 631 additions and 195332 deletions

View File

@@ -0,0 +1,75 @@
import { Inject, Injectable } from '@nestjs/common';
import path from 'path';
import { promises as fs } from 'fs';
import { PageProperties, PdfFormat } from '@/libs/Chromiumly/_types';
import { UrlConverter } from '@/libs/Chromiumly/UrlConvert';
import { Chromiumly } from '@/libs/Chromiumly/Chromiumly';
import {
PDF_FILE_EXPIRE_IN,
getPdfFilePath,
getPdfFilesStorageDir,
} from './utils';
import { Document } from './models/Document';
import { TenantModelProxy } from '../System/models/TenantBaseModel';
@Injectable()
export class ChromiumlyHtmlConvert {
/**
* @param {TenantModelProxy<typeof Document>} documentModel - Document model.
*/
constructor(
@Inject(Document.name)
private documentModel: TenantModelProxy<typeof Document>,
) {}
/**
* Write HTML content to temporary file.
* @param {string} content - HTML content.
* @returns {Promise<[string, () => Promise<void>]>}
*/
async writeTempHtmlFile(
content: string,
): Promise<[string, () => Promise<void>]> {
const filename = `document-print-${Date.now()}.html`;
const filePath = getPdfFilePath(filename);
await fs.writeFile(filePath, content);
await this.documentModel()
.query()
.insert({ key: filename, mimeType: 'text/html' });
const cleanup = async () => {
await fs.unlink(filePath);
await Document.query().where('key', filename).delete();
};
return [filename, cleanup];
}
/**
* Converts the given HTML content to PDF.
* @param {string} html
* @param {PageProperties} properties
* @param {PdfFormat} pdfFormat
* @returns {Array<Buffer>}
*/
async convert(
html: string,
properties?: PageProperties,
pdfFormat?: PdfFormat,
): Promise<Buffer> {
const [filename, cleanupTempFile] = await this.writeTempHtmlFile(html);
const fileDir = getPdfFilesStorageDir(filename);
const url = path.join(Chromiumly.GOTENBERG_DOCS_ENDPOINT, fileDir);
const urlConverter = new UrlConverter();
const buffer = await urlConverter.convert({
url,
properties,
pdfFormat,
});
await cleanupTempFile();
return buffer;
}
}

View File

@@ -0,0 +1,9 @@
import { Module } from '@nestjs/common';
import { ChromiumlyHtmlConvert } from './ChromiumlyHtmlConvert.service';
import { ChromiumlyTenancy } from './ChromiumlyTenancy.service';
@Module({
providers: [ChromiumlyHtmlConvert, ChromiumlyTenancy],
exports: [ChromiumlyHtmlConvert, ChromiumlyTenancy],
})
export class ChromiumlyTenancyModule {}

View File

@@ -0,0 +1,27 @@
import { PageProperties, PdfFormat } from '@/libs/Chromiumly/_types';
import { ChromiumlyHtmlConvert } from './ChromiumlyHtmlConvert.service';
import { Injectable } from '@nestjs/common';
@Injectable()
export class ChromiumlyTenancy {
constructor(private htmlConvert: ChromiumlyHtmlConvert) {}
/**
* Converts the given HTML content to PDF.
* @param {string} content
* @param {PageProperties} properties
* @param {PdfFormat} pdfFormat
* @returns {Promise<Buffer>}
*/
public convertHtmlContent(
content: string,
properties?: PageProperties,
pdfFormat?: PdfFormat
) {
const parsedProperties = {
margins: { top: 0, bottom: 0, left: 0, right: 0 },
...properties,
}
return this.htmlConvert.convert(content, parsedProperties, pdfFormat);
}
}

View File

@@ -0,0 +1,26 @@
import { mixin } from 'objection';
// import TenantModel from 'models/TenantModel';
// import ModelSetting from './ModelSetting';
// import ModelSearchable from './ModelSearchable';
import { BaseModel } from '@/models/Model';
export class Document extends BaseModel {
public key: string;
public mimeType: string;
public size?: number;
public originName?: string;
/**
* Table name
*/
static get tableName() {
return 'documents';
}
/**
* Model timestamps.
*/
get timestamps() {
return ['createdAt', 'updatedAt'];
}
}

View File

@@ -0,0 +1,47 @@
import { Model, mixin } from 'objection';
// import TenantModel from 'models/TenantModel';
// import ModelSetting from './ModelSetting';
// import ModelSearchable from './ModelSearchable';
import { BaseModel } from '@/models/Model';
export class DocumentLink extends BaseModel{
public modelRef: string;
public modelId: number;
public documentId: number;
public expiresAt?: Date;
/**
* Table name
*/
static get tableName() {
return 'document_links';
}
/**
* Model timestamps.
*/
get timestamps() {
return ['createdAt', 'updatedAt'];
}
/**
* Relationship mapping.
*/
static get relationMappings() {
const Document = require('./Document');
return {
/**
* Sale invoice associated entries.
*/
document: {
relation: Model.HasOneRelation,
modelClass: Document.default,
join: {
from: 'document_links.documentId',
to: 'documents.id',
},
},
};
}
}

View File

@@ -0,0 +1,14 @@
import path from 'path';
export const PDF_FILE_SUB_DIR = '/pdf';
export const PDF_FILE_EXPIRE_IN = 40; // ms
export const getPdfFilesStorageDir = (filename: string) => {
return path.join(PDF_FILE_SUB_DIR, filename);
};
export const getPdfFilePath = (filename: string) => {
const storageDir = getPdfFilesStorageDir(filename);
return path.join(global.__storage_dir, storageDir);
};