diff --git a/dist/models/TemplateExcel.js b/dist/models/TemplateExcel.js new file mode 100644 index 00000000..0bc7c328 --- /dev/null +++ b/dist/models/TemplateExcel.js @@ -0,0 +1,72 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.TemplateExcel = void 0; +const exceljs_1 = require("exceljs"); +const StringUtils_1 = require("../utils/StringUtils"); +class TemplateExcel { + constructor(config) { + this._config = config; + this._validationRules = config.validationRules; + this._columns = Object.keys(this._validationRules); + this._workbook = this.createTemplateExcel(); + } + createTemplateExcel() { + const workbook = new exceljs_1.Workbook(); + this.addExcelCoverWorksheet(workbook); + this.addExcelValidationWorksheet(workbook); + this.addExcelTemplateWorksheet(workbook); + return workbook; + } + getExcelBuffer() { + return this._workbook.xlsx.writeBuffer({ filename: 'template.xlsx' }); + } + addExcelCoverWorksheet(workbook) { + const coverSheet = workbook.addWorksheet('cover'); + coverSheet.getCell('A1').value = `Template downloaded on: ${new Date()}`; + coverSheet.getCell('A2').value = `Configuration version: ${this._config.version}`; + } + addExcelValidationWorksheet(workbook) { + const validationTemplate = workbook.addWorksheet('validation'); + this.setExcelWorksheetHeader(validationTemplate); + this.setValidationExcelWorksheetValues(validationTemplate); + } + addExcelTemplateWorksheet(workbook) { + const templateSheet = workbook.addWorksheet('template'); + this.setExcelWorksheetHeader(templateSheet); + this.setTemplateExcelWorksheetDataValidation(templateSheet); + } + setExcelWorksheetHeader(worksheet) { + const columns = ["url", ...this._columns]; + worksheet.columns = columns.map(column => { + return { + header: column, + key: column, + width: 20 + }; + }); + } + setValidationExcelWorksheetValues(validationWorksheet) { + this._columns.forEach(column => { + validationWorksheet.getColumn(column).values = [column, ...this._validationRules[column]]; + }); + } + setTemplateExcelWorksheetDataValidation(templateWorksheet) { + this._columns.forEach(column => { + if (!StringUtils_1.StringUtils.isStringForRegex(this._validationRules[column][0])) { + const validationCount = this._validationRules[column].length; + let columnLetter = templateWorksheet.getColumn(column).letter; + for (let i = 2; i < 1003; i++) { + templateWorksheet.getCell(columnLetter + i).dataValidation = { + type: 'list', + allowBlank: false, + formulae: [`=validation!$${columnLetter}$2:$${columnLetter}$${validationCount + 1}`] + }; + } + } + }); + } + checkRegex(string) { + return string.match(/^\/.*\/$/) !== null; + } +} +exports.TemplateExcel = TemplateExcel; diff --git a/dist/routes/template.js b/dist/routes/template.js index c37db5d9..6bb2e49c 100644 --- a/dist/routes/template.js +++ b/dist/routes/template.js @@ -1,31 +1,61 @@ -'use strict'; -Object.defineProperty(exports, '__esModule', { value: true }); -const ConfigDAO_1 = require('../models/DAO/ConfigDAO'); -const ApiResponse_1 = require('../models/ApiResponse'); +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +const ConfigDAO_1 = require("../models/DAO/ConfigDAO"); +const ApiResponse_1 = require("../models/ApiResponse"); +const TemplateExcel_1 = require("../models/TemplateExcel"); const template = (app) => { - app.get('/template', (req, res) => { - const configDAO = new ConfigDAO_1.ConfigDAO('company'); - const apiResponse = new ApiResponse_1.ApiResponse(); - configDAO - .getLastConfig() - .then((config) => { - res.setHeader('Content-disposition', 'attachment; filename=template.csv'); - res.set('Content-Type', 'text/csv; charset=utf-8'); - apiResponse.statusCode = 200; - apiResponse.responseText = config.toCsvTemplate(); - }) - .catch((err) => { - apiResponse.responseText = 'Erro ao recuperar a configuração!'; - apiResponse.statusCode = 500; - apiResponse.errorMessage = err.message; - }) - .finally(() => { - if (apiResponse.statusCode === 200) { - res.status(apiResponse.statusCode).send(apiResponse.responseText); - } else { - res.status(apiResponse.statusCode).send(apiResponse.jsonResponse); - } - }); - }); + app.get('/template', (req, res) => { + const company = req.company; + const configDAO = new ConfigDAO_1.ConfigDAO('company'); + const apiResponse = new ApiResponse_1.ApiResponse(); + configDAO + .getLastConfig() + .then((config) => { + res.setHeader('Content-disposition', 'attachment; filename=template.csv'); + res.set('Content-Type', 'text/csv; charset=utf-8'); + apiResponse.statusCode = 200; + apiResponse.responseText = config.toCsvTemplate(); + }) + .catch((err) => { + apiResponse.responseText = 'Erro ao recuperar a configuração!'; + apiResponse.statusCode = 500; + apiResponse.errorMessage = err.message; + }) + .finally(() => { + if (apiResponse.statusCode === 200) { + res.status(apiResponse.statusCode).send(apiResponse.responseText); + } + else { + res.status(apiResponse.statusCode).send(apiResponse.jsonResponse); + } + }); + }); + app.get('/template/excel', (req, res) => { + const company = req.company; + const configDAO = new ConfigDAO_1.ConfigDAO(company); + const apiResponse = new ApiResponse_1.ApiResponse(); + configDAO + .getLastConfig() + .then((config) => { + const templateExcel = new TemplateExcel_1.TemplateExcel(config); + templateExcel.getExcelBuffer() + .then((buffer) => { + apiResponse.statusCode = 200; + res.contentType('application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'); + res.attachment('template.xlsx'); + res.send(buffer); + }).catch((err) => { + apiResponse.responseText = 'Erro ao baixar o template!'; + apiResponse.statusCode = 500; + apiResponse.errorMessage = err.message; + res.status(apiResponse.statusCode).send(apiResponse.jsonResponse); + }); + }).catch((err) => { + apiResponse.responseText = 'Erro ao recuperar a configuração!'; + apiResponse.statusCode = 500; + apiResponse.errorMessage = err.message; + res.status(apiResponse.statusCode).send(apiResponse.jsonResponse); + }); + }); }; exports.default = template; diff --git a/dist/utils/StringUtils.js b/dist/utils/StringUtils.js index a11c7728..01bc0406 100644 --- a/dist/utils/StringUtils.js +++ b/dist/utils/StringUtils.js @@ -1,39 +1,38 @@ -'use strict'; -Object.defineProperty(exports, '__esModule', { value: true }); +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); exports.StringUtils = void 0; class StringUtils { - static normalize(string) { - return string - .toLowerCase() - .replace(/[áàãâä]/gi, 'a') - .replace(/[éèêë]/gi, 'e') - .replace(/[íìîï]/gi, 'i') - .replace(/[óòõôö]/gi, 'o') - .replace(/[úùûü]/gi, 'u') - .replace(/[ç]/gi, 'c'); - } - static replaceWhiteSpace(string, replacer) { - return string.replace(/ /g, replacer); - } - static _isStringForRegex(string) { - return string[0] === '/' && string[string.length - 1] === '/'; - } - static validateString(stringToValidate, rules, separator = ' ') { - const validate = [false]; - rules.forEach((rule) => { - if (this._isStringForRegex(rule)) { - const regexRule = new RegExp(rule.slice(1, rule.length - 1)); - validate.push(!!stringToValidate.match(regexRule)); - } else { - validate.push( - stringToValidate.toLocaleLowerCase() === this.replaceWhiteSpace(rule.toLocaleLowerCase(), separator) - ); - } - }); - return validate.indexOf(true) !== -1; - } - static isEmpty(string) { - return !string; - } + static normalize(string) { + return string + .toLowerCase() + .replace(/[áàãâä]/gi, 'a') + .replace(/[éèêë]/gi, 'e') + .replace(/[íìîï]/gi, 'i') + .replace(/[óòõôö]/gi, 'o') + .replace(/[úùûü]/gi, 'u') + .replace(/[ç]/gi, 'c'); + } + static replaceWhiteSpace(string, replacer) { + return string.replace(/ /g, replacer); + } + static isStringForRegex(string) { + return string[0] === '/' && string[string.length - 1] === '/'; + } + static validateString(stringToValidate, rules, separator = ' ') { + const validate = [false]; + rules.forEach((rule) => { + if (this.isStringForRegex(rule)) { + const regexRule = new RegExp(rule.slice(1, rule.length - 1)); + validate.push(!!stringToValidate.match(regexRule)); + } + else { + validate.push(stringToValidate.toLocaleLowerCase() === this.replaceWhiteSpace(rule.toLocaleLowerCase(), separator)); + } + }); + return validate.indexOf(true) !== -1; + } + static isEmpty(string) { + return !string; + } } exports.StringUtils = StringUtils; diff --git a/src/ts/models/TemplateExcel.ts b/src/ts/models/TemplateExcel.ts new file mode 100644 index 00000000..7634a721 --- /dev/null +++ b/src/ts/models/TemplateExcel.ts @@ -0,0 +1,112 @@ +import { Buffer, Workbook, Worksheet } from 'exceljs'; +import { StringUtils } from '../utils/StringUtils'; +import { Config } from './Config'; + +export class TemplateExcel { + private _config: Config; + private _validationRules: { [key:string]: string[] }; + private _columns: string[]; + private _workbook: Workbook; + + constructor(config: Config) { + this._config = config; + this._validationRules = config.validationRules; + this._columns = Object.keys(this._validationRules); + this._workbook = this.createTemplateExcel(); + } + + /** + * Criar o template em formato Excel .xlsx. + * @returns Workbook Excel com abas 'Template' e 'Validation' populados de acordo com a configuração de validação do AdInfo. + */ + private createTemplateExcel(): Workbook { + const workbook = new Workbook(); + this.addExcelCoverWorksheet(workbook); + this.addExcelValidationWorksheet(workbook); + this.addExcelTemplateWorksheet(workbook); + return workbook; + } + + /** + * Criar um buffer a partir do Excel gerado na construção da classe. + * @returns Uma Promise que retorna um Buffer a partir do Excel gerado na construção da classe. + */ + public getExcelBuffer(): Promise { + return this._workbook.xlsx.writeBuffer({filename: 'template.xlsx'}); + } + + /** + * Gerar a aba 'cover' no Excel Template, contendo informações do template, como data de download e versão da configuração. + * @param workbook Objeto Workbook no qual a aba será gerada. + */ + private addExcelCoverWorksheet(workbook: Workbook): void { + const coverSheet = workbook.addWorksheet('cover'); + coverSheet.getCell('A1').value = `Template downloaded on: ${new Date()}`; + coverSheet.getCell('A2').value = `Configuration version: ${this._config.version}` + } + + /** + * Gerar a aba de 'Validation' no Excel Template, com os valores populados para validação. + * @param workbook Objeto Workbook no qual a aba será gerada. + */ + private addExcelValidationWorksheet(workbook: Workbook): void { + const validationTemplate = workbook.addWorksheet('validation'); + this.setExcelWorksheetHeader(validationTemplate); + this.setValidationExcelWorksheetValues(validationTemplate); + } + + /** + * Gerar a aba de 'Template' no Excel Template, com os campos e validações populados para uso. + * @param workbook Objeto Workbook no qual a aba será gerada. + */ + private addExcelTemplateWorksheet(workbook: Workbook): void { + const templateSheet = workbook.addWorksheet('template'); + this.setExcelWorksheetHeader(templateSheet); + this.setTemplateExcelWorksheetDataValidation(templateSheet); + } + + /** + * Nomear as colunas e inserir os valores dos campos na aba do Excel, com os valores de acordo com a configuração de validação do AdInfo. + * @param worksheet Objeto Worksheet (aba do Excel) no qual terá os campos inseridos e as colunas nomeadas. + */ + private setExcelWorksheetHeader(worksheet: Worksheet): void { + const columns = ["url", ...this._columns]; + worksheet.columns = columns.map(column => { + return { + header: column, + key: column, + width: 20 + } + }) + } + + /** + * Inserir o nome do campo e os valores de cada campo que serão usados para validação de dados, de acordo com a configuração de validação do AdInfo. + * @param validationWorksheet Objeto Worksheet (aba do Excel) referente à aba de validação. + */ + private setValidationExcelWorksheetValues(validationWorksheet: Worksheet): void { + this._columns.forEach(column => { + validationWorksheet.getColumn(column).values = [column, ...this._validationRules[column]]; + }) + } + + /** + * Aplicar a validação de dados nos campos do template, de acordo com a configuração de validação do AdInfo, para as primeiras 1000 linhas. + * @param templateWorksheet Objecto worksheet (aba do Excel) referente à aba de template. + */ + private setTemplateExcelWorksheetDataValidation(templateWorksheet: Worksheet): void { + this._columns.forEach(column => { + if (!StringUtils.isStringForRegex(this._validationRules[column][0])) { + const validationCount = this._validationRules[column].length; + let columnLetter = templateWorksheet.getColumn(column).letter; + for(let i = 2; i < 1003; i++) { + templateWorksheet.getCell(columnLetter + i).dataValidation = { + type: 'list', + allowBlank: false, + formulae: [`=validation!$${columnLetter}$2:$${columnLetter}$${validationCount + 1}`] + }; + } + } + }) + } +} \ No newline at end of file diff --git a/src/ts/routes/template.ts b/src/ts/routes/template.ts index caa993e6..8bf87324 100644 --- a/src/ts/routes/template.ts +++ b/src/ts/routes/template.ts @@ -1,6 +1,7 @@ import { ConfigDAO } from '../models/DAO/ConfigDAO'; import { ApiResponse } from '../models/ApiResponse'; import { Config } from '../models/Config'; +import { TemplateExcel } from '../models/TemplateExcel'; const template = (app: { [key: string]: any }): void => { app.get('/template', (req: { [key: string]: any }, res: { [key: string]: any }) => { @@ -29,6 +30,34 @@ const template = (app: { [key: string]: any }): void => { } }); }); + + app.get('/template/excel', (req: { [key: string]: any }, res: { [key: string]: any }) => { + const company = req.company; + const configDAO = new ConfigDAO(company); + const apiResponse = new ApiResponse(); + configDAO + .getLastConfig() + .then((config: Config) => { + const templateExcel = new TemplateExcel(config); + templateExcel.getExcelBuffer() + .then((buffer: Buffer) => { + apiResponse.statusCode = 200; + res.contentType('application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'); + res.attachment('template.xlsx'); + res.send(buffer); + }).catch((err) => { + apiResponse.responseText = 'Erro ao baixar o template!'; + apiResponse.statusCode = 500; + apiResponse.errorMessage = err.message; + res.status(apiResponse.statusCode).send(apiResponse.jsonResponse); + }) + }).catch((err) => { + apiResponse.responseText = 'Erro ao recuperar a configuração!'; + apiResponse.statusCode = 500; + apiResponse.errorMessage = err.message; + res.status(apiResponse.statusCode).send(apiResponse.jsonResponse); + }) + }); }; export default template; diff --git a/src/ts/utils/StringUtils.ts b/src/ts/utils/StringUtils.ts index 53928727..a56e6cb4 100644 --- a/src/ts/utils/StringUtils.ts +++ b/src/ts/utils/StringUtils.ts @@ -37,7 +37,7 @@ export class StringUtils { * Verifica o começo e o final da string, se começar e terminar com barra, * significa que a string refere-se a um padrão de regex */ - private static _isStringForRegex(string: string): boolean { + static isStringForRegex(string: string): boolean { return string[0] === '/' && string[string.length - 1] === '/'; } @@ -55,7 +55,7 @@ export class StringUtils { static validateString(stringToValidate: string, rules: string[], separator = ' '): boolean { const validate: [boolean] = [false]; rules.forEach((rule) => { - if (this._isStringForRegex(rule)) { + if (this.isStringForRegex(rule)) { //Regex const regexRule = new RegExp(rule.slice(1, rule.length - 1)); validate.push(!!stringToValidate.match(regexRule));