diff --git a/src/modules/catalog/catalog.controller.ts b/src/modules/catalog/catalog.controller.ts index ab6290a..09daa16 100644 --- a/src/modules/catalog/catalog.controller.ts +++ b/src/modules/catalog/catalog.controller.ts @@ -61,6 +61,7 @@ import { RegisterDatasetWithMetatadaRequest, } from '@dadosfera/protospack-v2/dist/lib/Catalog/interfaces/messages'; import { Response } from 'express'; +import { TypeParser } from 'src/utils/FileParser/parser-types'; @ApiTags('Catalog') @ApiHeaders([{ name: 'dadosfera-lang', enum: LanguageEnum, required: false }]) @@ -864,29 +865,24 @@ export class CatalogController { @RequireModule( DADOSFERA_MODULES_KEYS.PII ) - async getPiiReporter(@User() user: RequestUser, @Res() res: Response, @Query('type') type: "html" | "csv") { + async getPiiReporter(@User() user: RequestUser, @Res() res: Response, @Query('type') contentType: TypeParser = "pdf") { this.logger.info('GET pii-reporter'); const metadata = PackTheMetadata(user); try { - const reporter = await this.catalogService.getPiiReporter(metadata, type); - - if (type === "html") { - res.setHeader('Content-Type', 'text/html'); - } else if (type === "csv") { - res.setHeader('Content-Type', 'text/csv'); - } else if (type === "pdf") { - res.setHeader('Content-Type', 'application/pdf'); - } - - const timestamp = new Date().toISOString().replace(/[:.]/g, '-'); - const filename = `relatorio-pii-${timestamp}.${type}`; - + const { + file, + filename, + type + } = await this.catalogService.getPiiReporter(metadata, contentType); res.setHeader('Content-Disposition', `attachment; filename="${filename}"`); + res.setHeader('Content-Type', type); - return res.send(reporter); + // use res.end to send buffer + return res.end(file); } catch (error) { - this.logger.error(error); + console.error(error) + this.logger.error(error.message); } } } diff --git a/src/modules/catalog/catalog.service.ts b/src/modules/catalog/catalog.service.ts index 68036c3..a3db9cc 100644 --- a/src/modules/catalog/catalog.service.ts +++ b/src/modules/catalog/catalog.service.ts @@ -33,6 +33,7 @@ import { AddRlsRuleRequest, GetNimbusDashboardsRequest, GetRlsRulesRequest, + PiiMetadata, } from '@dadosfera/protospack-v2/dist/lib/Catalog/interfaces/messages'; import { writeFileSync } from 'fs'; import path from 'path'; @@ -40,6 +41,8 @@ import { HtmlParser } from 'src/utils/FileParser/html-parser'; import { PiiDto } from './dtos/pii.dto'; import { CsvParser } from 'src/utils/FileParser/csv-parser'; import { PDFParser } from 'src/utils/FileParser/pdf-parser'; +import { TypeParser } from 'src/utils/FileParser/parser-types'; +import { ParserBuilder } from 'src/utils/FileParser/parser.builder'; class CatalogService implements OnModuleInit { catalogReadService: ReadService.CatalogReadServices; @@ -86,7 +89,8 @@ class CatalogService implements OnModuleInit { )}.dadosfera.ai`; } - async getPiiReporter(metadata: Metadata, type: "html"| "csv") { + async getPiiReporter(metadata: Metadata, type: TypeParser) { + this.logger.info('getPiiReporter: ' + type) try { const { data @@ -94,37 +98,29 @@ class CatalogService implements OnModuleInit { this.catalogWriteService.GetPiiReporter({}, metadata) ) this.logger.info("Finish grpc call") - - // 3. Ler o template HTML - const templatePath = path.join( - __dirname, - '../../../src/template/pii-reporter.html', - ); - this.logger.info("templatePath: " + templatePath); + const parser = ParserBuilder.build(type); - if (type === "html") { - const htmlParser = new HtmlParser(templatePath); - return htmlParser.parse(data); - } else if (type === "csv") { - const csvParser = new CsvParser(); - return await csvParser.parse(data) - } else if (type === "pdf") { - const htmlParser = new HtmlParser(templatePath); - const pdfParser = new PDFParser(); - const pdf = await pdfParser.parse(htmlParser.parse(data)); - const pdfPath = path.join( - __dirname, - '../../../src/template/teste.pdf', - ); - writeFileSync(pdfPath, pdf); - return pdf + this.logger.info('parser file to: ' + type) + const file = await parser.parse(data) + this.logger.info('finish parser') + const mimeTypes: Record = { + 'csv': 'text/csv', + 'html': 'text/html', + 'pdf': 'application/pdf' } - throw new Error("Unsupported Type: " + type) - + const timestamp = new Date().toISOString().replace(/[:.]/g, '-'); + const filename = `relatorio-pii-${timestamp}.${type}`; + + return { + file, + filename: filename, + type: mimeTypes[type] + } } catch (error) { - this.logger.error(error); + this.logger.error(error.message); + throw error; } } diff --git a/src/template/pii-reporter.html b/src/template/pii-reporter.html index d4b4505..fb51aac 100644 --- a/src/template/pii-reporter.html +++ b/src/template/pii-reporter.html @@ -7,51 +7,69 @@ diff --git a/src/utils/FileParser/csv-parser.ts b/src/utils/FileParser/csv-parser.ts index 61e1ae1..c481710 100644 --- a/src/utils/FileParser/csv-parser.ts +++ b/src/utils/FileParser/csv-parser.ts @@ -1,11 +1,11 @@ import { stringify } from 'csv' +import { Parser } from './parser.interface'; -export class CsvParser { +export class CsvParser implements Parser{ async parse(data: T[]) { - return new Promise((resolve, reject) => { + return new Promise((resolve, reject) => { stringify(data, { header: true }, function (err, output) { if (err) reject(err); - console.log(output) resolve(output) }); diff --git a/src/utils/FileParser/html-parser.ts b/src/utils/FileParser/html-parser.ts index 7e0b23c..0e7f155 100644 --- a/src/utils/FileParser/html-parser.ts +++ b/src/utils/FileParser/html-parser.ts @@ -1,9 +1,10 @@ import { readFileSync } from 'fs'; import Handlebars from 'handlebars'; +import { Parser } from './parser.interface'; -export class HtmlParser { +export class HtmlParser implements Parser { constructor(private readonly templatePath: string) {} - parse(data: T[]) { + async parse(data: T[]) { const templateSource = readFileSync(this.templatePath, 'utf8'); const template = Handlebars.compile(templateSource); diff --git a/src/utils/FileParser/parser-types.ts b/src/utils/FileParser/parser-types.ts new file mode 100644 index 0000000..021ac28 --- /dev/null +++ b/src/utils/FileParser/parser-types.ts @@ -0,0 +1 @@ +export type TypeParser = "html" | "csv" | "pdf" \ No newline at end of file diff --git a/src/utils/FileParser/parser.builder.ts b/src/utils/FileParser/parser.builder.ts new file mode 100644 index 0000000..3d70c2e --- /dev/null +++ b/src/utils/FileParser/parser.builder.ts @@ -0,0 +1,29 @@ +import path from 'path'; +import { TypeParser } from './parser-types'; +import { HtmlParser } from './html-parser'; +import { CsvParser } from './csv-parser'; +import { PDFParser } from './pdf-parser'; +import { Parser } from './parser.interface'; + +export class ParserBuilder { + static build(type: TypeParser): Parser { + const templatePath = path.join( + __dirname, + '../../../src/template/pii-reporter.html', + ); + + if (type === 'html') { + const htmlParser = new HtmlParser(templatePath); + return htmlParser; + } else if (type === 'csv') { + const csvParser = new CsvParser(); + return csvParser; + } else if (type === 'pdf') { + const htmlParser = new HtmlParser(templatePath); + const pdfParser = new PDFParser(htmlParser); + return pdfParser; + } + + throw new Error('Unsupported Type: ' + type); + } +} diff --git a/src/utils/FileParser/parser.interface.ts b/src/utils/FileParser/parser.interface.ts new file mode 100644 index 0000000..26af780 --- /dev/null +++ b/src/utils/FileParser/parser.interface.ts @@ -0,0 +1,3 @@ +export interface Parser { + parse(data: T[]): Promise +} \ No newline at end of file diff --git a/src/utils/FileParser/pdf-parser.ts b/src/utils/FileParser/pdf-parser.ts index bf0433a..1294b34 100644 --- a/src/utils/FileParser/pdf-parser.ts +++ b/src/utils/FileParser/pdf-parser.ts @@ -1,30 +1,39 @@ -import puppeteer from "puppeteer"; +import puppeteer from 'puppeteer'; +import { Parser } from './parser.interface'; +import { HtmlParser } from './html-parser'; -export class PDFParser { - async parse(data: T) { +export class PDFParser implements Parser { + constructor(private htmlParser: HtmlParser) {} + + async parse(data: T[]) { try { const browser = await puppeteer.launch({ executablePath: process.env.PUPPETEER_EXECUTABLE_PATH, - args: ['--no-sandbox', '--disable-setuid-sandbox', '--disable-dev-shm-usage'] + args: [ + '--no-sandbox', + '--disable-setuid-sandbox', + '--disable-dev-shm-usage', + ], }); - + const page = await browser.newPage(); page.setDefaultNavigationTimeout(0); - - await page.setContent(data, { + + const html = await this.htmlParser.parse(data); + await page.setContent(html, { waitUntil: 'networkidle0', - timeout: 30000 + timeout: 30000, }); // Configurações adicionais para garantir um PDF válido - const pdfBuffer = await page.pdf({ + const pdf = await page.pdf({ format: 'A4', printBackground: true, margin: { top: '20mm', right: '15mm', bottom: '20mm', - left: '15mm' + left: '15mm', }, preferCSSPageSize: true, displayHeaderFooter: false, @@ -34,12 +43,12 @@ export class PDFParser { pageRanges: '', tagged: true, outline: false, - timeout: 30000 + timeout: 30000, }); - + await browser.close(); - - return pdfBuffer; + + return Buffer.from(pdf); } catch (error) { console.error('Error generating PDF:', error); throw error;