@formio/appserver 1.0.0
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/README.md +61 -0
- package/lib/actions/index.d.ts +160 -0
- package/lib/actions/index.js +10 -0
- package/lib/actions/login/LoginAction.d.ts +110 -0
- package/lib/actions/login/LoginAction.js +288 -0
- package/lib/actions/role/RoleAction.d.ts +62 -0
- package/lib/actions/role/RoleAction.js +171 -0
- package/lib/actions/save/SaveAction.d.ts +29 -0
- package/lib/actions/save/SaveAction.js +307 -0
- package/lib/auth.d.ts +5 -0
- package/lib/auth.js +70 -0
- package/lib/db.d.ts +76 -0
- package/lib/db.js +384 -0
- package/lib/index.d.ts +167 -0
- package/lib/index.js +18 -0
- package/lib/prepare/access.d.ts +3 -0
- package/lib/prepare/access.js +62 -0
- package/lib/prepare/bcrypt.d.ts +3 -0
- package/lib/prepare/bcrypt.js +25 -0
- package/lib/prepare/index.d.ts +10 -0
- package/lib/prepare/index.js +54 -0
- package/lib/prepare/password.d.ts +3 -0
- package/lib/prepare/password.js +28 -0
- package/lib/prepare/persist.d.ts +3 -0
- package/lib/prepare/persist.js +24 -0
- package/lib/prepare/protect.d.ts +3 -0
- package/lib/prepare/protect.js +28 -0
- package/lib/process/calculate.d.ts +3 -0
- package/lib/process/calculate.js +23 -0
- package/lib/process/conditions.d.ts +3 -0
- package/lib/process/conditions.js +54 -0
- package/lib/process/fetch.d.ts +3 -0
- package/lib/process/fetch.js +61 -0
- package/lib/process/index.d.ts +9 -0
- package/lib/process/index.js +56 -0
- package/lib/process/validate.d.ts +3 -0
- package/lib/process/validate.js +14 -0
- package/lib/types/action.d.ts +7 -0
- package/lib/types/action.js +2 -0
- package/lib/types/form.d.ts +4 -0
- package/lib/types/form.js +2 -0
- package/lib/types/project.d.ts +4 -0
- package/lib/types/project.js +2 -0
- package/lib/types/server.d.ts +75 -0
- package/lib/types/server.js +2 -0
- package/lib/types/submission.d.ts +38 -0
- package/lib/types/submission.js +2 -0
- package/package.json +48 -0
- package/server.js +3 -0
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.RoleAction = void 0;
|
|
13
|
+
const debug = require('debug')('formio:actions:role');
|
|
14
|
+
const error = require('debug')('formio:error');
|
|
15
|
+
exports.RoleAction = {
|
|
16
|
+
// The action information.
|
|
17
|
+
get info() {
|
|
18
|
+
return {
|
|
19
|
+
name: 'role',
|
|
20
|
+
title: 'Role Assignment',
|
|
21
|
+
description: 'Provides the Role Assignment capabilities.',
|
|
22
|
+
priority: 1,
|
|
23
|
+
defaults: {
|
|
24
|
+
handler: ['after'],
|
|
25
|
+
method: ['create']
|
|
26
|
+
},
|
|
27
|
+
access: {
|
|
28
|
+
handler: false,
|
|
29
|
+
method: false
|
|
30
|
+
}
|
|
31
|
+
};
|
|
32
|
+
},
|
|
33
|
+
/**
|
|
34
|
+
* The settings form for this action.
|
|
35
|
+
* @param {*} scope
|
|
36
|
+
*/
|
|
37
|
+
settingsForm(scope) {
|
|
38
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
39
|
+
return [
|
|
40
|
+
{
|
|
41
|
+
type: 'select',
|
|
42
|
+
input: true,
|
|
43
|
+
label: 'Resource Association',
|
|
44
|
+
key: 'association',
|
|
45
|
+
placeholder: 'Select the type of resource to perform role manipulation.',
|
|
46
|
+
template: '<span>{{ item.title }}</span>',
|
|
47
|
+
dataSrc: 'json',
|
|
48
|
+
data: {
|
|
49
|
+
json: JSON.stringify([
|
|
50
|
+
{
|
|
51
|
+
association: 'existing',
|
|
52
|
+
title: 'Existing Resource'
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
association: 'new',
|
|
56
|
+
title: 'New Resource'
|
|
57
|
+
}
|
|
58
|
+
])
|
|
59
|
+
},
|
|
60
|
+
valueProperty: 'association',
|
|
61
|
+
multiple: false,
|
|
62
|
+
validate: {
|
|
63
|
+
required: true
|
|
64
|
+
}
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
type: 'select',
|
|
68
|
+
input: true,
|
|
69
|
+
label: 'Action Type',
|
|
70
|
+
key: 'type',
|
|
71
|
+
placeholder: 'Select whether this Action will Add or Remove the contained Role.',
|
|
72
|
+
template: '<span>{{ item.title }}</span>',
|
|
73
|
+
dataSrc: 'json',
|
|
74
|
+
data: {
|
|
75
|
+
json: JSON.stringify([
|
|
76
|
+
{
|
|
77
|
+
type: 'add',
|
|
78
|
+
title: 'Add Role'
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
type: 'remove',
|
|
82
|
+
title: 'Remove Role'
|
|
83
|
+
}
|
|
84
|
+
])
|
|
85
|
+
},
|
|
86
|
+
valueProperty: 'type',
|
|
87
|
+
multiple: false,
|
|
88
|
+
validate: {
|
|
89
|
+
required: true
|
|
90
|
+
}
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
type: 'select',
|
|
94
|
+
input: true,
|
|
95
|
+
label: 'Role',
|
|
96
|
+
key: 'role',
|
|
97
|
+
placeholder: 'Select the Role that this action will Add or Remove.',
|
|
98
|
+
template: '<span>{{ item.title }}</span>',
|
|
99
|
+
dataSrc: 'json',
|
|
100
|
+
data: { json: Object.values(scope.template.roles) },
|
|
101
|
+
valueProperty: '_id',
|
|
102
|
+
multiple: false,
|
|
103
|
+
validate: {
|
|
104
|
+
required: true
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
];
|
|
108
|
+
});
|
|
109
|
+
},
|
|
110
|
+
/**
|
|
111
|
+
* Returns the action middleware.
|
|
112
|
+
*
|
|
113
|
+
* @param {*} scope
|
|
114
|
+
*/
|
|
115
|
+
executor(scope) {
|
|
116
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
117
|
+
return (req, res, next) => __awaiter(this, void 0, void 0, function* () {
|
|
118
|
+
debug('Role Action');
|
|
119
|
+
// Check the submission for the submissionId.
|
|
120
|
+
if (scope.action.settings.association !== 'existing' && scope.action.settings.association !== 'new') {
|
|
121
|
+
error('Invalid setting `association` for the RoleAction; expecting `new` or `existing`.');
|
|
122
|
+
return res.status(400).send('Invalid setting `association` for the RoleAction; expecting `new` or `existing`.');
|
|
123
|
+
}
|
|
124
|
+
// Error if operation type is not valid.
|
|
125
|
+
if (!scope.action.settings.type || (scope.action.settings.type !== 'add' && scope.action.settings.type !== 'remove')) {
|
|
126
|
+
error('Invalid setting `type` for the RoleAction; expecting `add` or `remove`.');
|
|
127
|
+
return res.status(400).send('Invalid setting `type` for the RoleAction; expecting `add` or `remove`.');
|
|
128
|
+
}
|
|
129
|
+
// Error if no resource is being returned.
|
|
130
|
+
if (scope.action.settings.association === 'new' && res.hasOwnProperty('resource') && !res.resource.item && scope.action.settings.role) {
|
|
131
|
+
error('Invalid resource was provided for RoleAction association of `new`.');
|
|
132
|
+
return res.status(400).send('Invalid resource was provided for RoleAction association of `new`.');
|
|
133
|
+
}
|
|
134
|
+
// Error if association is existing and valid data was not provided.
|
|
135
|
+
if (scope.action.settings.association === 'existing' && !scope.action.settings.role) {
|
|
136
|
+
error('Missing role for RoleAction association of "existing". Must specify role to assign in action settings or a form component named "role"');
|
|
137
|
+
return res.status(400).send('Missing role for RoleAction association of "existing". Must specify role to assign in action settings or a form component named "role"');
|
|
138
|
+
}
|
|
139
|
+
if (scope.action.settings.association === 'existing' && !res.resource.item) {
|
|
140
|
+
error('Missing submission for RoleAction association of "existing:. Form must have a resource field named "submission".');
|
|
141
|
+
return res.status(400).send('Missing submission for RoleAction association of "existing:. Form must have a resource field named "submission".');
|
|
142
|
+
}
|
|
143
|
+
// Determine the resources based on the current request.
|
|
144
|
+
let resource = res.resource ? (res.resource.item || req.body) : req.body;
|
|
145
|
+
let role = scope.utils.roleId(scope, scope.action.settings.role);
|
|
146
|
+
if (!resource.roles) {
|
|
147
|
+
resource.roles = [];
|
|
148
|
+
}
|
|
149
|
+
const roleIndex = resource.roles.indexOf(role);
|
|
150
|
+
switch (scope.action.settings.type) {
|
|
151
|
+
case 'add':
|
|
152
|
+
if (roleIndex !== -1) {
|
|
153
|
+
return next();
|
|
154
|
+
}
|
|
155
|
+
resource.roles.push(role);
|
|
156
|
+
break;
|
|
157
|
+
case 'remove':
|
|
158
|
+
if (roleIndex === -1) {
|
|
159
|
+
return next();
|
|
160
|
+
}
|
|
161
|
+
resource.roles.slice(roleIndex, 1);
|
|
162
|
+
break;
|
|
163
|
+
}
|
|
164
|
+
debug('Updating user with roles', resource.roles);
|
|
165
|
+
// Update the user.
|
|
166
|
+
yield scope.db.update(scope, resource._id, resource, ['roles']);
|
|
167
|
+
next();
|
|
168
|
+
});
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
};
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { ActionScope } from '../../types/action';
|
|
2
|
+
import { SubmissionRequest, SubmissionResponse } from '../../types/submission';
|
|
3
|
+
import { NextFunction } from 'express';
|
|
4
|
+
export declare const SaveAction: {
|
|
5
|
+
readonly info: {
|
|
6
|
+
name: string;
|
|
7
|
+
title: string;
|
|
8
|
+
description: string;
|
|
9
|
+
priority: number;
|
|
10
|
+
defaults: {
|
|
11
|
+
handler: string[];
|
|
12
|
+
method: string[];
|
|
13
|
+
};
|
|
14
|
+
access: {
|
|
15
|
+
handler: boolean;
|
|
16
|
+
method: boolean;
|
|
17
|
+
};
|
|
18
|
+
};
|
|
19
|
+
mappingComponents(scope: ActionScope): Promise<any>;
|
|
20
|
+
/**
|
|
21
|
+
* The settings form for this action.
|
|
22
|
+
* @param {*} scope
|
|
23
|
+
*/
|
|
24
|
+
settingsForm(scope: ActionScope): Promise<any>;
|
|
25
|
+
saveToForm(scope: ActionScope, resource: string): undefined;
|
|
26
|
+
childSubmission(scope: ActionScope, req: SubmissionRequest, res: SubmissionResponse, submission: any): any;
|
|
27
|
+
childResponse(scope: ActionScope, req: SubmissionRequest, res: SubmissionResponse): void;
|
|
28
|
+
executor(scope: ActionScope): Promise<(req: SubmissionRequest, res: SubmissionResponse, next: NextFunction) => Promise<void>>;
|
|
29
|
+
};
|
|
@@ -0,0 +1,307 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
12
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
13
|
+
};
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
exports.SaveAction = void 0;
|
|
16
|
+
const each_1 = __importDefault(require("lodash/each"));
|
|
17
|
+
const set_1 = __importDefault(require("lodash/set"));
|
|
18
|
+
const has_1 = __importDefault(require("lodash/has"));
|
|
19
|
+
const get_1 = __importDefault(require("lodash/get"));
|
|
20
|
+
const async_1 = __importDefault(require("async"));
|
|
21
|
+
const debug = require('debug')('formio:actions:save');
|
|
22
|
+
const error = require('debug')('formio:error');
|
|
23
|
+
exports.SaveAction = {
|
|
24
|
+
// The action information.
|
|
25
|
+
get info() {
|
|
26
|
+
return {
|
|
27
|
+
name: 'save',
|
|
28
|
+
title: 'Save Submission',
|
|
29
|
+
description: 'Saves the submission into the database.',
|
|
30
|
+
priority: 10,
|
|
31
|
+
defaults: {
|
|
32
|
+
handler: ['before'],
|
|
33
|
+
method: ['create', 'update']
|
|
34
|
+
},
|
|
35
|
+
access: {
|
|
36
|
+
handler: false,
|
|
37
|
+
method: false
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
},
|
|
41
|
+
mappingComponents(scope) {
|
|
42
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
43
|
+
const components = [
|
|
44
|
+
{
|
|
45
|
+
type: 'select',
|
|
46
|
+
key: 'mapType',
|
|
47
|
+
label: 'Request Mapping Type',
|
|
48
|
+
persist: 'client-only',
|
|
49
|
+
defaultValue: 'simple',
|
|
50
|
+
dataSrc: 'values',
|
|
51
|
+
data: {
|
|
52
|
+
values: [
|
|
53
|
+
{ label: 'Simple', value: 'simple' },
|
|
54
|
+
{ label: 'Advanced', value: 'advanced' }
|
|
55
|
+
]
|
|
56
|
+
}
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
type: 'panel',
|
|
60
|
+
title: 'Advanced Request Mapping',
|
|
61
|
+
key: 'requestMappingPanel',
|
|
62
|
+
customConditional: `show = row.mapType === 'advanced'`,
|
|
63
|
+
components: [
|
|
64
|
+
{
|
|
65
|
+
input: true,
|
|
66
|
+
label: "Request Mapping",
|
|
67
|
+
key: "mapping",
|
|
68
|
+
placeholder: "/** Example Code **/\nbody = submission;",
|
|
69
|
+
rows: 8,
|
|
70
|
+
defaultValue: "",
|
|
71
|
+
persistent: true,
|
|
72
|
+
editor: "ace",
|
|
73
|
+
type: "textarea",
|
|
74
|
+
description: "Manually perform a mapping of the request being made to the child resource. The 'body' is the req.body sent to the resource. You can use any standard evaluation context variables (form, submission, etc)."
|
|
75
|
+
}
|
|
76
|
+
]
|
|
77
|
+
}
|
|
78
|
+
];
|
|
79
|
+
for (let key in scope.template.resources) {
|
|
80
|
+
const form = scope.template.resources[key];
|
|
81
|
+
const mappings = {
|
|
82
|
+
title: 'Simple Mappings',
|
|
83
|
+
label: 'Simple Mappings',
|
|
84
|
+
collapsible: false,
|
|
85
|
+
key: 'mappings',
|
|
86
|
+
type: 'panel',
|
|
87
|
+
customConditional: `show = row.mapType === 'simple' && row.resource === "${key}"`,
|
|
88
|
+
components: []
|
|
89
|
+
};
|
|
90
|
+
const toFields = [];
|
|
91
|
+
yield scope.utils.eachComponent(form.components, (component) => {
|
|
92
|
+
if (['button'].indexOf(component.type) !== -1) {
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
toFields.push({ label: component.label || component.key, value: component.key });
|
|
96
|
+
});
|
|
97
|
+
yield scope.utils.eachComponent(scope.form.components, (component) => {
|
|
98
|
+
if (['button'].indexOf(component.type) !== -1) {
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
mappings.components.push({
|
|
102
|
+
type: 'select',
|
|
103
|
+
key: `fields.${component.key}`,
|
|
104
|
+
label: component.label,
|
|
105
|
+
valueProperty: 'value',
|
|
106
|
+
dataSrc: 'json',
|
|
107
|
+
data: { json: toFields }
|
|
108
|
+
});
|
|
109
|
+
});
|
|
110
|
+
components.push(mappings);
|
|
111
|
+
}
|
|
112
|
+
return components;
|
|
113
|
+
});
|
|
114
|
+
},
|
|
115
|
+
/**
|
|
116
|
+
* The settings form for this action.
|
|
117
|
+
* @param {*} scope
|
|
118
|
+
*/
|
|
119
|
+
settingsForm(scope) {
|
|
120
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
121
|
+
const resources = [];
|
|
122
|
+
for (let name in scope.template.resources) {
|
|
123
|
+
resources.push({
|
|
124
|
+
label: scope.template.resources[name].title,
|
|
125
|
+
value: name
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
return [
|
|
129
|
+
{
|
|
130
|
+
type: 'select',
|
|
131
|
+
key: 'resource',
|
|
132
|
+
label: 'Save submission to',
|
|
133
|
+
placeholder: 'This form',
|
|
134
|
+
valueProperty: 'value',
|
|
135
|
+
dataSrc: 'json',
|
|
136
|
+
data: {
|
|
137
|
+
json: resources
|
|
138
|
+
},
|
|
139
|
+
required: false
|
|
140
|
+
},
|
|
141
|
+
{
|
|
142
|
+
type: 'textfield',
|
|
143
|
+
key: 'property',
|
|
144
|
+
label: 'Resource Property',
|
|
145
|
+
placeholder: 'Assign this resource to the following property',
|
|
146
|
+
customConditional: 'show = row.resource'
|
|
147
|
+
},
|
|
148
|
+
{
|
|
149
|
+
legend: 'Resource Fields',
|
|
150
|
+
key: 'resourceFields',
|
|
151
|
+
type: 'fieldset',
|
|
152
|
+
label: 'Resource Fields',
|
|
153
|
+
customConditional: 'show = row.resource',
|
|
154
|
+
components: [
|
|
155
|
+
{
|
|
156
|
+
label: 'Summary',
|
|
157
|
+
key: 'summary',
|
|
158
|
+
type: 'well',
|
|
159
|
+
hideLabel: true,
|
|
160
|
+
components: [
|
|
161
|
+
{
|
|
162
|
+
label: 'HTML',
|
|
163
|
+
content: 'Below are the fields within the selected resource. For each of these fields, select the corresponding field within this form that you wish to map to the selected Resource. Simple mappings may be used for any component that is not nested within a container, editgrid, datagrid or other nested data component.',
|
|
164
|
+
refreshOnChange: false,
|
|
165
|
+
attrs: [{ attr: 'style', value: 'margin: 0' }],
|
|
166
|
+
key: 'html',
|
|
167
|
+
type: 'htmlelement'
|
|
168
|
+
}
|
|
169
|
+
]
|
|
170
|
+
}
|
|
171
|
+
].concat(yield exports.SaveAction.mappingComponents(scope))
|
|
172
|
+
},
|
|
173
|
+
{
|
|
174
|
+
type: 'panel',
|
|
175
|
+
title: 'Transform Mappings',
|
|
176
|
+
key: 'transformPanel',
|
|
177
|
+
components: [
|
|
178
|
+
{
|
|
179
|
+
input: true,
|
|
180
|
+
label: "Transform Data",
|
|
181
|
+
key: "transform",
|
|
182
|
+
placeholder: "/** Example Code **/\ndata = submission.data;",
|
|
183
|
+
rows: 8,
|
|
184
|
+
defaultValue: "",
|
|
185
|
+
persistent: true,
|
|
186
|
+
editor: "ace",
|
|
187
|
+
type: "textarea",
|
|
188
|
+
description: "Available variables are submission and data (data is already transformed by simple mappings)."
|
|
189
|
+
}
|
|
190
|
+
]
|
|
191
|
+
}
|
|
192
|
+
];
|
|
193
|
+
});
|
|
194
|
+
},
|
|
195
|
+
saveToForm(scope, resource) {
|
|
196
|
+
let saveTo;
|
|
197
|
+
(0, each_1.default)(scope.template.resources, (form) => {
|
|
198
|
+
if (form.key === resource) {
|
|
199
|
+
saveTo = form;
|
|
200
|
+
return false;
|
|
201
|
+
}
|
|
202
|
+
});
|
|
203
|
+
if (!saveTo) {
|
|
204
|
+
(0, each_1.default)(scope.template.forms, (form) => {
|
|
205
|
+
if (form.key === resource) {
|
|
206
|
+
saveTo = form;
|
|
207
|
+
return false;
|
|
208
|
+
}
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
return saveTo;
|
|
212
|
+
},
|
|
213
|
+
// Create a child submission.
|
|
214
|
+
childSubmission(scope, req, res, submission) {
|
|
215
|
+
const { action } = scope;
|
|
216
|
+
let childSub = { data: {} };
|
|
217
|
+
if (action.settings.mapping) {
|
|
218
|
+
try {
|
|
219
|
+
childSub = scope.utils.evaluate(action.settings.mapping, scope.utils.evalContext(Object.assign(Object.assign({}, scope), { body: req.body }), req, res), 'body');
|
|
220
|
+
}
|
|
221
|
+
catch (err) {
|
|
222
|
+
console.log(`Error in mapping transform: ${err.message}`);
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
else {
|
|
226
|
+
(0, each_1.default)(action.settings.fields, function (field, key) {
|
|
227
|
+
if (field === 'data') {
|
|
228
|
+
(0, set_1.default)(childSub.data, key, submission.data);
|
|
229
|
+
}
|
|
230
|
+
else if ((0, has_1.default)(submission.data, field)) {
|
|
231
|
+
(0, set_1.default)(childSub.data, key, (0, get_1.default)(submission.data, field));
|
|
232
|
+
}
|
|
233
|
+
});
|
|
234
|
+
}
|
|
235
|
+
childSub.metadata = submission.metadata;
|
|
236
|
+
if (action.settings.transform) {
|
|
237
|
+
try {
|
|
238
|
+
childSub.data = scope.utils.evaluate(action.settings.transform, scope.utils.evalContext(scope, req, res), 'data');
|
|
239
|
+
}
|
|
240
|
+
catch (err) {
|
|
241
|
+
console.log(`Error in submission transform: ${err.message}`);
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
return childSub;
|
|
245
|
+
},
|
|
246
|
+
// Set the child response
|
|
247
|
+
childResponse(scope, req, res) {
|
|
248
|
+
var _a, _b;
|
|
249
|
+
const { action } = scope;
|
|
250
|
+
if ((_a = res.resource) === null || _a === void 0 ? void 0 : _a.item) {
|
|
251
|
+
// Set the action in the property.
|
|
252
|
+
if ((_b = action.settings) === null || _b === void 0 ? void 0 : _b.property) {
|
|
253
|
+
(0, set_1.default)(req.body.data, action.settings.property, res.resource.item);
|
|
254
|
+
}
|
|
255
|
+
// Save the reference in the external ids.
|
|
256
|
+
if (req.method === 'POST' && res.resource.item._id) {
|
|
257
|
+
// Save the external resource in the external ids.
|
|
258
|
+
req.body.externalIds = req.body.externalIds || [];
|
|
259
|
+
req.body.externalIds.push({
|
|
260
|
+
type: 'resource',
|
|
261
|
+
resource: action.settings.resource,
|
|
262
|
+
id: res.resource.item._id.toString()
|
|
263
|
+
});
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
},
|
|
267
|
+
executor(scope) {
|
|
268
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
269
|
+
const action = scope.action;
|
|
270
|
+
return (req, res, next) => __awaiter(this, void 0, void 0, function* () {
|
|
271
|
+
var _a;
|
|
272
|
+
debug('Save Action');
|
|
273
|
+
if (req.skipSave || !req.body || (req.method !== 'POST' && req.method !== 'PUT')) {
|
|
274
|
+
debug('Skipping save action');
|
|
275
|
+
return next();
|
|
276
|
+
}
|
|
277
|
+
// If this is saving to another resource, then we need to use those handlers instead.
|
|
278
|
+
if ((_a = action.settings) === null || _a === void 0 ? void 0 : _a.resource) {
|
|
279
|
+
debug('Saving to resource: ' + action.settings.resource);
|
|
280
|
+
const saveTo = exports.SaveAction.saveToForm(scope, action.settings.resource);
|
|
281
|
+
if (saveTo) {
|
|
282
|
+
if (!saveTo.handlers) {
|
|
283
|
+
error('Cannot find resource handlers.');
|
|
284
|
+
return next('Cannot find resource handlers.');
|
|
285
|
+
}
|
|
286
|
+
const handlers = req.method === 'PUT' ? saveTo.handlers.update : saveTo.handlers.create;
|
|
287
|
+
const childReq = scope.utils.childRequest(req);
|
|
288
|
+
childReq.body = exports.SaveAction.childSubmission(scope, req, res, childReq.body);
|
|
289
|
+
return async_1.default.series(handlers.map((handler) => async_1.default.apply(handler, childReq, res)), (err) => {
|
|
290
|
+
if (err) {
|
|
291
|
+
error(err);
|
|
292
|
+
return next(err);
|
|
293
|
+
}
|
|
294
|
+
// Set the child response based on the response of the subform.
|
|
295
|
+
exports.SaveAction.childResponse(scope, req, res);
|
|
296
|
+
next();
|
|
297
|
+
});
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
// Save the submission.
|
|
301
|
+
req.scope.saveSubmission = true;
|
|
302
|
+
debug('Saving submission');
|
|
303
|
+
return next();
|
|
304
|
+
});
|
|
305
|
+
});
|
|
306
|
+
}
|
|
307
|
+
};
|
package/lib/auth.d.ts
ADDED
package/lib/auth.js
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
12
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
13
|
+
};
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
exports.Auth = void 0;
|
|
16
|
+
const jsonwebtoken_1 = __importDefault(require("jsonwebtoken"));
|
|
17
|
+
const debug = require('debug')('formio:auth');
|
|
18
|
+
const error = require('debug')('formio:error');
|
|
19
|
+
class Auth {
|
|
20
|
+
token(user, secret, expire = 240) {
|
|
21
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
22
|
+
user = Object.assign({}, user);
|
|
23
|
+
delete user.iat;
|
|
24
|
+
delete user.exp;
|
|
25
|
+
return new Promise((resolve, reject) => {
|
|
26
|
+
if (!secret) {
|
|
27
|
+
return reject(new Error('You cannot generate a token without a secret!'));
|
|
28
|
+
}
|
|
29
|
+
debug('auth.token()', user);
|
|
30
|
+
jsonwebtoken_1.default.sign(user, secret, {
|
|
31
|
+
expiresIn: expire * 60,
|
|
32
|
+
}, (err, signed) => {
|
|
33
|
+
if (err) {
|
|
34
|
+
error(err);
|
|
35
|
+
return reject(err);
|
|
36
|
+
}
|
|
37
|
+
resolve(signed || '');
|
|
38
|
+
});
|
|
39
|
+
});
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
user(token, secret) {
|
|
43
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
44
|
+
if (!token) {
|
|
45
|
+
return Promise.resolve(null);
|
|
46
|
+
}
|
|
47
|
+
return new Promise((resolve, reject) => {
|
|
48
|
+
if (!secret) {
|
|
49
|
+
return reject('You cannot authenticate without a JWT Secret!');
|
|
50
|
+
}
|
|
51
|
+
debug('auth.verify()', token);
|
|
52
|
+
jsonwebtoken_1.default.verify(token, secret, (err, payload) => {
|
|
53
|
+
if (err) {
|
|
54
|
+
error(err);
|
|
55
|
+
if (err.name === 'JsonWebTokenError') {
|
|
56
|
+
return reject({ message: 'Bad Token' });
|
|
57
|
+
}
|
|
58
|
+
if (err.name === 'TokenExpiredError') {
|
|
59
|
+
return reject({ message: 'Token Expired' });
|
|
60
|
+
}
|
|
61
|
+
return reject(err);
|
|
62
|
+
}
|
|
63
|
+
debug('auth.user()', payload);
|
|
64
|
+
resolve(payload);
|
|
65
|
+
});
|
|
66
|
+
});
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
exports.Auth = Auth;
|
package/lib/db.d.ts
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { Collection, Db } from 'mongodb';
|
|
2
|
+
import { DBConfig, ServerDB } from './types/server';
|
|
3
|
+
import { FormScope } from './types/form';
|
|
4
|
+
export declare class Database implements ServerDB {
|
|
5
|
+
config: DBConfig;
|
|
6
|
+
db: Db | null;
|
|
7
|
+
currentCollectionName: string;
|
|
8
|
+
currentCollection: Collection<Document> | null;
|
|
9
|
+
defaultCollection: Collection<Document> | null;
|
|
10
|
+
constructor(config: DBConfig);
|
|
11
|
+
ObjectId(id: any): any;
|
|
12
|
+
/**
|
|
13
|
+
* Connect to the database.
|
|
14
|
+
* @param {*} scope
|
|
15
|
+
* @returns
|
|
16
|
+
*/
|
|
17
|
+
connect(): Promise<void>;
|
|
18
|
+
save(collectionName: string, item: any): Promise<import("mongodb").WithId<import("bson").Document> | null>;
|
|
19
|
+
load(collectionName: string): Promise<import("mongodb").WithId<import("bson").Document> | null | undefined>;
|
|
20
|
+
collection(scope: FormScope): Promise<Collection<Document> | null>;
|
|
21
|
+
/**
|
|
22
|
+
* Setup indexes.
|
|
23
|
+
*/
|
|
24
|
+
setupIndexes(collection: Collection<Document> | null, scope?: FormScope): Promise<void>;
|
|
25
|
+
/**
|
|
26
|
+
* Add a field index
|
|
27
|
+
*/
|
|
28
|
+
addIndex(collection: Collection<Document>, path: string): Promise<void>;
|
|
29
|
+
/**
|
|
30
|
+
* Remove a field index.
|
|
31
|
+
*/
|
|
32
|
+
removeIndex(collection: Collection<Document>, path: string): Promise<void>;
|
|
33
|
+
/**
|
|
34
|
+
* Fetch a list of submissions from a table/collection.
|
|
35
|
+
* @param {*} table
|
|
36
|
+
* @param {*} query
|
|
37
|
+
*/
|
|
38
|
+
index(scope: FormScope, query?: {}): Promise<import("mongodb").WithId<Document>[] | undefined>;
|
|
39
|
+
/**
|
|
40
|
+
* Create a new record.
|
|
41
|
+
*/
|
|
42
|
+
create(scope: FormScope, record: any, allowFields?: string[]): Promise<import("mongodb").WithId<Document> | null | undefined>;
|
|
43
|
+
/**
|
|
44
|
+
* Return a query for a single mongo record.
|
|
45
|
+
* @param {*} form
|
|
46
|
+
* @param {*} id
|
|
47
|
+
* @returns
|
|
48
|
+
*/
|
|
49
|
+
query(scope: FormScope, query?: any): any;
|
|
50
|
+
/**
|
|
51
|
+
* Find many records that match a query.
|
|
52
|
+
*/
|
|
53
|
+
find(scope: FormScope, query?: any): Promise<import("mongodb").WithId<Document>[]>;
|
|
54
|
+
/**
|
|
55
|
+
* Find a record for a provided query.
|
|
56
|
+
*/
|
|
57
|
+
findOne(scope: FormScope, query?: any): Promise<import("mongodb").WithId<Document> | null>;
|
|
58
|
+
/**
|
|
59
|
+
* Read a single submission from a form
|
|
60
|
+
*
|
|
61
|
+
* @param {*} table
|
|
62
|
+
* @param {*} query
|
|
63
|
+
*/
|
|
64
|
+
read(scope: FormScope, id: string): Promise<import("mongodb").WithId<Document> | null>;
|
|
65
|
+
/**
|
|
66
|
+
* Update a single submission of a form.
|
|
67
|
+
*
|
|
68
|
+
* @param {*} table
|
|
69
|
+
* @param {*} query
|
|
70
|
+
*/
|
|
71
|
+
update(scope: FormScope, id: string, update: any, allowFields?: string[]): Promise<import("mongodb").WithId<Document> | null>;
|
|
72
|
+
/**
|
|
73
|
+
* Delete a record from the database.
|
|
74
|
+
*/
|
|
75
|
+
delete(scope: FormScope, id: string): Promise<boolean>;
|
|
76
|
+
}
|