const UserError = require('vn-loopback/util/user-error'); const fs = require('fs-extra'); const fastCsv = require("fast-csv"); const axios = require('axios'); const path = require('path'); const { pipeline } = require('stream/promises'); module.exports = Self => { Self.remoteMethod('syncData', { description: 'Sync schema data from external provider', accessType: 'WRITE', returns: { type: 'object', root: true }, http: { path: `/syncData`, verb: 'POST' } }); Self.syncData = async options => { const models = Self.app.models; const myOptions = {}; if (typeof options == 'object') Object.assign(myOptions, options); let tx, ws; try { const floricodeConfig = await models.FloricodeConfig.findOne({}, myOptions); if (!floricodeConfig) throw new UserError(`Floricode service is not configured`); const tables = await models.TableMultiConfig.find({}, myOptions); if (!tables?.length) throw new UserError(`No tables to sync`); const token = await Self.getToken(floricodeConfig); for (const table of tables) { const data = await Self.getData(floricodeConfig.url, table.method, token); if (!data) continue; if (!myOptions.transaction) { tx = await Self.beginTransaction({}); myOptions.transaction = tx; } await Self.rawSql(`DELETE FROM edi.??`, [table.toTable], myOptions); ws = fs.createWriteStream(path.join(__dirname, `/${table.toTable}.csv`)); await pipeline(fastCsv.write(data, { delimiter: ';' }), ws); const templatePath = path.join(__dirname, `./syncSql/${table.toTable}.sql`); const sqlTemplate = await fs.readFile(templatePath, 'utf8'); await Self.rawSql(sqlTemplate, [ws.path], myOptions); await fs.remove(ws.path); await table.updateAttribute('updated', Date.vnNew(), myOptions); if (tx) { await tx.commit(); delete myOptions.transaction; } } } catch (e) { if (tx) await tx.rollback(); if (await fs.pathExists(ws?.path)) await fs.remove(ws?.path); throw e; } }; Self.getToken = async function ({ url, user, password}) { return (await axios.post(`${url}/oauth/token`, { grant_type: 'client_credentials', client_id: user, client_secret: password }, { headers: { 'Content-Type': 'application/x-www-form-urlencoded' } } )).data.access_token; }; Self.getData = async function (url, method, token) { let data = []; let count = 0; const maxCount = (await Self.get(`${url}/v2/${method}?$count=true`, token))["@odata.count"]; while (count < maxCount) { const response = await Self.get(`${url}/v2/${method}?$skip=${count}`, token) data.push(...response.value); count += response.value.length; } return data; }; Self.get = async function get(url, token) { return (await axios.get(url, { headers: { Authorization: `Bearer ${token}` } })).data; }; };