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.remoteMethodCtx('syncData', { description: 'Sync schema data from external provider', accessType: 'WRITE', returns: { type: 'object', root: true }, http: { path: `/syncData`, verb: 'POST' } }); Self.syncData = async ctx => { const models = Self.app.models; let tx; try { const tables = await models.TableMultiConfig.find(); if (!tables?.length) throw new UserError(`No tables to sync`); const floricodeConfig = await models.FloricodeConfig.findOne(); if (!floricodeConfig) throw new UserError(`Floricode service is not configured`); const token = await getToken(floricodeConfig); for (const table of tables) { const data = await getData(floricodeConfig.url, table.method, token); if (!data) continue; tx = await Self.beginTransaction({}); const options = {transaction: tx, userId: ctx.req.accessToken.userId}; await Self.rawSql(`DELETE FROM edi.??`, [table.toTable]); const 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], options); await fs.remove(ws.path); await table.updateAttribute('updated', Date.vnNew(), options); await tx.commit(); } } catch (e) { if (tx) await tx.rollback(); throw e; } }; async function getToken(floricodeConfig) { const response = await axios.post(`${floricodeConfig.url}/oauth/token`, { grant_type: 'client_credentials', client_id: floricodeConfig.user, client_secret: floricodeConfig.password }, { headers: { 'Content-Type': 'application/x-www-form-urlencoded' } }); return response.data.access_token; } async function getData(url, method, token) { let data = []; let count = 0; const maxCount = await getCount(url, method, token); while (count < maxCount) { const request = await axios.get(`${url}/v2/${method}?$skip=${count}`, { headers: { 'Authorization': `Bearer ${token}` } }); data.push(...request.data.value); count += request.data.value.length; } return data; } async function getCount(url, method, token) { const request = await axios.get(`${url}/v2/${method}?$count=true`, { headers: { 'Authorization': `Bearer ${token}` } }); return request.data["@odata.count"]; } };