forms-angular 0.12.0-beta.246 → 0.12.0-beta.247
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/server/data_form.js +82 -19
- package/dist/server/index.d.ts +2 -2
- package/package.json +1 -1
package/dist/server/data_form.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.FormsAngular = void 0;
|
|
4
4
|
const mongoose_1 = require("mongoose");
|
|
5
|
-
// This part of forms-angular borrows
|
|
5
|
+
// This part of forms-angular borrows from https://github.com/Alexandre-Strzelewicz/angular-bridge
|
|
6
6
|
// (now https://github.com/Unitech/angular-bridge
|
|
7
7
|
const _ = require('lodash');
|
|
8
8
|
const util = require('util');
|
|
@@ -907,7 +907,7 @@ class FormsAngular {
|
|
|
907
907
|
}
|
|
908
908
|
}
|
|
909
909
|
;
|
|
910
|
-
sanitisePipeline(aggregationParam, hiddenFields, findFuncQry) {
|
|
910
|
+
async sanitisePipeline(aggregationParam, hiddenFields, findFuncQry, req) {
|
|
911
911
|
let that = this;
|
|
912
912
|
let array = Array.isArray(aggregationParam) ? aggregationParam : [aggregationParam];
|
|
913
913
|
let retVal = [];
|
|
@@ -922,9 +922,16 @@ class FormsAngular {
|
|
|
922
922
|
throw new Error('Invalid pipeline instruction');
|
|
923
923
|
}
|
|
924
924
|
switch (keys[0]) {
|
|
925
|
-
case '$
|
|
926
|
-
case '$
|
|
927
|
-
|
|
925
|
+
case '$project':
|
|
926
|
+
case '$addFields':
|
|
927
|
+
case '$count':
|
|
928
|
+
case "$group":
|
|
929
|
+
case "$limit":
|
|
930
|
+
case "$replaceRoot":
|
|
931
|
+
case "$sort":
|
|
932
|
+
case "$unwind":
|
|
933
|
+
// We don't care about these - they are all (as far as we know) safe
|
|
934
|
+
break;
|
|
928
935
|
case '$unionWith':
|
|
929
936
|
/*
|
|
930
937
|
Sanitise the pipeline we are doing a union with, removing hidden fields from that collection
|
|
@@ -940,7 +947,7 @@ class FormsAngular {
|
|
|
940
947
|
unionHiddenLookupFields = this.generateHiddenFields(unionResource, false);
|
|
941
948
|
}
|
|
942
949
|
}
|
|
943
|
-
stage.$unionWith.pipeline = that.sanitisePipeline(stage.$unionWith.pipeline, unionHiddenLookupFields, findFuncQry);
|
|
950
|
+
stage.$unionWith.pipeline = await that.sanitisePipeline(stage.$unionWith.pipeline, unionHiddenLookupFields, findFuncQry, req);
|
|
944
951
|
break;
|
|
945
952
|
case '$match':
|
|
946
953
|
this.hackVariables(array[pipelineSection]['$match']);
|
|
@@ -954,14 +961,24 @@ class FormsAngular {
|
|
|
954
961
|
stage = null;
|
|
955
962
|
break;
|
|
956
963
|
case '$lookup':
|
|
964
|
+
case '$graphLookup':
|
|
965
|
+
if (keys[0] === '$lookup') {
|
|
966
|
+
// For now at least, we only support simple $lookups with a single join field equality
|
|
967
|
+
let lookupProps = Object.keys(stage.$lookup);
|
|
968
|
+
if (lookupProps.length !== 4 || lookupProps.indexOf('from') === -1 || lookupProps.indexOf('localField') === -1 || lookupProps.indexOf('foreignField') === -1 || lookupProps.indexOf('as') === -1) {
|
|
969
|
+
throw new Error("No support for $lookup that isn't Equality Match with a Single Join Condition");
|
|
970
|
+
}
|
|
971
|
+
}
|
|
957
972
|
// hide any hiddenfields in the lookup collection
|
|
958
|
-
const collectionName = stage
|
|
959
|
-
const lookupField = stage
|
|
973
|
+
const collectionName = stage[keys[0]].from;
|
|
974
|
+
const lookupField = stage[keys[0]].as;
|
|
960
975
|
if ((collectionName + lookupField).indexOf('$') !== -1) {
|
|
961
976
|
throw new Error('No support for lookups where the "from" or "as" is anything other than a simple string');
|
|
962
977
|
}
|
|
963
978
|
const resource = that.getResourceFromCollection(collectionName);
|
|
964
979
|
if (resource) {
|
|
980
|
+
retVal.push(stage);
|
|
981
|
+
stage = null;
|
|
965
982
|
if (resource.options?.hide?.length > 0) {
|
|
966
983
|
const hiddenLookupFields = this.generateHiddenFields(resource, false);
|
|
967
984
|
let hiddenFieldsObj = {};
|
|
@@ -970,11 +987,40 @@ class FormsAngular {
|
|
|
970
987
|
});
|
|
971
988
|
retVal.push({ $project: hiddenFieldsObj });
|
|
972
989
|
}
|
|
990
|
+
// Now we need to make sure that we restrict the lookup to documents we have access to
|
|
991
|
+
if (resource.options.findFunc) {
|
|
992
|
+
// If the next stage is an $unwind
|
|
993
|
+
let nextStageIsUnwind = false;
|
|
994
|
+
if (array.length >= pipelineSection) {
|
|
995
|
+
const nextStage = array[pipelineSection + 1];
|
|
996
|
+
let nextKeys = Object.keys(nextStage);
|
|
997
|
+
if (nextKeys.length !== 1) {
|
|
998
|
+
throw new Error('Invalid pipeline instruction');
|
|
999
|
+
}
|
|
1000
|
+
if (nextKeys[0] === '$unwind' && nextStage["$unwind"] === "$" + lookupField) {
|
|
1001
|
+
nextStageIsUnwind = true;
|
|
1002
|
+
}
|
|
1003
|
+
}
|
|
1004
|
+
if (!nextStageIsUnwind) {
|
|
1005
|
+
throw new Error('No support for $lookup where the next stage is not an $unwind and the resources has a findFunc');
|
|
1006
|
+
}
|
|
1007
|
+
// Push the $unwind, add our own findFunc, and increment the pipelineStage counter
|
|
1008
|
+
retVal.push({ $unwind: "$" + lookupField });
|
|
1009
|
+
const lookedUpFindQry = await this.doFindFuncPromise(req, resource);
|
|
1010
|
+
// Now we need to put the lookup base into the criteria
|
|
1011
|
+
for (const prop in lookedUpFindQry) {
|
|
1012
|
+
if (lookedUpFindQry.hasOwnProperty(prop)) {
|
|
1013
|
+
lookedUpFindQry[`${lookupField}.${prop}`] = lookedUpFindQry[prop];
|
|
1014
|
+
delete lookedUpFindQry[prop];
|
|
1015
|
+
}
|
|
1016
|
+
}
|
|
1017
|
+
retVal.push({ $match: lookedUpFindQry });
|
|
1018
|
+
}
|
|
973
1019
|
}
|
|
974
1020
|
break;
|
|
975
1021
|
default:
|
|
976
|
-
//
|
|
977
|
-
|
|
1022
|
+
// anything else is either known to be dangerous, not yet needed or we don't know what it is
|
|
1023
|
+
throw new Error('Unsupported pipeline instruction ' + keys[0]);
|
|
978
1024
|
}
|
|
979
1025
|
if (stage) {
|
|
980
1026
|
retVal.push(stage);
|
|
@@ -1040,13 +1086,18 @@ class FormsAngular {
|
|
|
1040
1086
|
let hiddenFields = self.generateHiddenFields(resource, false);
|
|
1041
1087
|
let toDo = {
|
|
1042
1088
|
runAggregation: function (cb) {
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
.
|
|
1046
|
-
|
|
1089
|
+
self.sanitisePipeline(runPipelineObj, hiddenFields, queryObj, req)
|
|
1090
|
+
.then((runPipelineObj) => {
|
|
1091
|
+
resource.model.aggregate(runPipelineObj)
|
|
1092
|
+
.then((results) => {
|
|
1093
|
+
cb(null, results);
|
|
1094
|
+
})
|
|
1095
|
+
.catch((err) => {
|
|
1096
|
+
cb(err);
|
|
1097
|
+
});
|
|
1047
1098
|
})
|
|
1048
1099
|
.catch((err) => {
|
|
1049
|
-
|
|
1100
|
+
throw new Error('Error in sanitisePipeline ' + err);
|
|
1050
1101
|
});
|
|
1051
1102
|
}
|
|
1052
1103
|
};
|
|
@@ -1166,7 +1217,6 @@ class FormsAngular {
|
|
|
1166
1217
|
callback(err);
|
|
1167
1218
|
}
|
|
1168
1219
|
else {
|
|
1169
|
-
// TODO: Could loop through schema.params and just send back the values
|
|
1170
1220
|
callback(null, {
|
|
1171
1221
|
success: true,
|
|
1172
1222
|
schema: schema,
|
|
@@ -1327,13 +1377,26 @@ class FormsAngular {
|
|
|
1327
1377
|
}
|
|
1328
1378
|
}
|
|
1329
1379
|
;
|
|
1330
|
-
|
|
1380
|
+
async doFindFuncPromise(req, resource) {
|
|
1381
|
+
return new Promise((resolve, reject) => {
|
|
1382
|
+
this.doFindFunc(req, resource, (err, queryObj) => {
|
|
1383
|
+
if (err) {
|
|
1384
|
+
reject(err);
|
|
1385
|
+
}
|
|
1386
|
+
else {
|
|
1387
|
+
resolve(queryObj);
|
|
1388
|
+
}
|
|
1389
|
+
});
|
|
1390
|
+
});
|
|
1391
|
+
}
|
|
1392
|
+
;
|
|
1393
|
+
async filteredFind(resource, req, aggregationParam, findParam, projectParam, sortOrder, limit, skip, callback) {
|
|
1331
1394
|
const that = this;
|
|
1332
1395
|
let hiddenFields = this.generateHiddenFields(resource, false);
|
|
1333
1396
|
let stashAggregationResults;
|
|
1334
|
-
function doAggregation(queryObj, cb) {
|
|
1397
|
+
async function doAggregation(queryObj, cb) {
|
|
1335
1398
|
if (aggregationParam) {
|
|
1336
|
-
aggregationParam = that.sanitisePipeline(aggregationParam, hiddenFields, queryObj);
|
|
1399
|
+
aggregationParam = await that.sanitisePipeline(aggregationParam, hiddenFields, queryObj, req);
|
|
1337
1400
|
resource.model.aggregate(aggregationParam)
|
|
1338
1401
|
.then((aggregationResults) => {
|
|
1339
1402
|
stashAggregationResults = aggregationResults;
|
package/dist/server/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Error, Model, Types } from "mongoose";
|
|
1
|
+
import { Error, FilterQuery, Model, Types } from "mongoose";
|
|
2
2
|
import {Express} from "express";
|
|
3
3
|
|
|
4
4
|
declare module fngServer {
|
|
@@ -52,7 +52,7 @@ declare module fngServer {
|
|
|
52
52
|
handleRemove?: 'allow' | 'cascade'; // default behaviour is to prevent deletion if record is used as a foreign key
|
|
53
53
|
searchImportance?: boolean | number,
|
|
54
54
|
onSave?: (doc, req, cb) => void,
|
|
55
|
-
findFunc?: (req, cb) => void,
|
|
55
|
+
findFunc?: (req: Express.Request, cb: (err:Error, criteria?: FilterQuery<any>) => void) => void,
|
|
56
56
|
getOrgCriteria?: (userOrganisation: string) => Promise<any>
|
|
57
57
|
idIsList?: IIdIsList,
|
|
58
58
|
searchResultFormat?: ISearchResultFormatter,
|
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"author": "Mark Chapman <support@forms-angular.org>",
|
|
4
4
|
"description": "A form builder that sits on top of Angular.js, Twitter Bootstrap, jQuery UI, Angular-UI, Express and Mongoose. Opinionated or what?",
|
|
5
5
|
"homepage": "http://forms-angular.org",
|
|
6
|
-
"version": "0.12.0-beta.
|
|
6
|
+
"version": "0.12.0-beta.247",
|
|
7
7
|
"engines": {
|
|
8
8
|
"node": ">=8.x",
|
|
9
9
|
"npm": ">=5.x"
|