yekonga-server
Version:
Yekonga Server
1,163 lines (1,003 loc) • 90.5 kB
JavaScript
/*global Yekonga, serverLibrary */
// @ts-nocheck
const H = Yekonga.Helper;
const fs = serverLibrary.fs;
const moment = serverLibrary.moment;
const excel = serverLibrary.excel;
const path = serverLibrary.path;
const PDF = serverLibrary.PDF;
const ObjectId = serverLibrary.mongodb.ObjectId;
const AuditTrail = require('./auditTrail');
function beforeAndAfterCallback(action, name, params, isAdmin) {
const { accessRole, route } = params || {}
return Yekonga.Cloud.getBeforeAndAfterCallback(action, name, accessRole, route, isAdmin);
}
module.exports = class ModelControl {
constructor(model) {
this.collection = null;
this.modelTitle = '';
this.modelClass = null;
this.modelClassVariable = null;
this.modelFields = {};
this.modelRelationFields = [];
this.databaseType = null;
this.auditTrail = null;
this.ModelController = {};
this.hasProfileId = false;
this.fileFields = [];
this.timestampFields = [];
this.keyFields = [];
this.init(model);
this.ModelController.ignoreAction = false;
this.ModelController.findOne = this.buildFindOne(this);
this.ModelController.find = this.buildFind(this);
this.ModelController.paginate = this.buildPaginate(this);
this.ModelController.download = this.buildDownload(this);
this.ModelController.summary = this.buildSummary(this);
this.ModelController.count = this.buildCount(this);
this.ModelController.sum = this.buildSum(this);
this.ModelController.max = this.buildMax(this);
this.ModelController.min = this.buildMin(this);
this.ModelController.graph = this.buildGraph(this);
this.ModelController.create = this.buildCreate(this);
this.ModelController.update = this.buildUpdate(this);
this.ModelController.import = this.buildImport(this);
this.ModelController.delete = this.buildDelete(this);
this.ModelController.force = this.buildForce(this);
const conf = Yekonga.Config.database[Yekonga.Config.defaultDatabase];
this.databaseType = (conf && conf.type) ? conf.type : 'mongodb';
}
init(model) {
var updatedCollection = this.collection;
for (const key in model) {
if (key == "profileId") {
this.hasProfileId = true;
break;
}
}
if (model._id) {
this.collection = model._id.collection;
updatedCollection = this.collection.startsWith('_')
? this.collection.substr(1)
: this.collection;
this.modelTitle = H.getTitle(H.toSingular(updatedCollection));
this.modelClass = H.getClass(updatedCollection);
this.modelClassVariable = H.getClassVariable(updatedCollection, true);
}
if (!model._id.secondaryKey) {
model._id.secondaryKey = H.getVariable(`${H.toSingular(H.getUnderscore(updatedCollection))}_id`);
}
this.secondaryKey = model._id.secondaryKey;
this.modelFields = model;
this.auditTrail = new AuditTrail({
collection: this.collection,
modelClass: this.modelClass,
secondaryKey: this.secondaryKey,
});
for (const key in this.modelFields) {
if (H.isTimestampColumn(key, this.modelFields[key])) {
this.timestampFields.push(key);
} else if(H.isColumnUrl(key, this.modelFields[key])) {
this.fileFields.push(key);
}
if(H.isObjectID(key, this.modelFields[key])) {
this.keyFields.push(key);
}
}
this.setRelations();
}
create() {
return this.ModelController;
}
setRelations() {
let parents = {};
let children = {};
let parentsArray = H.getParents(this.modelFields);
let childrenArray = H.getChildren(this.modelFields);
this.modelRelationFields.push(this.secondaryKey);
for (const item of parentsArray) {
this.modelRelationFields.push(item._id.foreignKey);
// parents[H.getClass(item._id.collection)] = H.copyJson(item._id);
parents[item._id.relatedName] = H.copyJson(item._id);
}
for (const item of childrenArray) {
this.modelRelationFields.push(item._id.foreignKey);
// children[H.getClass(item._id.collection)] = H.copyJson(item._id);
children[item._id.relatedName] = H.copyJson(item._id);
}
this.parents = parents;
this.children = children;
}
async getWhere(self, key, operation, value, context) {
var result = {};
if (key == 'AND') {
var newValue = [];
for (const whr of value) {
newValue.push((await self.processWhere(self, whr, context)))
}
result = { key: '$and', value: newValue };
} else if (key == 'OR') {
var newValue = [];
for (const whr of value) {
newValue.push((await self.processWhere(self, whr, context)))
}
result = { key: '$or', value: newValue };
} else if (key == 'NOR') {
var newValue = [];
for (const whr of value) {
newValue.push((await self.processWhere(self, whr, context)))
}
result = { key: '$nor', value: newValue };
} else {
result = await self.getWhereItem(self, key, value, operation);
}
return result;
}
getWhereItem(self, key, value, operation) {
var result = null;
if(
Array.isArray(self.keyFields)
&& self.keyFields.includes(key)
) {
if(
typeof value == "string"
&& value.length == 24
) {
value = new ObjectId(value);
} else if(Array.isArray(value)) {
for (let i = 0; i < value.length; i++) {
if(
typeof value[i] == "string"
&& value[i].length == 24
) {
value[i] = new ObjectId(value[i]);
}
}
}
}
switch (operation) {
case 'equalTo':
result = { key, value: { '$eq': value } };
break;
case 'notEqualTo':
result = { key, value: { '$ne': value } };
break;
case 'lessThan':
value = H.convertCalculatedValue(value);
result = { key, value: { '$lt': value } };
break;
case 'notLessThan':
value = H.convertCalculatedValue(value);
result = { key, value: { '$not': { '$lt': value } } };
break;
case 'lessThanOrEqualTo':
value = H.convertCalculatedValue(value);
result = { key, value: { '$lte': value } };
break;
case 'notLessThanOrEqualTo':
value = H.convertCalculatedValue(value);
result = { key, value: { '$not': { '$lte': value } } };
break;
case 'greaterThan':
value = H.convertCalculatedValue(value);
result = { key, value: { '$gt': value } };
break;
case 'notGreaterThan':
value = H.convertCalculatedValue(value);
result = { key, value: { '$not': { '$gt': value } } };
break;
case 'greaterThanOrEqualTo':
value = H.convertCalculatedValue(value);
result = { key, value: { '$gte': value } };
break;
case 'notGreaterThanOrEqualTo':
value = H.convertCalculatedValue(value);
result = { key, value: { '$not': { '$gte': value } } };
break;
case 'in':
result = { key, value: { '$in': value } };
break;
case 'all':
result = { key, value: { '$all': value } };
break;
case 'notIn':
result = { key, value: { '$nin': value } };
break;
case 'exists':
var exists = (value ? true : false);
if(exists) {
result = {
key,
value: {
'$exists': true,
'$nin': [null,undefined]
}
};
} else {
var valueA = {};
var valueB = {};
valueA[key] = { '$exists': false };
valueB[key] = { '$in': [null,undefined] };
result = {
key: '$or',
value: [valueA, valueB]
};
}
break;
case 'matchesRegex':
result = { key, value: (new RegExp(value, "i")) };
break;
case 'options':
result = { key, value: { '$eq': value } };
break;
case 'text':
result = { key, value: { '$eq': value } };
break;
case 'inQueryKey':
result = { key, value: { '$eq': value } };
break;
case 'notInQueryKey':
result = { key, value: { '$eq': value } };
break;
default:
result = { key, value };
break;
}
return result;
}
async processWhere(self, where, context) {
var filter = {}
const { req } = context;
for (const key in where) {
const valueObj = where[key];
const whereName = H.getClass(key);
if (['AND', 'OR', 'NOR'].includes(key)) {
const params = await self.getWhere(self, key, key, valueObj, context);
filter[params.key] = params.value;
} else if (self.modelFields[key] && self.databaseType == 'mongodb' && (self.modelRelationFields.includes(key) || self.secondaryKey === key)) {
let _value = valueObj;
if (!(valueObj instanceof ObjectId) && typeof valueObj == 'string' && valueObj.length === 24) {
// @ts-ignore
_value = new ObjectId(valueObj);
const params = await self.getWhere(self, key, 'equalTo', _value, context);
filter[H.getColumn(params.key)] = params.value;
} else if (Array.isArray(valueObj)) {
_value = valueObj.map((v) => {
// @ts-ignore
return (typeof v == 'string' && v.length === 24) ? new ObjectId(v) : v;
});
const params = await self.getWhere(self, key, 'in', _value, context);
filter[H.getColumn(params.key)] = params.value;
} else if (valueObj && !(valueObj instanceof ObjectId) && typeof valueObj == 'object') {
for (const operation in valueObj) {
let _value = valueObj[operation];
if (!(_value instanceof ObjectId) && typeof _value == 'string' && _value.length === 24) {
// @ts-ignore
_value = new ObjectId(_value);
} else if (Array.isArray(_value)) {
_value = _value.map((v) => {
// @ts-ignore
return (typeof v == 'string' && v.length == 24) ? new ObjectId(v) : v;
});
}
const params = await self.getWhere(self, key, operation, _value, context);
if (filter[H.getColumn(params.key)]) {
if (params.value && typeof params.value == 'object' && !(params.value instanceof Date) ) {
for (const k in params.value) {
filter[H.getColumn(params.key)][k] = params.value[k];
}
} else {
filter[H.getColumn(params.key)] = params.value;
}
} else {
filter[H.getColumn(params.key)] = params.value;
}
}
} else {
const params = await self.getWhere(self, key, 'equalTo', _value, context);
filter[H.getColumn(params.key)] = params.value;
}
} else if (self.modelFields[key] && valueObj && typeof valueObj == 'object' && !(valueObj instanceof ObjectId)) {
for (const operation in valueObj) {
const value = valueObj[operation];
const params = await self.getWhere(self, key, operation, value, context);
if (filter[H.getColumn(params.key)]) {
if (params.value && typeof params.value == 'object' && !(params.value instanceof Date)) {
if (typeof filter[H.getColumn(params.key)] !== 'object') {
filter[H.getColumn(params.key)] = {};
}
for (const k in params.value) {
filter[H.getColumn(params.key)][k] = params.value[k];
}
} else {
filter[H.getColumn(params.key)] = params.value;
}
} else {
filter[H.getColumn(params.key)] = params.value;
}
}
} else if (self.modelFields[key]) {
let _value = valueObj;
if (key === self.secondaryKey) {
if (typeof valueObj == 'string' && valueObj.length === 24) {
// @ts-ignore
_value = new ObjectId(valueObj);
} else if (Array.isArray(valueObj)) {
_value = valueObj.map((v) => {
// @ts-ignore
return (typeof v == 'string' && v.length === 24) ? new ObjectId(v) : v;
});
}
}
const params = await self.getWhere(self, key, 'equalTo', _value, context);
filter[H.getColumn(params.key)] = params.value;
} else if (!self.modelFields[key] && key.startsWith('_') && self.modelFields[key.substring(1)]) {
let _value = valueObj;
if (key === self.secondaryKey) {
if (typeof valueObj == 'string' && valueObj.length === 24) {
// @ts-ignore
_value = new ObjectId(valueObj);
} else if (Array.isArray(valueObj)) {
_value = valueObj.map((v) => {
// @ts-ignore
return (typeof v == 'string' && v.length === 24) ? new ObjectId(v) : v;
});
}
}
if (_value && typeof _value === 'object') {
filter[key] = _value;
} else {
const params = await self.getWhere(self, key, 'equalTo', _value, context);
filter[params.key] = params.value;
}
} else if (!self.modelFields[key]) {
if (
self.parents[key] || self.children[key]
) {
let ids = [];
let objectToGetKey = {};
objectToGetKey[key] = valueObj;
let objectValueId = H.getObjectUUID(objectToGetKey);
// console.debug(objectToGetKey);
// console.debug(objectValueId);
// console.debug(context.params)
// console.debug(context.filter)
// console.debug('============================')
if (req && !req.Yekonga.Temporary) req.Yekonga.Temporary = {};
if (req && req.Yekonga.Temporary[objectValueId]) {
ids = req.Yekonga.Temporary[objectValueId];
} else {
let localSecondaryKey = null;
let localModelClass = null;
if (self.parents[key]) {
localSecondaryKey = self.parents[key].secondaryKey;
localModelClass = H.getClass(self.parents[key].collection);
} else if (self.children[key]) {
localSecondaryKey = self.children[key].foreignKey;
localModelClass = H.getClass(self.children[key].collection);
}
if (Yekonga.Model[localModelClass]) {
let sourceIds = await Yekonga.Model[localModelClass].find(valueObj, { ...context, select: [localSecondaryKey] }, true);
if (Array.isArray(sourceIds)) {
for (let i = 0; i < sourceIds.length; i++) {
var item = sourceIds[i];
var v = item[localSecondaryKey];
if (typeof v == 'string' && v.length === 24) {
v = new ObjectId(v);
}
if (!(typeof v === 'undefined' || v === null)) {
if (!ids.includes(v)) ids.push(v);
}
}
}
}
}
if (Array.isArray(ids)) {
let params = null;
if (self.parents[key]) {
params = await self.getWhere(self, self.parents[key].foreignKey, 'in', ids, context);
} else if (self.children[key]) {
params = await self.getWhere(self, self.children[key].foreignKey, 'in', ids, context);
}
if (params) {
if(filter[H.getColumn(params.key)]) {
for (const k in filter[H.getColumn(params.key)]) {
if (Object.hasOwnProperty.call(filter[H.getColumn(params.key)], k)) {
params.value[k] = filter[H.getColumn(params.key)][k];
}
}
}
filter[H.getColumn(params.key)] = params.value;
}
}
}
}
}
return filter;
}
async model(self, context, isAdmin = false) {
if(typeof context === 'boolean') {
isAdmin = context;
context = { };
}
if (!context) context = {}
var filterQuery = {};
// @ts-ignore
var { filter, params } = context;
const { beforeFind, afterFind, parent, Auth, Client, headers, req } = context;
// @ts-ignore
if (parent && !context.accessRole) {
context.accessRole = (parent.params && parent.params.accessRole) ? parent.params.accessRole : null;
}
var newFilter = {};
if (!filter) filter = {};
if (self.hasProfileId && !context.accessRole) {
// if (req && req.Yekonga.Auth && req.Yekonga.Auth.profileId) {
// // filter["profileId"] = { equalTo: req.Yekonga.Auth.profileId }
// } else if (!isAdmin) {
// if (!filter["profileId"]) {
// const profileId = (Auth && Auth.profileId) ? Auth.profileId : null;
// if (profileId) {
// // filter["profileId"] = { equalTo: profileId }
// }
// }
// }
}
var InjectFunction = beforeAndAfterCallback('beforeFind', self.modelClass, params, isAdmin);
if (InjectFunction) {
var response = await InjectFunction({
filter,
...context,
});
if (response === false) {
return null;
} else if (typeof response != 'undefined') {
filter = response;
}
}
for (const key in filter) {
if (Object.prototype.hasOwnProperty.call(filter, key)) {
const value = filter[key];
if (value === null || typeof value == 'string' || typeof value == 'number' || typeof value == 'bigint' || typeof value == 'boolean') {
newFilter[key] = { '$eq': value };
} else {
newFilter[key] = value;
}
}
}
var dataModel = Yekonga.DB.table(self.collection);
if (newFilter) {
filterQuery = await self.processWhere(self, newFilter, context);
}
filterQuery = await this.setTimestampFilters(self, dataModel, filterQuery);
dataModel.where(filterQuery);
if (params) {
// console.debug(params);
if (params.page) {
dataModel.page(params.page);
}
if (params.limit) {
dataModel.limit(params.limit);
}
if (params.groupBy) {
if (Array.isArray(params.groupBy)) {
let value = {}
for (const key of params.groupBy) {
if (typeof key == 'string') {
value[H.getColumn(key)] = `$${H.getColumn(key)}`;
} else if (key && typeof key == 'object') {
value = key;
}
}
dataModel.groupBy("_id", value);
} else {
let value = {}
if (typeof params.groupBy == 'string') {
value[H.getColumn(params.groupBy)] = `$${H.getColumn(params.groupBy)}`;
} else if (params.groupBy && typeof params.groupBy == 'object') {
value = params.groupBy;
}
dataModel.groupBy("_id", value);
}
}
if (params.orderBy) {
if (Array.isArray(params.orderBy)) {
for (const orderBy of params.orderBy) {
if (orderBy.key) {
var key = (orderBy.key == '_id' || orderBy.key.startsWith('_id.'))
? orderBy.key
: H.getColumn(orderBy.key);
dataModel.orderBy(key, orderBy.value);
}
}
} else if (params.orderBy.key) {
var key = (params.orderBy.key == '_id' || params.orderBy.key.startsWith('_id.'))
? params.orderBy.key
: H.getColumn(params.orderBy.key);
dataModel.orderBy(key, params.orderBy.value);
}
}
if (params.addedFields) {
dataModel.addField(params.addedFields);
}
}
return dataModel;
}
async setTimestampFilters(self, model, filters) {
var addedFilters = {};
var formattedFilters = {};
for (const key in filters) {
if (self.timestampFields.includes(key)) {
// console.debug(self.timestampFields);
var format = '%Y-%m-%d';
var value = filters[key];
if (value && typeof value == 'object' && !(value instanceof Date)) {
for (const operator in value) {
if (Object.hasOwnProperty.call(value, operator)) {
const _value = value[operator];
if (_value && typeof _value == "string") {
format = H.formatJsToMongo(H.getTimeFormat(_value));
formattedFilters[`_${key}`] = value;
} else if (_value && typeof _value == "object" && !(_value instanceof Date)) {
for (const _operator in _value) {
if (Object.hasOwnProperty.call(_value, _operator)) {
const __value = _value[_operator];
if (__value && typeof __value == "string") {
format = H.formatJsToMongo(H.getTimeFormat(__value));
formattedFilters[`_${key}`] = _value;
}
}
}
} else {
formattedFilters[`${key}`] = value;
}
}
}
}
addedFilters[`_${key}`] = {
$dateToString: {
format: format,
date: `$${key}`
}
}
} else {
formattedFilters[key] = filters[key];
}
}
// if (self.modelClass == "Event") {
// console.debug(filters);
// }
model.addField(addedFilters);
return formattedFilters;
}
buildForce(self) {
return async(force = true) => {
self.ModelController.ignoreAction = force;
return self.ModelController;
}
}
buildFindOne(self) {
return async(filter, context, isAdmin = false) => {
authentication(self.modelClass, `${self.modelClassVariable}.information`, `view ${self.modelTitle} information`);
if(typeof context === 'boolean') {
isAdmin = context;
context = { };
}
if (!context) context = {};
context.filter = filter;
const { select, params, parent, Auth, Client, headers, beforeFind, afterFind, } = context;
var model = await self.model(self, context, isAdmin);
if (model === null) {
throw new Yekonga.Error.Forbidden(getRejectedByAction({modelClass: self.modelClass, params, action: 'before find'}))
}
if (select && Array.isArray(select) && select.length) {
model.select(H.formatToColumn(select));
}
var result = await model.findOne();
result = H.formatToVariables(result, self.secondaryKey, self.collection);
var afterFindInjectFunction = beforeAndAfterCallback('afterFind', self.modelClass, params, isAdmin);
if (afterFindInjectFunction) {
await afterFindInjectFunction({
result,
...context,
})
}
if(result) {
result.__ = {
collection: self.collection,
secondaryKey: self.secondaryKey,
}
}
return result;
}
}
buildFind(self) {
return async(filter, context, isAdmin = false) => {
authentication(self.modelClass, `${self.modelClassVariable}.list`, `see ${self.modelTitle} list`);
if(typeof context === 'boolean') {
isAdmin = context;
context = { };
}
if (!context) context = {};
context.filter = filter;
const { select, params, parent, Auth, Client, headers, beforeFind, afterFind, } = context;
var model = await self.model(self, context, isAdmin);
if (model === null) throw new Yekonga.Error.Forbidden(getRejectedByAction({modelClass: self.modelClass, params, action: 'before find'}));
if (select && Array.isArray(select) && select.length) {
model.select(H.formatToColumn(select))
}
var result = await model.find();
result = H.formatToVariables(result, self.secondaryKey, self.collection);
if (!Array.isArray(result)) {
result = [];
}
var afterFindInjectFunction = beforeAndAfterCallback('afterFind', self.modelClass, params, isAdmin);
if (afterFindInjectFunction) {
await afterFindInjectFunction({
result,
...context,
})
}
return result;
}
}
buildPaginate(self) {
return async(filter, context, isAdmin = false) => {
authentication(self.modelClass, `${self.modelClassVariable}.list`, `see ${self.modelTitle} list`);
if(typeof context === 'boolean') {
isAdmin = context;
context = { };
}
if (!context) context = {};
context.filter = filter;
const { select, params, parent, Auth, Client, headers, beforeFind, afterFind, } = context;
var model = await self.model(self, context, isAdmin);
if (model === null) throw new Yekonga.Error.Forbidden(getRejectedByAction({modelClass: self.modelClass, params, action: 'before find'}));
if (select && Array.isArray(select) && select.length) {
model.select(H.formatToColumn(select))
}
var result = await model.paginate();
result.data = H.formatToVariables(result.data, self.secondaryKey, self.collection);
var afterFindInjectFunction = beforeAndAfterCallback('afterFind', self.modelClass, params, isAdmin);
if (afterFindInjectFunction) {
await afterFindInjectFunction({
result,
...context,
});
}
return result;
}
}
buildDownload(self) {
var headingColumnNames = [];
for (const key in this.modelFields) {
headingColumnNames.push(H.getTitle(key));
}
return async(filter, context, isAdmin = false) => {
authentication(self.modelClass, `${self.modelClassVariable}.download`, `download ${self.modelTitle} list`, false);
if(typeof context === 'boolean') {
isAdmin = context;
context = { };
}
if (!context) context = {};
context.filter = filter;
const { select, params, parent, Auth, Client, headers, beforeFind, afterFind, req, res} = context;
var data = [];
var queryBody = null;
if(
req
&& req.Yekonga
&& req.Yekonga.Client
&& req.Yekonga.Client.body
&& req.Yekonga.Client.body.variables
&& req.Yekonga.Client.body.variables.download
) {
queryBody = req.Yekonga.Client.body.variables.download;
}
// console.debug('downloadQuery', 'Start');
if (queryBody) {
data = await Yekonga.Helper.getGraphql(queryBody, req.Yekonga.Client.headers, 'list', context);
} else {
var model = await self.model(self, context, isAdmin);
if (model === null) throw new Yekonga.Error.Forbidden(getRejectedByAction({modelClass: self.modelClass, params, action: 'before download'}));
if (select && Array.isArray(select) && select.length) {
model.select(H.formatToColumn(select))
}
data = await model.limit(null).find();
}
// console.debug('downloadQuery', 'Loaded');
if (Array.isArray(data)) {
var timezone = (headers)? (headers['timezone'] || headers['Timezone']): null;
// console.debug("download timezone:", timezone);
data = data.map(e => {
// console.debug(e);
return ModelControl.getDataValue(e, timezone);
});
} else {
// console.debug()
data = [];
}
// console.debug('downloadQuery', 'sorted');
// console.debug("downloadQuery", headingColumnNames)
headingColumnNames = ModelControl.getHeading(headingColumnNames, data);
// console.debug("downloadQuery", headingColumnNames)
var publicPath = Array.isArray(Yekonga.Config.public) ? Yekonga.Config.public[0] : Yekonga.Config.public;
var time = H.toTimestampString(null, 'YYYY-MM-DD-HHmm'); // YYYY-MM-DD-HHmm
var ext = ModelControl.getExtName(params.downloadType);
var filename = `${H.getLink(self.modelClass)}-${time}.${ext}`;
var dirpath = `${path.join(serverLibrary.__dirname, publicPath)}/tmp/`;
var filepath = `${dirpath}/${filename}`;
var fileUrl = `//${Yekonga.Config.domain}/download/${filename}`;
if (!fs.existsSync(filepath)) {
H.createFile(filepath, '');
}
var result = {
filename: null,
url: null,
type: params.downloadType,
size: 0,
}
if (['PDF', 'PRINT', 'JPG', 'PNG', 'IMAGE'].includes(result.type)) {
var html = this._dataHtmlContent(headingColumnNames, data);
var orientation = (params.orientation) ? params.orientation : 'portrait';
var options = { format: 'A4', orientation: orientation, type: ext, quality: "100", };
options.margin = { top: '10px', right: '10px', bottom: '10px', left: '10px' };
// @ts-ignore
await H.PDF(html, filepath, options);
} else if (result.type == 'EXCEL') {
const wb = new excel.Workbook();
const ws = wb.addWorksheet('Raw Data');
//Write Column Title in Excel file
let headingColumnIndex = 1;
headingColumnNames.forEach(heading => {
ws.cell(1, headingColumnIndex++).string(H.getTitle(heading));
});
//Write Data in Excel file
let rowIndex = 2;
data.forEach(record => {
let columnIndex = 1;
for (const key of headingColumnNames) {
var v = record[key];
if(Array.isArray(v)) v = v.join(" / ");
ws.cell(rowIndex, columnIndex++).string(`${(typeof v != 'undefined' && v != null)? v: ''}`);
}
rowIndex++;
});
wb.write(filepath);
} else {
const csvData = [headingColumnNames.map(e=>H.getTitle(e)).join(',')];
//Write Data in Excel file
data.forEach(record => {
let _data = [];
for (const key of headingColumnNames) {
var v = record[key];
if(Array.isArray(v)) v = v.join(" / ");
if(typeof v == 'string'){
if(v.includes(',')) v = JSON.stringify(v);
else if(v.includes("'")) v = JSON.stringify(v);
}
_data.push(v);
}
csvData.push(_data);
});
fs.writeFileSync(filepath, csvData.join('\n'));
}
result.filename = filename;
result.url = fileUrl;
await H.wait(5000);
var afterFindInjectFunction = beforeAndAfterCallback('afterFind', self.modelClass, params, isAdmin);
if (afterFindInjectFunction) {
await afterFindInjectFunction({
result,
...context,
})
}
return result;
}
}
buildCreate(self) {
var secondaryKey = this.secondaryKey;
return async(input, context, isAdmin = false) => {
authentication(self.modelClass, `${self.modelClassVariable}.create`, `${self.modelTitle}`);
if(typeof context === 'boolean') {
isAdmin = context;
context = { };
}
if (!context) context = {};
if (!context.params) context.params = {};
const { select, params, parent, Auth, Client, headers, beforeFind, afterFind, } = context;
const orgInput = H.copyJson(context.params.input);
const { beforeSave, afterSave, beforeCreate, afterCreate } = context;
var result = null;
try {
if (Array.isArray(input)) {
var _inputValid = [];
for (let i = 0; i < input.length; i++) {
const v = input[i];
if (v && !v[secondaryKey]) v[secondaryKey] = H.getHexString();
const value = H.formatToColumn(H.getValidFields({
input: v,
validFields: self.modelFields,
isCreate: true,
relations: self.modelRelationFields,
request: context.req,
fileFields: self.fileFields,
}).pop())
if (self.modelClass === 'User') {
if (!value.email && !value.phone) {
throw new Yekonga.Error.Forbidden(`User must have email or phone number`);
}
if (typeof value.email == 'string' && !H.isEmail(value.email)) {
throw new Yekonga.Error.Forbidden(`Email can't be empty or must be valid`);
}
if (typeof value.phone == 'string' && !H.isPhone(value.phone)) {
throw new Yekonga.Error.Forbidden(`Phone number can't be empty or must be valid`);
}
if (value.email && H.isEmailIdentifier()) await H.uniqueEmail(value.email, null);
if (value.phone && H.isPhoneIdentifier()) await H.uniquePhone(value.phone, null);
if (value.whatsapp && H.isWhatsappIdentifier()) await H.uniqueWhatsapp(value.whatsapp, null);
if (value.username && H.isUsernameIdentifier()) await H.uniqueUsername(value.username, null);
}
if (self.hasProfileId && self.modelClass == 'Profile') {
value.profileId = new ObjectId(H.getHexString());
}
_inputValid.push(value);
}
input = _inputValid;
} else {
if (!input[secondaryKey]) input[secondaryKey] = H.getHexString();
// {input, validFields, isCreate = false, fileFields = [], relations = [], request = {}}
input = H.formatToColumn(H.getValidFields({
input: input,
validFields: self.modelFields,
isCreate: true,
relations: self.modelRelationFields,
request: context.req,
fileFields: self.fileFields,
}).pop());
if (self.modelClass == 'User') {
if (input.email && H.isEmailIdentifier()) await H.uniqueEmail(input.email, null);
if (input.phone && H.isPhoneIdentifier()) await H.uniquePhone(input.phone, null);
if (input.whatsapp && H.isWhatsappIdentifier()) await H.uniqueWhatsapp(input.whatsapp, null);
if (input.username && H.isUsernameIdentifier()) await H.uniqueUsername(input.username, null);
}
if (self.hasProfileId && self.modelClass == 'Profile') {
input.profileId = new ObjectId(H.getHexString())
}
}
var beforeSaveInjectFunction = beforeAndAfterCallback('beforeSave', self.modelClass, params, isAdmin);
if (beforeSaveInjectFunction) {
var _input = await beforeSaveInjectFunction({
input,
result,
...context,
});
if (_input === false) throw new Yekonga.Error.Forbidden(getRejectedByAction({modelClass: self.modelClass, params, action: 'before save'}));
if (_input) input = _input;
}
var beforeCreateInjectFunction = beforeAndAfterCallback('beforeCreate', self.modelClass, params, isAdmin);
if (beforeCreateInjectFunction) {
var _input = await beforeCreateInjectFunction({
input,
result,
...context,
});
if (_input === false) throw new Yekonga.Error.Forbidden(getRejectedByAction({modelClass: self.modelClass, params, action: 'before create'}));
if (_input) input = _input;
}
// {input, validFields, isCreate = false, fileFields = [], relations = [], request = {}}
input = H.formatToColumn(H.getValidFields({
input: input,
validFields: self.modelFields,
isCreate: true,
relations: self.modelRelationFields,
request: null,
fileFields: self.fileFields,
secondaryKey: self.secondaryKey,
}));
self.auditTrail.setOldValues(context, isAdmin);
result = await Yekonga.DB.table(self.collection, H.getColumn(`${secondaryKey}`)).create(input);
self.auditTrail.record(orgInput, 'create', result.data);
if (Array.isArray(result.data)) {
result.data = result.data.map(v => {
return H.formatToVariables(v, secondaryKey, self.collection);
});
} else {
result.data = H.formatToVariables(result.data, secondaryKey, self.collection);
}
} catch (error) {
console.error(error);
result = { error: error.message };
}
var afterSaveInjectFunction = beforeAndAfterCallback('afterSave', self.modelClass, params, isAdmin);
if (afterSaveInjectFunction) {
await afterSaveInjectFunction({
result,
input,
...context,
})
}
var afterCreateInjectFunction = beforeAndAfterCallback('afterCreate', self.modelClass, params, isAdmin);
if (afterCreateInjectFunction) {
await afterCreateInjectFunction({
result,
input,
...context,
})
}
return result;
}
}
buildUpdate(self) {
return async(input, filter, context, isAdmin = false) => {
authentication(self.modelClass, `${self.modelClassVariable}.edit`, `${self.modelTitle} data`);
if(typeof context === 'boolean') {
isAdmin = context;
context = { };
}
if (!context) context = {};
context.filter = filter;
const { select, params, parent, Auth, Client, headers, beforeFind, afterFind, beforeSave, afterSave, beforeUpdate, afterUpdate } = context;
var model = null;
var result = null;
try {
// {input, validFields, isCreate = false, fileFields = [], relations = [], request = {}}
input = H.getValidFields({
input: input,
validFields: self.modelFields,
isCreate: false,
relations: self.modelRelationFields,
request: context.req,
fileFields: self.fileFields,
secondaryKey: self.secondaryKey,
}).pop();
input = H.formatToColumn(input);
model = await self.model(self, context, isAdmin);
var beforeSaveInjectFunction = beforeAndAfterCallback('beforeSave', self.modelClass, params, isAdmin);
if (beforeSaveInjectFunction) {
var _input = await beforeSaveInjectFunction({
input,
filter,
...context,
});
if (_input === false) throw new Yekonga.Error.Forbidden(getRejectedByAction({modelClass: self.modelClass, params, action: 'before save'}));
if (_input) input = _input;
}
var beforeUpdateInjectFunction = beforeAndAfterCallback('beforeUpdate', self.modelClass, params, isAdmin);
if (beforeUpdateInjectFunction) {
var _input = await beforeUpdateInjectFunction({
input,
filter,
...context,
});
if (_input === false) throw new Yekonga.Error.Forbidden(getRejectedByAction({modelClass: self.modelClass, params, action: 'before update'}));
if (_input) input = _input;
}
if (self.modelClass == 'User') {
if (input.email && H.isEmailIdentifier()) await H.uniqueEmail(input.email, filter);
if (input.phone && H.isPhoneIdentifier()) await H.uniquePhone(input.phone, filter);
if (input.whatsapp && H.isWhatsappIdentifier()) await H.uniqueWhatsapp(input.whatsapp, filter);
if (input.username && H.isUsernameIdentifier()) await H.uniqueUsername(input.username, filter);
}
// {input, validFields, isCreate = false, fileFields = [], relations = [], request = {}}
input = H.getValidFields({
input: input,
validFields: self.modelFields,
isCreate: false,
relations: self.modelRelationFields,
request: null,
fileFields: self.fileFields,
secondaryKey: self.secondaryKey,
}).pop();
await self.auditTrail.setOldValues(context, isAdmin, model);
result = await model.update(input);
result.data = H.formatToVariables(result.data, self.secondaryKey, self.collection);
self.auditTrail.record(input, 'update', result.data);
} catch (error) {
console.error(error);
result = null;
result = { error: error.message };
throw new Yekonga.Error.Forbidden(result.error);
}
if (model === null) throw new Yekonga.Error.Forbidden(getRejectedByAction({modelClass: self.modelClass, params, action: 'before find on update'}));
var afterSaveInjectFunction = beforeAndAfterCallback(