@opengis/fastify-table
Version:
core-plugins
156 lines (125 loc) • 5.76 kB
JavaScript
/* eslint-disable no-param-reassign */
import path from 'node:path';
import {
config, getAccess, handlebars, setOpt, setToken, getTemplate, handlebarsSync, applyHook, getData,
} from '../../../../utils.js';
import conditions from './utils/conditions.js';
const components = {
'vs-widget-file': 'select \'vs-widget-file\' as component, count(*) from crm.files where entity_id=$1 and file_status<>3',
'vs-widget-comments': 'select \'vs-widget-comments\' as component, count(*) from crm.communications where entity_id=$1',
};
export default async function getCardData(req, reply) {
const {
pg, headers, params = {}, user = {},
} = req;
const { table, id } = params;
const { uid } = user;
const res = await applyHook('cardData', { table, id, user });
if (res) return res;
const time = Date.now();
const template = await getTemplate('card', table);
const access = await getAccess({ table, user }, pg);
if (!access?.actions?.length) {
return reply.status(403).send('access restricted');
}
const tableTemplate = await getTemplate('table', table);
const index = template?.find(el => el[0] === 'index.yml')?.[1] || {};
const result = index.table && index.query
? await pg.query(
`select * from ${index.table} where ${handlebarsSync.compile(index.query)({ uid, user })}`,
)
: await getData({
pg, table, id, user, headers,
}, reply);
if (result?.message) return result?.message;
if (!result?.rows?.length) {
return reply.status(403).send('access restricted: empty rows');
}
const { rows = [] } = result;
const panels = (index.table && index.query ? index.panels : result?.panels) || [];
if (index.table && index.query) {
// conditions
panels.filter(panel => panel.items).forEach(el => {
el.items = el.items?.filter?.(item => conditions(item.conditions, rows[0]));
});
// title, count
await Promise.all(panels.filter(el => el.items).map(async el => {
const filtered = el.items.filter(item => item.count?.toLowerCase?.().includes('select'));
const data = await Promise.all(filtered.map(async el1 => pg.query(el1.count).then(item => item.rows?.[0] || {})));
filtered.forEach((item1, i) => {
Object.assign(item1, data[i] || {}, data[i].count ? {} : { count: undefined });
});
const q = el.items.map((item2) => (item2.component ? components[item2.component] : null)).filter(item2 => item2).join(' union all ');
const counts = q && id
? await pg.query(q, [id])
.then(e => e.rows.reduce((acc, curr) => Object.assign(acc, { [curr.component]: curr.count }), {}))
: {};
el.items?.filter?.(item => item.component)?.forEach(item => Object.assign(item, { count: counts?.[item.component] }));
}));
}
// tokens result
const tokens = {};
if (!config.security?.disableToken && index?.tokens && typeof index?.tokens === 'object' && !Array.isArray(index?.tokens)) {
Object.keys(index.tokens || {})
.filter(key => index?.tokens[key]?.public
|| access.actions?.includes?.('edit')
|| access.actions?.includes?.('add')
|| !index?.tokens[key]?.table)
.forEach(key => {
const item = index?.tokens[key];
Object.keys(item).filter(el => item[el]?.includes?.('{{')).forEach(el => {
item[el] = handlebarsSync.compile(item[el])({
user, uid, id, data: rows[0],
});
});
const token = item.form && item.table ? setToken({
ids: [JSON.stringify(item)],
uid,
array: 1,
})[0] : setOpt(item, uid);
tokens[key] = token;
});
}
// vue result
const vue = template?.filter((el) => el[0].endsWith('.vue'))
.reduce((acc, curr) => Object.assign(acc, { [path.parse(curr[0]).name]: curr[1].match(/<template[^>]*>([\s\S]*?)<\/template>/)[1].trim() }), {});
// data result
const data = {};
const route = await pg.query('select route_id as path, title from admin.routes where enabled and alias=$1 limit 1', [table])
.then(el => el.rows?.[0] || {});
Object.assign(route, { tableTitle: tableTemplate?.title });
if (index?.data && index?.data?.[0]?.name) {
await Promise.all(index.data.filter((el) => el?.name && el?.sql).map(async (el) => {
const q = handlebarsSync.compile(el.sql)({
data: rows[0], user, uid, id,
});
const { rows: sqlData } = await pg.query(q);
data[el.name] = sqlData;
}));
}
// html result
const html = {};
if (template) {
await Promise.all(template.filter(el => el[0].includes('.hbs')).map(async (el) => {
const htmlContent = await handlebars.compile(el[1])({
...rows[0], user, data, tokens,
});
const name = el[0].substring(0, el[0].lastIndexOf('.'));
html[name] = htmlContent;
}));
}
return {
time: Date.now() - time,
...index,
panels,
tokens,
vue,
data,
route,
html,
rows,
columns: tableTemplate?.columns || tableTemplate?.colModel,
table: undefined,
query: undefined,
};
}