Skip to content

Commit

Permalink
chore: merge into develop
Browse files Browse the repository at this point in the history
  • Loading branch information
CaduGomes committed Feb 14, 2024
2 parents 0a350d5 + f641cd6 commit 466c57c
Show file tree
Hide file tree
Showing 6 changed files with 229 additions and 134 deletions.
44 changes: 27 additions & 17 deletions src/imports/data/data.js
Original file line number Diff line number Diff line change
Expand Up @@ -62,18 +62,26 @@ export async function getNextUserFromQueue({ authTokenId, document, queueId, con
return getNext(queueId, user);
}

/* Get a list of records
@param authTokenId
@param document
@param displayName
@param displayType
@param fields
@param filter
@param sort
@param limit
@param start
@param getTotal
*/
/**
* Get a list of records
* @param {Object} payload
*
* @param {string} [payload.authTokenId]
* @param {string} payload.document
* @param {string | Object} payload.filter
*
* @param {string} [payload.displayName]
* @param {string} [payload.displayType]
* @param {string} [payload.fields]
* @param {string} [payload.sort]
* @param {number} [payload.limit=50]
* @param {number} [payload.start=0]
* @param {boolean} [payload.getTotal=false]
* @param {'true'} [payload.withDetailFields]
* @param {import('../model/User').User} [payload.contextUser]
*
* @returns {Promise<import('../types/result').KonectyResult<object[]>>} - Konecty result
*/

export async function find({ authTokenId, document, displayName, displayType, fields, filter, sort, limit, start, getTotal, withDetailFields, contextUser }) {
try {
Expand Down Expand Up @@ -670,9 +678,9 @@ export async function populateDetailFieldsInRecord({ record, document, authToken
return;
}

const getDetailFieldsValue = async function (field, value, parent) {
const getDetailFieldsValue = async function (field, value) {
if (!has(value, '_id')) {
logger.error({ field, document: document, parent }, 'populateDetailFields: value without _id');
logger.error({ field, document }, 'populateDetailFields: value without _id');
}

const record = await findById({
Expand All @@ -682,9 +690,11 @@ export async function populateDetailFieldsInRecord({ record, document, authToken
dataId: value._id,
});

if (has(record, 'data.0')) {
if (record.success && record.data != null && record.data.length > 0) {
return { ...value, ...record.data[0] };
}

return value;
};

const metaObject = MetaObject.Meta[document];
Expand All @@ -698,12 +708,12 @@ export async function populateDetailFieldsInRecord({ record, document, authToken
if (field.isList === true) {
const values = isArray(value) ? value : [value];
const detailValues = await BluebirdPromise.mapSeries(values, async item => {
const detailValue = await getDetailFieldsValue(field, item, value);
const detailValue = await getDetailFieldsValue(field, item);
return detailValue;
});
acc[fieldName] = detailValues;
} else {
const detailValue = await getDetailFieldsValue(field, value, record);
const detailValue = await getDetailFieldsValue(field, value);
acc[fieldName] = detailValue;
}
} else {
Expand Down
137 changes: 137 additions & 0 deletions src/imports/data/export.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
import first from 'lodash/first';
import isArray from 'lodash/isArray';
import isObject from 'lodash/isObject';
import isString from 'lodash/isString';

import { flatten } from 'flat';

import { MetaObject } from '@imports/model/MetaObject';

import { find } from '@imports/data/data';

import { errorReturn, successReturn } from '@imports/utils/return';

import { csvExport } from '@imports/exports/csvExport';
import { xlsExport } from '@imports/exports/xlsExport';
import { List } from '@imports/model/List';
import { User } from '@imports/model/User';
import { KonectyResult } from '@imports/types/result';

type ExportDataParams = {
document: string;
listName: string;
type: 'csv' | 'xls';
user: User;

displayName?: string;
displayType?: string;

filter?: string | object;
sort?: string;
fields?: string;
limit?: number;
start?: number;
};

type ExportDataResponse = {
httpHeaders: Record<string, string>;
content: string | Buffer;
};

export default async function exportData({ document, listName, type = 'csv', user, ...query }: ExportDataParams): Promise<KonectyResult<ExportDataResponse>> {
const listMeta = (await MetaObject.MetaObject.findOne({
type: 'list',
document,
name: listName,
})) as List;

if (listMeta == null) {
return errorReturn(`[${document}] Can't find list ${listName} of document ${document}`);
}

const metaObject = MetaObject.Meta[document];
if (metaObject == null) {
return errorReturn(`[${document}] Can't find meta`);
}

const userLocale = user.locale ?? 'en';

const getLabel = () => {
if (listMeta.plurals != null) {
return listMeta.plurals[userLocale] ?? listMeta.plurals.en ?? first(Object.values(listMeta.plurals));
}
if (listMeta.label != null) {
return listMeta.label[userLocale] ?? listMeta.label.en ?? first(Object.values(listMeta.label));
}
if (metaObject.plurals != null) {
return metaObject.plurals[userLocale] ?? metaObject.plurals.en ?? first(Object.values(metaObject.plurals));
}
if (metaObject.label != null) {
return metaObject.label[userLocale] ?? metaObject.label.en ?? first(Object.values(metaObject.label));
}
return document;
};

const name = getLabel();

if (isString(query.filter) === false && isObject(listMeta.filter)) {
query.filter = JSON.stringify(listMeta.filter);
}

if (isString(query.sort) === false && isArray(listMeta.sorters)) {
query.sort = JSON.stringify(listMeta.sorters);
}

const getFields = () => {
if (isString(query.fields)) {
return query.fields;
}
if (isObject(listMeta.columns)) {
return Object.values(listMeta.columns)
.filter(column => column.visible === true)
.map(column => column.linkField)
.join(',');
}
return undefined;
};

const fields = getFields();

const filter = isString(query.filter) ? JSON.parse(query.filter) : undefined;

const result = await find({
contextUser: user,
document,
displayName: query.displayName,
displayType: query.displayType,
fields,
filter,
sort: query.sort,
limit: query.limit,
start: query.start,
withDetailFields: 'true',
getTotal: true,
});

if (result == null || result.success === false) {
return result;
}

const dataResult = result.data.reduce(
(acc: { flatData: object[]; keys: Record<string, number> }, item) => {
const flatItem = flatten<object, object>(item);

acc.flatData.push(flatItem);
Object.keys(flatItem as object).forEach(key => (acc.keys[key] = 1));

return acc;
},
{ flatData: [], keys: {} },
);

if (type === 'xls') {
return successReturn(await xlsExport(Object.keys(dataResult.keys), dataResult.flatData, name));
}

return successReturn(csvExport(Object.keys(dataResult.keys), dataResult.flatData, name));
}
23 changes: 13 additions & 10 deletions src/imports/exports/csvExport.js
Original file line number Diff line number Diff line change
@@ -1,17 +1,22 @@


export function csvExport(headers, data, name,
/** @type FastifyReply */
reply
) {
/**
*
* @param {string[]} headers
* @param {object[]} data
* @param {string} name
* @returns {Promise<{ httpHeaders: object, content: string }>}
*/
export function csvExport(headers, data, name) {
// Define separator, sufix and prefix
const separator = '","';
const prefix = '"';
const sufix = '"';

// Send headers with content type and file name
reply.header('Content-Type', 'application/csv');
reply.header('Content-Disposition', `attachment; filename=${name}.csv`);
const httpHeaders = {
'Content-Type': 'application/csv',
'Content-Disposition': `attachment; filename=${name}.csv`,
};

// Iterate over keys to send header line
let header = headers.join(separator);
Expand All @@ -22,8 +27,6 @@ export function csvExport(headers, data, name,

const content = [header];



// Iterate over data
for (let item of data) {
let value = [];
Expand All @@ -44,5 +47,5 @@ export function csvExport(headers, data, name,
content.push(value);
}

reply.send(content.join('\n'));
return { httpHeaders, content: content.join('\n') };
}
21 changes: 17 additions & 4 deletions src/imports/exports/xlsExport.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,15 @@
import moment from 'moment';
import isDate from 'lodash/isDate';
import { Workbook } from 'excel4node';
export function xlsExport(headers, data, name, reply) {
import isDate from 'lodash/isDate';
import moment from 'moment';

/**
*
* @param {string[]} headers
* @param {object[]} data
* @param {string} name
* @returns {Promise<{ httpHeaders: object, content: Buffer }>}
*/
export async function xlsExport(headers, data, name) {
let header, index;
const wb = new Workbook();
wb.debug = false;
Expand Down Expand Up @@ -58,5 +66,10 @@ export function xlsExport(headers, data, name, reply) {
ws.column(index + 1).setWidth(widths[index]);
}

return wb.write(`${name}.xlsx`, reply);
const httpHeaders = {
'Content-Type': 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
'Content-Disposition': `attachment; filename=${name}.xlsx`,
};

return { httpHeaders, content: await wb.writeToBuffer() };
}
11 changes: 11 additions & 0 deletions src/imports/utils/return.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@

/**
*
* @param {any} value
* @returns {{success: true, data: any}}
*/
export const successReturn = function (value) {
if (value == null) {
return {
Expand All @@ -10,6 +16,11 @@ export const successReturn = function (value) {
};
};

/**
*
* @param {string | string[]} messages
* @returns {{success: false, errors: import("../types/result").KonectyError[]}}
*/
export const errorReturn = function (messages) {
if (Array.isArray(messages)) {
return {
Expand Down
Loading

0 comments on commit 466c57c

Please sign in to comment.