mirror of
https://github.com/dadosfera/maestro.git
synced 2026-11-14 20:29:08 +00:00
FEAT: pii
This commit is contained in:
@@ -346,7 +346,7 @@ export class CatalogController {
|
||||
@Language() language: LanguageEnum,
|
||||
@Param('id') id: string,
|
||||
): Promise<IPreviewResponse> {
|
||||
const { customer_name, customer_id, user_id, username } = user;
|
||||
const { customer_name, customer_id, user_id, username, customer_modules } = user;
|
||||
|
||||
this.logger.info(`/catalog - ON GET DATA DOCS ROUTE`, {
|
||||
user_id,
|
||||
@@ -359,6 +359,7 @@ export class CatalogController {
|
||||
user_id,
|
||||
username,
|
||||
language,
|
||||
is_mask: customer_modules.some(mod => mod === 'pii')
|
||||
});
|
||||
|
||||
const preview = await this.catalogService.getDatasetPreview(id, metadata);
|
||||
@@ -863,15 +864,27 @@ export class CatalogController {
|
||||
@RequireModule(
|
||||
DADOSFERA_MODULES_KEYS.PII
|
||||
)
|
||||
async getPiiReporter(@User() user: RequestUser, @Res() res: Response) {
|
||||
async getPiiReporter(@User() user: RequestUser, @Res() res: Response, @Query('type') type: "html" | "csv") {
|
||||
this.logger.info('GET pii-reporter');
|
||||
const metadata = PackTheMetadata(user);
|
||||
|
||||
try {
|
||||
const reporterHtml = await this.catalogService.getPiiReporter(metadata);
|
||||
const reporter = await this.catalogService.getPiiReporter(metadata, type);
|
||||
|
||||
res.setHeader('Content-Type', 'text/html');
|
||||
return res.send(reporterHtml);
|
||||
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}`;
|
||||
|
||||
res.setHeader('Content-Disposition', `attachment; filename="${filename}"`);
|
||||
|
||||
return res.send(reporter);
|
||||
} catch (error) {
|
||||
this.logger.error(error);
|
||||
}
|
||||
|
||||
@@ -34,8 +34,12 @@ import {
|
||||
GetNimbusDashboardsRequest,
|
||||
GetRlsRulesRequest,
|
||||
} from '@dadosfera/protospack-v2/dist/lib/Catalog/interfaces/messages';
|
||||
import { readFileSync } from 'fs';
|
||||
import { writeFileSync } from 'fs';
|
||||
import path from 'path';
|
||||
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';
|
||||
|
||||
class CatalogService implements OnModuleInit {
|
||||
catalogReadService: ReadService.CatalogReadServices;
|
||||
@@ -82,49 +86,47 @@ class CatalogService implements OnModuleInit {
|
||||
)}.dadosfera.ai`;
|
||||
}
|
||||
|
||||
async getPiiReporter(metadata: Metadata) {
|
||||
const {
|
||||
data
|
||||
} = await lastValueFrom(
|
||||
this.catalogWriteService.GetPiiReporter({}, metadata)
|
||||
)
|
||||
async getPiiReporter(metadata: Metadata, type: "html"| "csv") {
|
||||
try {
|
||||
const {
|
||||
data
|
||||
} = await lastValueFrom(
|
||||
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',
|
||||
);
|
||||
|
||||
const result = data.map((props) => ({
|
||||
...props,
|
||||
pii_rules: this.formatPiiRules(JSON.parse(props.pii_rules)),
|
||||
}));
|
||||
this.logger.info("templatePath: " + templatePath);
|
||||
|
||||
// 3. Ler o template HTML
|
||||
const templatePath = path.join(
|
||||
__dirname,
|
||||
'../../../src/template/pii-reporter.html',
|
||||
);
|
||||
const templateSource = readFileSync(templatePath, 'utf8');
|
||||
|
||||
// 4. Compilar o template
|
||||
const template = Handlebars.compile(templateSource);
|
||||
|
||||
// 5. Aplicar os dados ao template
|
||||
return template({
|
||||
dados: result,
|
||||
dataGeracao: new Date().toLocaleString('pt-BR'),
|
||||
});
|
||||
}
|
||||
|
||||
private formatPiiRules(
|
||||
data: Record<
|
||||
string,
|
||||
{
|
||||
avg_score: number;
|
||||
max_score: number;
|
||||
if (type === "html") {
|
||||
const htmlParser = new HtmlParser<PiiDto>(templatePath);
|
||||
return htmlParser.parse(data);
|
||||
} else if (type === "csv") {
|
||||
const csvParser = new CsvParser<PiiDto>();
|
||||
return await csvParser.parse(data)
|
||||
} else if (type === "pdf") {
|
||||
const htmlParser = new HtmlParser<PiiDto>(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
|
||||
}
|
||||
>,
|
||||
) {
|
||||
return Object.keys(data)
|
||||
.filter((key) => {
|
||||
return data[key].max_score > 0.7;
|
||||
})
|
||||
.join(', ');
|
||||
|
||||
throw new Error("Unsupported Type: " + type)
|
||||
|
||||
} catch (error) {
|
||||
this.logger.error(error);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
async createDataAsset(data: Messages.CreateDataAssetRequest, metadata) {
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
export class PiiDto {
|
||||
database_name: string;
|
||||
table_schema: string;
|
||||
table_name: string;
|
||||
column_name: string;
|
||||
data_type: string;
|
||||
pii_rules: string;
|
||||
}
|
||||
@@ -6,6 +6,10 @@
|
||||
<title>Dadosfera Relatório de PII</title>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Quicksand:wght@400;500;700&display=swap" rel="stylesheet">
|
||||
<style>
|
||||
@page {
|
||||
size: A4;
|
||||
margin: 20mm 15mm 20mm 15mm;
|
||||
}
|
||||
body {
|
||||
font-family: 'Quicksand', sans-serif;
|
||||
color: #5c5c5c;
|
||||
@@ -13,8 +17,7 @@
|
||||
padding: 20px;
|
||||
}
|
||||
.container {
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
margin: 0 24px;
|
||||
}
|
||||
.header {
|
||||
display: flex;
|
||||
|
||||
@@ -14,6 +14,7 @@ interface IMetadata {
|
||||
host?: string;
|
||||
origin?: string;
|
||||
custom_host?: string;
|
||||
is_mask?: boolean;
|
||||
}
|
||||
|
||||
export function PackTheMetadata(info: IMetadata): Metadata {
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
import { stringify } from 'csv'
|
||||
|
||||
export class CsvParser<T> {
|
||||
async parse(data: T[]) {
|
||||
return new Promise((resolve, reject) => {
|
||||
stringify(data, { header: true }, function (err, output) {
|
||||
if (err) reject(err);
|
||||
console.log(output)
|
||||
|
||||
resolve(output)
|
||||
});
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
import { readFileSync } from 'fs';
|
||||
import Handlebars from 'handlebars';
|
||||
|
||||
export class HtmlParser<T> {
|
||||
constructor(private readonly templatePath: string) {}
|
||||
parse(data: T[]) {
|
||||
const templateSource = readFileSync(this.templatePath, 'utf8');
|
||||
|
||||
const template = Handlebars.compile(templateSource);
|
||||
|
||||
return template({
|
||||
dados: data,
|
||||
dataGeracao: new Date().toLocaleString('pt-BR'),
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
import puppeteer from "puppeteer";
|
||||
|
||||
export class PDFParser<T extends string> {
|
||||
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']
|
||||
});
|
||||
|
||||
const page = await browser.newPage();
|
||||
page.setDefaultNavigationTimeout(0);
|
||||
|
||||
await page.setContent(data, {
|
||||
waitUntil: 'networkidle0',
|
||||
timeout: 30000
|
||||
});
|
||||
|
||||
// Configurações adicionais para garantir um PDF válido
|
||||
const pdfBuffer = await page.pdf({
|
||||
format: 'A4',
|
||||
printBackground: true,
|
||||
margin: {
|
||||
top: '20mm',
|
||||
right: '15mm',
|
||||
bottom: '20mm',
|
||||
left: '15mm'
|
||||
},
|
||||
preferCSSPageSize: true,
|
||||
displayHeaderFooter: false,
|
||||
headerTemplate: '',
|
||||
footerTemplate: '',
|
||||
omitBackground: false,
|
||||
pageRanges: '',
|
||||
tagged: true,
|
||||
outline: false,
|
||||
timeout: 30000
|
||||
});
|
||||
|
||||
await browser.close();
|
||||
|
||||
return pdfBuffer;
|
||||
} catch (error) {
|
||||
console.error('Error generating PDF:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user