@izara_project/izara-core-generate-service-code 1.0.98 → 1.0.100
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/package.json +1 -1
- package/src/compile/compileProject.js +16 -5
- package/src/compile/flowValidator.js +47 -8
- package/src/compile/loadSchemas.js +18 -7
- package/src/compile/schemaValidatorSetup.js +16 -0
- package/src/emit/application/coreFunction/emitCoreFunctionArtifacts.js +123 -109
- package/src/emit/application/coreFunction/templates/InitialSetupConfig.ejs +8 -4
- package/src/emit/application/coreFunction/templates/InitialSetupRunner.ejs +2 -2
- package/src/emit/application/crud/templates/CreateComplete_Main.ejs +2 -0
- package/src/emit/application/crud/templates/CreateEndpoint_Main.ejs +4 -4
- package/src/emit/application/crud/templates/CreateLogicalLib.ejs +74 -15
- package/src/emit/application/crud/templates/DeleteComplete_Main.ejs +2 -0
- package/src/emit/application/crud/templates/DeleteEndpoint_Main.ejs +4 -4
- package/src/emit/application/crud/templates/FlowEndpoint_HdrWbs.ejs +7 -5
- package/src/emit/application/crud/templates/UpdateComplete_Main.ejs +2 -0
- package/src/emit/application/crud/templates/UpdateEndpoint_Main.ejs +4 -4
- package/src/emit/application/custom/customFlowPaths.js +13 -16
- package/src/emit/application/custom/customFlowS3.js +277 -66
- package/src/emit/application/custom/customFlows.js +131 -0
- package/src/emit/application/custom/emitCustomFlowApplicationArtifacts.js +3 -1
- package/src/emit/application/custom/templates/FlowEndpoint_Main.ejs +2 -2
- package/src/emit/application/custom/templates/s3/ConfirmAfterUpload_HdrSqs.ejs +110 -0
- package/src/emit/application/custom/templates/s3/ConfirmAfterUpload_Main.ejs +89 -0
- package/src/emit/application/custom/templates/s3/ConfirmComplete_HdrSqs.ejs +110 -0
- package/src/emit/application/custom/templates/s3/ConfirmComplete_Main.ejs +89 -0
- package/src/emit/application/custom/templates/s3/CreateObject_HdrWbs.ejs +2 -1
- package/src/emit/application/custom/templates/s3/CreateObject_Main.ejs +4 -0
- package/src/emit/application/custom/templates/s3/CreatePreSignUrl_HdrSqs.ejs +42 -0
- package/src/emit/application/custom/templates/s3/CreatePreSignUrl_Main.ejs +23 -0
- package/src/emit/application/custom/templates/s3/ProcessS3File_Main.ejs +135 -27
- package/src/emit/application/custom/templates/s3/Start_Main.ejs +197 -0
- package/src/emit/application/rbac/emitDynamicRbacFlowSchemas.js +8 -1
- package/src/emit/application/rbac/emitRbacApplicationArtifacts.js +107 -25
- package/src/emit/application/rbac/templates/ReservedDynamicUsage_Main.ejs +29 -9
- package/src/emit/application/rbac/templates/ReservedUsageTtlExpired_HdrDss.ejs +176 -0
- package/src/emit/application/rbac/templates/UserRbacFlow_Main.ejs +4 -3
- package/src/emit/application/system/templates/Register_HdrWbs.ejs +2 -1
- package/src/emit/infrastructure/functions/functionYamlArtifact.js +31 -8
- package/src/emit/infrastructure/functions/templates/DssFunction_Yaml.ejs +21 -0
- package/src/emit/infrastructure/functions/templates/S3Function_Yaml.ejs +2 -3
- package/src/emit/infrastructure/resources/iamResourceArtifacts.js +67 -5
- package/src/emit/infrastructure/resources/resourceState.js +15 -5
- package/src/emit/infrastructure/resources/s3ResourceArtifacts.js +19 -3
- package/src/emit/infrastructure/resources/templates/GeneratedLambdaRoleServiceConfig.ejs +5 -3
- package/src/emit/infrastructure/resources/templates/S3Bucket_Yaml.ejs +1 -1
- package/src/emit/infrastructure/resources/templates/SystemDynamoDB_Yaml.ejs +2 -2
- package/src/emit/schemas/attributeTree/emitAttributeTreeSchemas.js +62 -1
- package/src/emit/schemas/error/emitErrorSchemas.js +120 -10
- package/src/emit/schemas/error/templates/errorConsts.ejs +12 -0
- package/src/generate.js +32 -34
- package/src/output/mergeHooks.js +105 -5
- package/src/plan/domainRegistry.js +0 -10
- package/task.md +40 -96
- package/test/integration/graphDrivenFlowSchema.test.js +58 -0
- package/test/integration/publicApi.test.js +33 -24
- package/test/unit/application/createTargetRoleHandler.test.js +101 -9
- package/test/unit/application/crudApplicationArtifacts.test.js +4 -0
- package/test/unit/application/customFlowApplicationArtifacts.test.js +6 -6
- package/test/unit/application/customFlowS3.test.js +730 -0
- package/test/unit/infrastructure/functionYamlArtifact.test.js +6 -4
- package/test/unit/infrastructure/resourceArtifacts.test.js +103 -0
- package/test/unit/output/mergeHooks.test.js +137 -0
- package/test/unit/schemas/attributeTreeSchemas.test.js +32 -3
- package/test/unit/schemas/attributeTreeSingleService.test.js +175 -0
- package/test/unit/schemas/dynamicRbacFlowSchemas.test.js +8 -6
- package/test/unit/schemas/dynamicRelationshipFlowSchemas.test.js +51 -0
- package/test/unit/schemas/errorSchemas.test.js +84 -5
- package/test/unit/templates/hookTagsValidation.test.js +83 -0
- package/src/emit/schemas/attributeTree/emitAttributeTreeTargetValueStandard.js +0 -132
- package/test/unit/schemas/attributeTreeDirectives.test.js +0 -177
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
import { renderCustom } from './customFlowTemplates.js';
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
customFlowRoleName,
|
|
4
|
+
upperFirst,
|
|
5
|
+
resolveS3Parts,
|
|
6
|
+
flowHasRbac
|
|
7
|
+
} from './customFlows.js';
|
|
3
8
|
import {
|
|
4
9
|
renderInvFunctionYaml,
|
|
5
10
|
renderS3FunctionYaml,
|
|
@@ -7,63 +12,81 @@ import {
|
|
|
7
12
|
renderWbsFunctionYaml
|
|
8
13
|
} from '../../infrastructure/functions/functionYamlArtifact.js';
|
|
9
14
|
|
|
10
|
-
export
|
|
15
|
+
export function isSimplifiedS3Flow(flow) {
|
|
16
|
+
if (!Array.isArray(flow?.flowSteps) || flow.flowSteps.length === 0) {
|
|
17
|
+
return false;
|
|
18
|
+
}
|
|
19
|
+
const stepNames = flow.flowSteps.map((s) => s.stepName);
|
|
20
|
+
if (stepNames.includes('ReservedLimit')) {
|
|
21
|
+
return false;
|
|
22
|
+
}
|
|
23
|
+
return true;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export async function emitS3Flow(
|
|
27
|
+
flow,
|
|
28
|
+
source,
|
|
29
|
+
handlerRoot,
|
|
30
|
+
{ objects = [] } = {}
|
|
31
|
+
) {
|
|
11
32
|
const tag = upperFirst(flow.flowTag);
|
|
12
33
|
const roleName = customFlowRoleName(flow.flowTag);
|
|
13
|
-
const parts =
|
|
14
|
-
|
|
15
|
-
action: 'CreateObject',
|
|
16
|
-
handler: 'HdrWbs',
|
|
17
|
-
type: 'wbs',
|
|
18
|
-
mainTemplate: 'CreateObject_Main.ejs',
|
|
19
|
-
handlerTemplate: 'CreateObject_HdrWbs.ejs'
|
|
20
|
-
},
|
|
21
|
-
{
|
|
22
|
-
action: 'ReservedLimit',
|
|
23
|
-
handler: 'HdrSqs',
|
|
24
|
-
type: 'sqs',
|
|
25
|
-
mainTemplate: 'ReservedLimit_Main.ejs',
|
|
26
|
-
handlerTemplate: 'ReservedLimit_HdrSqs.ejs'
|
|
27
|
-
},
|
|
28
|
-
{
|
|
29
|
-
action: 'CreatePreSignUrl',
|
|
30
|
-
handler: 'HdrSqs',
|
|
31
|
-
type: 'sqs',
|
|
32
|
-
mainTemplate: 'CreatePreSignUrl_Main.ejs',
|
|
33
|
-
handlerTemplate: 'CreatePreSignUrl_HdrSqs.ejs'
|
|
34
|
-
},
|
|
35
|
-
{
|
|
36
|
-
action: 'ProcessAfterUpload',
|
|
37
|
-
handler: 'HdrS3',
|
|
38
|
-
type: 's3',
|
|
39
|
-
mainTemplate: 'ProcessS3File_Main.ejs',
|
|
40
|
-
handlerTemplate: 'FlowHandler_HdrS3.ejs'
|
|
41
|
-
},
|
|
42
|
-
{
|
|
43
|
-
action: 'ConfirmAfterUpload',
|
|
44
|
-
handler: 'HdrSqs',
|
|
45
|
-
type: 'sqs',
|
|
46
|
-
mainTemplate: 'ConfirmReserved_Main.ejs',
|
|
47
|
-
handlerTemplate: 'ConfirmReserved_HdrSqs.ejs'
|
|
48
|
-
}
|
|
49
|
-
];
|
|
34
|
+
const parts = resolveS3Parts(flow);
|
|
35
|
+
const isSimplifiedS3 = isSimplifiedS3Flow(flow);
|
|
50
36
|
|
|
51
37
|
const emitted = await Promise.all(
|
|
52
38
|
parts.map(
|
|
53
|
-
async (
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
39
|
+
async (
|
|
40
|
+
{ action, handler, type, mainTemplate, handlerTemplate },
|
|
41
|
+
index
|
|
42
|
+
) => {
|
|
43
|
+
let isStart = false;
|
|
44
|
+
if (typeof action === 'string' && action.toLowerCase() === 'start') {
|
|
45
|
+
isStart = true;
|
|
46
|
+
}
|
|
47
|
+
let functionName = `${tag}${action}`;
|
|
48
|
+
let mainFileName = `${functionName}_Main`;
|
|
49
|
+
let handlerFileName = `${functionName}_${handler}`;
|
|
50
|
+
let slsFunctionName = `${functionName}${handler}`;
|
|
51
|
+
let flowStepName = action;
|
|
52
|
+
if (isStart) {
|
|
53
|
+
functionName = tag;
|
|
54
|
+
mainFileName = `${tag}_Main`;
|
|
55
|
+
handlerFileName = `${tag}_${handler}`;
|
|
56
|
+
slsFunctionName = `${tag}${handler}`;
|
|
57
|
+
flowStepName = '';
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const nextPart = parts.find((p, i) => i > index && p.type === 'sqs');
|
|
61
|
+
let nextStepFunctionName = null;
|
|
62
|
+
if (nextPart) {
|
|
63
|
+
nextStepFunctionName = `${tag}${nextPart.action}${nextPart.handler}`;
|
|
64
|
+
}
|
|
65
|
+
|
|
57
66
|
const mainContent = await renderCustom(
|
|
58
67
|
`s3/${mainTemplate}`,
|
|
59
|
-
_s3TemplateData({
|
|
68
|
+
_s3TemplateData({
|
|
69
|
+
action,
|
|
70
|
+
flow,
|
|
71
|
+
functionName,
|
|
72
|
+
nextStepFunctionName,
|
|
73
|
+
isSimplifiedS3,
|
|
74
|
+
objects
|
|
75
|
+
})
|
|
60
76
|
);
|
|
61
77
|
const handlerContent = await renderCustom(
|
|
62
78
|
`s3/${handlerTemplate}`,
|
|
63
|
-
_s3HandlerData({
|
|
79
|
+
_s3HandlerData({
|
|
80
|
+
action,
|
|
81
|
+
flow,
|
|
82
|
+
functionName,
|
|
83
|
+
mainFileName,
|
|
84
|
+
handler,
|
|
85
|
+
isSimplifiedS3
|
|
86
|
+
})
|
|
64
87
|
);
|
|
65
88
|
const descriptor = {
|
|
66
|
-
functionName:
|
|
89
|
+
functionName: slsFunctionName,
|
|
67
90
|
handlerPath: `${handlerRoot}/${handlerFileName}.main`,
|
|
68
91
|
roleName
|
|
69
92
|
};
|
|
@@ -73,18 +96,18 @@ export async function emitS3Flow(flow, source, handlerRoot) {
|
|
|
73
96
|
...descriptor,
|
|
74
97
|
routeName: tag,
|
|
75
98
|
flowTag: flow.flowTag,
|
|
76
|
-
flowStepName
|
|
99
|
+
flowStepName
|
|
77
100
|
});
|
|
78
101
|
} else if (type === 'sqs') {
|
|
79
102
|
let filterPatternFunctionName = descriptor.functionName;
|
|
80
|
-
if (action === 'CreatePreSignUrl') {
|
|
103
|
+
if (!isSimplifiedS3 && action === 'CreatePreSignUrl') {
|
|
81
104
|
filterPatternFunctionName = 'CreatePresignUrlHdrSqs';
|
|
82
105
|
}
|
|
83
106
|
functionYaml = renderSqsFunctionYaml({
|
|
84
107
|
...descriptor,
|
|
85
108
|
queueName: descriptor.functionName,
|
|
86
109
|
flowTag: flow.flowTag,
|
|
87
|
-
flowStepName:
|
|
110
|
+
flowStepName: action,
|
|
88
111
|
filterPatternFunctionName
|
|
89
112
|
});
|
|
90
113
|
} else if (type === 's3') {
|
|
@@ -100,14 +123,15 @@ export async function emitS3Flow(flow, source, handlerRoot) {
|
|
|
100
123
|
functionYaml = renderS3FunctionYaml({
|
|
101
124
|
...descriptor,
|
|
102
125
|
bucketName: flow.bucketName,
|
|
126
|
+
s3KeyPrefix: flow.s3KeyPrefix,
|
|
103
127
|
flowTag: flow.flowTag,
|
|
104
|
-
flowStepName:
|
|
128
|
+
flowStepName: action
|
|
105
129
|
});
|
|
106
130
|
} else {
|
|
107
131
|
functionYaml = renderInvFunctionYaml({
|
|
108
132
|
...descriptor,
|
|
109
133
|
flowTag: flow.flowTag,
|
|
110
|
-
flowStepName:
|
|
134
|
+
flowStepName: action
|
|
111
135
|
});
|
|
112
136
|
}
|
|
113
137
|
return {
|
|
@@ -127,23 +151,209 @@ export async function emitS3Flow(flow, source, handlerRoot) {
|
|
|
127
151
|
};
|
|
128
152
|
}
|
|
129
153
|
|
|
130
|
-
function
|
|
131
|
-
if (
|
|
132
|
-
return
|
|
133
|
-
flowTag: flow.flowTag,
|
|
134
|
-
objectType: flow.objType?.objectType,
|
|
135
|
-
functionName
|
|
136
|
-
};
|
|
154
|
+
export function extractIdentifierFieldNames(identifiers) {
|
|
155
|
+
if (!Array.isArray(identifiers) || identifiers.length === 0) {
|
|
156
|
+
return [];
|
|
137
157
|
}
|
|
138
|
-
|
|
139
|
-
|
|
158
|
+
const keys = [];
|
|
159
|
+
for (const item of identifiers) {
|
|
160
|
+
if (typeof item === 'string') {
|
|
161
|
+
if (item && !keys.includes(item)) {
|
|
162
|
+
keys.push(item);
|
|
163
|
+
}
|
|
164
|
+
} else if (item && typeof item === 'object') {
|
|
165
|
+
if (Array.isArray(item.fieldNames) && item.fieldNames.length > 0) {
|
|
166
|
+
for (const fn of item.fieldNames) {
|
|
167
|
+
if (typeof fn === 'string' && fn && !keys.includes(fn)) {
|
|
168
|
+
keys.push(fn);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
} else if (typeof item.fieldName === 'string' && item.fieldName) {
|
|
172
|
+
if (!keys.includes(item.fieldName)) {
|
|
173
|
+
keys.push(item.fieldName);
|
|
174
|
+
}
|
|
175
|
+
} else if (typeof item.name === 'string' && item.name) {
|
|
176
|
+
if (!keys.includes(item.name)) {
|
|
177
|
+
keys.push(item.name);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
}
|
|
140
181
|
}
|
|
141
|
-
return
|
|
182
|
+
return keys;
|
|
142
183
|
}
|
|
143
184
|
|
|
144
|
-
function
|
|
145
|
-
|
|
146
|
-
|
|
185
|
+
export function resolveParentIdentifierInfo(flow, objects = []) {
|
|
186
|
+
let parentObjectType = null;
|
|
187
|
+
let parentServiceTag = null;
|
|
188
|
+
const targetObjType =
|
|
189
|
+
typeof flow.objType === 'string'
|
|
190
|
+
? flow.objType
|
|
191
|
+
: flow.objType?.objectType || flow.objectType;
|
|
192
|
+
const matchedObject = (objects || []).find(
|
|
193
|
+
(o) => o.objectType === targetObjType
|
|
194
|
+
);
|
|
195
|
+
|
|
196
|
+
if (flow.parentObjectType) {
|
|
197
|
+
parentObjectType = flow.parentObjectType;
|
|
198
|
+
} else if (flow.belongTo?.objectType) {
|
|
199
|
+
parentObjectType = flow.belongTo.objectType;
|
|
200
|
+
parentServiceTag = flow.belongTo.serviceTag;
|
|
201
|
+
} else if (Array.isArray(flow.belongTo) && flow.belongTo[0]?.objectType) {
|
|
202
|
+
parentObjectType = flow.belongTo[0].objectType;
|
|
203
|
+
parentServiceTag = flow.belongTo[0].serviceTag;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
if (!parentObjectType && matchedObject?.belongTo) {
|
|
207
|
+
const belongTo = matchedObject.belongTo;
|
|
208
|
+
if (Array.isArray(belongTo) && belongTo[0]?.objectType) {
|
|
209
|
+
parentObjectType = belongTo[0].objectType;
|
|
210
|
+
parentServiceTag = belongTo[0].serviceTag;
|
|
211
|
+
} else if (belongTo.objectType) {
|
|
212
|
+
parentObjectType = belongTo.objectType;
|
|
213
|
+
parentServiceTag = belongTo.serviceTag;
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
const belongToDef = flow.belongTo || matchedObject?.belongTo;
|
|
218
|
+
const singleBelongTo = Array.isArray(belongToDef) ? belongToDef[0] : belongToDef;
|
|
219
|
+
|
|
220
|
+
let parentIdKeys = [];
|
|
221
|
+
if (Array.isArray(flow.parentIdentifierKeys) && flow.parentIdentifierKeys.length > 0) {
|
|
222
|
+
parentIdKeys = [...flow.parentIdentifierKeys];
|
|
223
|
+
} else if (flow.parentIdentifierKey) {
|
|
224
|
+
parentIdKeys = [flow.parentIdentifierKey];
|
|
225
|
+
} else if (
|
|
226
|
+
Array.isArray(singleBelongTo?.parentIdentifierKeys) &&
|
|
227
|
+
singleBelongTo.parentIdentifierKeys.length > 0
|
|
228
|
+
) {
|
|
229
|
+
parentIdKeys = [...singleBelongTo.parentIdentifierKeys];
|
|
230
|
+
} else if (
|
|
231
|
+
Array.isArray(singleBelongTo?.identifiers) &&
|
|
232
|
+
singleBelongTo.identifiers.length > 0
|
|
233
|
+
) {
|
|
234
|
+
parentIdKeys = extractIdentifierFieldNames(singleBelongTo.identifiers);
|
|
235
|
+
} else {
|
|
236
|
+
const parentObj =
|
|
237
|
+
Array.isArray(objects) && parentObjectType
|
|
238
|
+
? objects.find((o) => o.objectType === parentObjectType)
|
|
239
|
+
: null;
|
|
240
|
+
const parentIdentifiers =
|
|
241
|
+
parentObj?.identifiers || matchedObject?.belongToSchema?.identifiers;
|
|
242
|
+
if (Array.isArray(parentIdentifiers) && parentIdentifiers.length > 0) {
|
|
243
|
+
parentIdKeys = extractIdentifierFieldNames(parentIdentifiers);
|
|
244
|
+
}
|
|
245
|
+
if (parentIdKeys.length === 0 && parentObjectType) {
|
|
246
|
+
parentIdKeys = [`${parentObjectType}Id`];
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
let parentIdKey = null;
|
|
251
|
+
if (parentIdKeys.length > 0) {
|
|
252
|
+
parentIdKey = parentIdKeys[0];
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
return {
|
|
256
|
+
parentObjectType,
|
|
257
|
+
parentServiceTag,
|
|
258
|
+
parentIdKey,
|
|
259
|
+
parentIdKeys
|
|
260
|
+
};
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
function _s3TemplateData({
|
|
264
|
+
action,
|
|
265
|
+
flow,
|
|
266
|
+
functionName,
|
|
267
|
+
nextStepFunctionName,
|
|
268
|
+
isSimplifiedS3,
|
|
269
|
+
objects = []
|
|
270
|
+
}) {
|
|
271
|
+
let maxFileSizeMb = 50;
|
|
272
|
+
if (flow.maxFileSizeMb) {
|
|
273
|
+
maxFileSizeMb = flow.maxFileSizeMb;
|
|
274
|
+
}
|
|
275
|
+
let expires = 86400;
|
|
276
|
+
if (flow.expires) {
|
|
277
|
+
expires = flow.expires;
|
|
278
|
+
}
|
|
279
|
+
let contentTypePrefix = 'video/';
|
|
280
|
+
if (flow.contentTypePrefix) {
|
|
281
|
+
contentTypePrefix = flow.contentTypePrefix;
|
|
282
|
+
} else if (flow.contentType) {
|
|
283
|
+
contentTypePrefix = flow.contentType;
|
|
284
|
+
}
|
|
285
|
+
const { parentObjectType, parentServiceTag, parentIdKey, parentIdKeys } =
|
|
286
|
+
resolveParentIdentifierInfo(flow, objects);
|
|
287
|
+
let s3KeyPrefix = 'uploads/';
|
|
288
|
+
if (flow.s3KeyPrefix) {
|
|
289
|
+
s3KeyPrefix = flow.s3KeyPrefix;
|
|
290
|
+
}
|
|
291
|
+
let defaultImportType = 'bin';
|
|
292
|
+
if (flow.defaultImportType) {
|
|
293
|
+
defaultImportType = flow.defaultImportType;
|
|
294
|
+
} else if (flow.importType) {
|
|
295
|
+
defaultImportType = flow.importType;
|
|
296
|
+
} else if (typeof contentTypePrefix === 'string' && contentTypePrefix.startsWith('video/')) {
|
|
297
|
+
defaultImportType = 'mp4';
|
|
298
|
+
} else if (typeof contentTypePrefix === 'string' && contentTypePrefix.startsWith('image/')) {
|
|
299
|
+
defaultImportType = 'jpg';
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
let isRbac = false;
|
|
303
|
+
if (typeof flow.isRbac === 'boolean') {
|
|
304
|
+
isRbac = flow.isRbac;
|
|
305
|
+
} else if (flowHasRbac(flow, objects)) {
|
|
306
|
+
isRbac = true;
|
|
307
|
+
} else if (parentObjectType && parentServiceTag) {
|
|
308
|
+
isRbac = true;
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
let rbacServiceTag = parentServiceTag;
|
|
312
|
+
if (!rbacServiceTag) {
|
|
313
|
+
rbacServiceTag = flow.objType?.serviceTag || flow.serviceTag || 'Rbac';
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
return {
|
|
317
|
+
action,
|
|
318
|
+
flowTag: flow.flowTag,
|
|
319
|
+
objectType: flow.objType?.objectType,
|
|
320
|
+
functionName,
|
|
321
|
+
nextStepFunctionName,
|
|
322
|
+
isSimplifiedS3,
|
|
323
|
+
bucketName: flow.bucketName,
|
|
324
|
+
s3KeyPrefix,
|
|
325
|
+
maxFileSizeMb,
|
|
326
|
+
expires,
|
|
327
|
+
contentTypePrefix,
|
|
328
|
+
parentObjectType,
|
|
329
|
+
parentServiceTag,
|
|
330
|
+
parentIdKey,
|
|
331
|
+
parentIdKeys,
|
|
332
|
+
defaultImportType,
|
|
333
|
+
isRbac,
|
|
334
|
+
rbacServiceTag
|
|
335
|
+
};
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
function _s3HandlerData({
|
|
339
|
+
action,
|
|
340
|
+
flow,
|
|
341
|
+
functionName,
|
|
342
|
+
mainFileName,
|
|
343
|
+
handler,
|
|
344
|
+
isSimplifiedS3
|
|
345
|
+
}) {
|
|
346
|
+
const isStartOrCreate =
|
|
347
|
+
action === 'CreateObject' ||
|
|
348
|
+
(typeof action === 'string' && action.toLowerCase() === 'start');
|
|
349
|
+
if (isStartOrCreate) {
|
|
350
|
+
return {
|
|
351
|
+
functionName,
|
|
352
|
+
mainFileName,
|
|
353
|
+
handlerType: handler,
|
|
354
|
+
route: flow.flowTag,
|
|
355
|
+
isSimplifiedS3
|
|
356
|
+
};
|
|
147
357
|
}
|
|
148
358
|
if (action === 'ProcessAfterUpload') {
|
|
149
359
|
let bucketName = '';
|
|
@@ -154,8 +364,9 @@ function _s3HandlerData({ action, flow, functionName, mainFileName, handler }) {
|
|
|
154
364
|
flowTag: flow.flowTag,
|
|
155
365
|
functionName,
|
|
156
366
|
mainFileName,
|
|
157
|
-
s3Bucket: bucketName
|
|
367
|
+
s3Bucket: bucketName,
|
|
368
|
+
isSimplifiedS3
|
|
158
369
|
};
|
|
159
370
|
}
|
|
160
|
-
return { functionName, handlerType: handler };
|
|
371
|
+
return { functionName, mainFileName, handlerType: handler, isSimplifiedS3 };
|
|
161
372
|
}
|
|
@@ -79,6 +79,9 @@ export function flowExtTopicSteps(flows) {
|
|
|
79
79
|
if (typeof flow?.flowTag !== 'string' || flow.flowTag === '') {
|
|
80
80
|
return [];
|
|
81
81
|
}
|
|
82
|
+
if (Array.isArray(flow.event) && flow.event.includes('s3')) {
|
|
83
|
+
return [];
|
|
84
|
+
}
|
|
82
85
|
const hasTriggerFlowTypes =
|
|
83
86
|
Array.isArray(flow.triggerFlowTypes) && flow.triggerFlowTypes.length > 0;
|
|
84
87
|
if (flow.statusType === 'triggerCache' && !hasTriggerFlowTypes) {
|
|
@@ -341,3 +344,131 @@ function normalizeBelongTo(object) {
|
|
|
341
344
|
if (!belongTo) return [];
|
|
342
345
|
return Array.isArray(belongTo) ? belongTo : [belongTo];
|
|
343
346
|
}
|
|
347
|
+
|
|
348
|
+
export const LEGACY_S3_PARTS = [
|
|
349
|
+
{
|
|
350
|
+
action: 'CreateObject',
|
|
351
|
+
handler: 'HdrWbs',
|
|
352
|
+
type: 'wbs',
|
|
353
|
+
mainTemplate: 'CreateObject_Main.ejs',
|
|
354
|
+
handlerTemplate: 'CreateObject_HdrWbs.ejs'
|
|
355
|
+
},
|
|
356
|
+
{
|
|
357
|
+
action: 'ReservedLimit',
|
|
358
|
+
handler: 'HdrSqs',
|
|
359
|
+
type: 'sqs',
|
|
360
|
+
mainTemplate: 'ReservedLimit_Main.ejs',
|
|
361
|
+
handlerTemplate: 'ReservedLimit_HdrSqs.ejs'
|
|
362
|
+
},
|
|
363
|
+
{
|
|
364
|
+
action: 'CreatePreSignUrl',
|
|
365
|
+
handler: 'HdrSqs',
|
|
366
|
+
type: 'sqs',
|
|
367
|
+
mainTemplate: 'CreatePreSignUrl_Main.ejs',
|
|
368
|
+
handlerTemplate: 'CreatePreSignUrl_HdrSqs.ejs'
|
|
369
|
+
},
|
|
370
|
+
{
|
|
371
|
+
action: 'ProcessAfterUpload',
|
|
372
|
+
handler: 'HdrS3',
|
|
373
|
+
type: 's3',
|
|
374
|
+
mainTemplate: 'ProcessS3File_Main.ejs',
|
|
375
|
+
handlerTemplate: 'FlowHandler_HdrS3.ejs'
|
|
376
|
+
},
|
|
377
|
+
{
|
|
378
|
+
action: 'ConfirmAfterUpload',
|
|
379
|
+
handler: 'HdrSqs',
|
|
380
|
+
type: 'sqs',
|
|
381
|
+
mainTemplate: 'ConfirmReserved_Main.ejs',
|
|
382
|
+
handlerTemplate: 'ConfirmReserved_HdrSqs.ejs'
|
|
383
|
+
}
|
|
384
|
+
];
|
|
385
|
+
|
|
386
|
+
export function resolveS3Parts(flow) {
|
|
387
|
+
if (!Array.isArray(flow?.flowSteps) || flow.flowSteps.length === 0) {
|
|
388
|
+
return LEGACY_S3_PARTS;
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
const stepNames = flow.flowSteps.map((s) => s.stepName);
|
|
392
|
+
if (
|
|
393
|
+
stepNames.includes('CreateObject') &&
|
|
394
|
+
stepNames.includes('ReservedLimit') &&
|
|
395
|
+
stepNames.includes('ConfirmAfterUpload')
|
|
396
|
+
) {
|
|
397
|
+
return LEGACY_S3_PARTS;
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
const hasS3Step = flow.flowSteps.some(
|
|
401
|
+
(step) =>
|
|
402
|
+
(Array.isArray(step.event) && step.event.includes('s3')) ||
|
|
403
|
+
(typeof step.stepName === 'string' &&
|
|
404
|
+
step.stepName.toLowerCase().includes('afterupload'))
|
|
405
|
+
);
|
|
406
|
+
|
|
407
|
+
if (!hasS3Step) {
|
|
408
|
+
return LEGACY_S3_PARTS;
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
const isDeferredNodeFlow =
|
|
412
|
+
!stepNames.includes('CreatePreSignUrl') &&
|
|
413
|
+
(stepNames.includes('ConfirmComplete') ||
|
|
414
|
+
stepNames.includes('ConfirmAfterUpload') ||
|
|
415
|
+
stepNames.length <= 3);
|
|
416
|
+
|
|
417
|
+
return flow.flowSteps.map((step) => {
|
|
418
|
+
const action = upperFirst(step.stepName);
|
|
419
|
+
const eventType = Array.isArray(step.event) ? step.event[0] : 'sqs';
|
|
420
|
+
|
|
421
|
+
if (eventType === 'wbs' || action === 'Start' || action === 'CreateObject') {
|
|
422
|
+
let mainTemplate = 'CreateObject_Main.ejs';
|
|
423
|
+
if (isDeferredNodeFlow) {
|
|
424
|
+
mainTemplate = 'Start_Main.ejs';
|
|
425
|
+
}
|
|
426
|
+
return {
|
|
427
|
+
action,
|
|
428
|
+
handler: 'HdrWbs',
|
|
429
|
+
type: 'wbs',
|
|
430
|
+
mainTemplate,
|
|
431
|
+
handlerTemplate: 'CreateObject_HdrWbs.ejs'
|
|
432
|
+
};
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
if (eventType === 's3' || action === 'ProcessAfterUpload') {
|
|
436
|
+
return {
|
|
437
|
+
action,
|
|
438
|
+
handler: 'HdrS3',
|
|
439
|
+
type: 's3',
|
|
440
|
+
mainTemplate: 'ProcessS3File_Main.ejs',
|
|
441
|
+
handlerTemplate: 'FlowHandler_HdrS3.ejs'
|
|
442
|
+
};
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
if (action === 'ConfirmComplete') {
|
|
446
|
+
return {
|
|
447
|
+
action,
|
|
448
|
+
handler: 'HdrSqs',
|
|
449
|
+
type: 'sqs',
|
|
450
|
+
mainTemplate: 'ConfirmComplete_Main.ejs',
|
|
451
|
+
handlerTemplate: 'ConfirmComplete_HdrSqs.ejs'
|
|
452
|
+
};
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
if (action === 'ConfirmAfterUpload') {
|
|
456
|
+
return {
|
|
457
|
+
action,
|
|
458
|
+
handler: 'HdrSqs',
|
|
459
|
+
type: 'sqs',
|
|
460
|
+
mainTemplate: 'ConfirmAfterUpload_Main.ejs',
|
|
461
|
+
handlerTemplate: 'ConfirmAfterUpload_HdrSqs.ejs'
|
|
462
|
+
};
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
return {
|
|
466
|
+
action,
|
|
467
|
+
handler: 'HdrSqs',
|
|
468
|
+
type: 'sqs',
|
|
469
|
+
mainTemplate: 'CreatePreSignUrl_Main.ejs',
|
|
470
|
+
handlerTemplate: 'CreatePreSignUrl_HdrSqs.ejs'
|
|
471
|
+
};
|
|
472
|
+
});
|
|
473
|
+
}
|
|
474
|
+
|
|
@@ -201,7 +201,9 @@ async function emitFlow(flow, objects) {
|
|
|
201
201
|
functions.push(...root.functions);
|
|
202
202
|
}
|
|
203
203
|
if (flow.event.includes('s3')) {
|
|
204
|
-
const s3Artifacts = await emitS3Flow(flow, source, handlerRoot
|
|
204
|
+
const s3Artifacts = await emitS3Flow(flow, source, handlerRoot, {
|
|
205
|
+
objects
|
|
206
|
+
});
|
|
205
207
|
artifacts.push(...s3Artifacts.artifacts);
|
|
206
208
|
functions.push(...s3Artifacts.functions);
|
|
207
209
|
}
|
|
@@ -247,8 +247,8 @@ export default async function <%- typeof functionName !== 'undefined' ? function
|
|
|
247
247
|
resultPermissionCheck
|
|
248
248
|
);
|
|
249
249
|
|
|
250
|
-
//(<rbacPublish_<%- flowTag
|
|
251
|
-
//(</rbacPublish_<%- flowTag
|
|
250
|
+
//(<rbacPublish_<%- flowTag %>>)
|
|
251
|
+
//(</rbacPublish_<%- flowTag %>>)
|
|
252
252
|
|
|
253
253
|
return resultPermissionCheck;
|
|
254
254
|
<% } else { -%>
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Copyright (C) 2026 Sven Mason <http://izara.io>
|
|
3
|
+
|
|
4
|
+
This program is free software: you can redistribute it and/or modify
|
|
5
|
+
it under the terms of the GNU Affero General Public License as
|
|
6
|
+
published by the Free Software Foundation, either version 3 of the
|
|
7
|
+
License, or (at your option) any later version.
|
|
8
|
+
|
|
9
|
+
This program is distributed in the hope that it will be useful,
|
|
10
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
11
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
12
|
+
GNU Affero General Public License for more details.
|
|
13
|
+
|
|
14
|
+
You should have received a copy of the GNU Affero General Public License
|
|
15
|
+
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
import { middlewareHandler as middleware } from '@izara_project/izara-middleware';
|
|
19
|
+
import { recordHandlerSharedLib } from '@izara_project/izara-core-library-record-handler';
|
|
20
|
+
import Logger from '@izara_project/izara-core-library-logger';
|
|
21
|
+
import callingFlowSharedLib from '@izara_project/izara-core-library-calling-flow';
|
|
22
|
+
|
|
23
|
+
import <%= functionName %> from './<%= functionName %>_Main.js';
|
|
24
|
+
|
|
25
|
+
middleware.setValidatorSchema(recordHandlerSharedLib.baseValidatorSchema());
|
|
26
|
+
|
|
27
|
+
let perRecordsValidatorSchema = {
|
|
28
|
+
type: 'object',
|
|
29
|
+
required: ['objType', 'objInstanceFull'],
|
|
30
|
+
properties: {
|
|
31
|
+
objType: {
|
|
32
|
+
type: 'object',
|
|
33
|
+
required: ['objectType', 'serviceTag'],
|
|
34
|
+
properties: {
|
|
35
|
+
objectType: {
|
|
36
|
+
type: 'string',
|
|
37
|
+
pattern: '^[a-zA-Z0-9_-]+$'
|
|
38
|
+
},
|
|
39
|
+
serviceTag: {
|
|
40
|
+
type: 'string',
|
|
41
|
+
pattern: '^[a-zA-Z0-9_-]+$'
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
},
|
|
45
|
+
objInstanceFull: {
|
|
46
|
+
type: 'object',
|
|
47
|
+
properties: {
|
|
48
|
+
identifiers: {
|
|
49
|
+
type: 'object',
|
|
50
|
+
minProperties: 1
|
|
51
|
+
},
|
|
52
|
+
fields: {
|
|
53
|
+
type: 'object'
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
perRecordsValidatorSchema =
|
|
61
|
+
callingFlowSharedLib.addOptionalPassBackPropertiesToValidatorSchema(
|
|
62
|
+
perRecordsValidatorSchema
|
|
63
|
+
);
|
|
64
|
+
|
|
65
|
+
export const main = middleware.wrap(async (event, context) => {
|
|
66
|
+
try {
|
|
67
|
+
let recordPromises = [];
|
|
68
|
+
|
|
69
|
+
await Promise.all(
|
|
70
|
+
event.Records.map(async (record) => {
|
|
71
|
+
let passOnProperties = [];
|
|
72
|
+
record._izContext.logger.debug('record <%= functionName %><%= handlerType %>', record);
|
|
73
|
+
|
|
74
|
+
await recordHandlerSharedLib.validateRecord(
|
|
75
|
+
record,
|
|
76
|
+
'<%= functionName %><%= handlerType %>',
|
|
77
|
+
perRecordsValidatorSchema
|
|
78
|
+
);
|
|
79
|
+
|
|
80
|
+
passOnProperties.push(record.body.Message.objType);
|
|
81
|
+
passOnProperties.push(record.body.Message.objInstanceFull);
|
|
82
|
+
//(<additionalProperties>)
|
|
83
|
+
//(</additionalProperties>)
|
|
84
|
+
passOnProperties.push(
|
|
85
|
+
callingFlowSharedLib.addPassBackPropertiesToPassOnProperties(
|
|
86
|
+
record.body.Message
|
|
87
|
+
)
|
|
88
|
+
);
|
|
89
|
+
|
|
90
|
+
record._izContext.logger.debug(
|
|
91
|
+
'passOnProperties in <%= functionName %><%= handlerType %>',
|
|
92
|
+
passOnProperties
|
|
93
|
+
);
|
|
94
|
+
|
|
95
|
+
let returnPromise = await recordHandlerSharedLib.recordHandler(
|
|
96
|
+
record,
|
|
97
|
+
<%= functionName %>,
|
|
98
|
+
passOnProperties
|
|
99
|
+
);
|
|
100
|
+
|
|
101
|
+
recordPromises.push(returnPromise);
|
|
102
|
+
})
|
|
103
|
+
);
|
|
104
|
+
|
|
105
|
+
return await Promise.all(recordPromises);
|
|
106
|
+
} catch (err) {
|
|
107
|
+
Logger.error('Error <%= functionName %><%= handlerType %>: ', err);
|
|
108
|
+
throw err;
|
|
109
|
+
}
|
|
110
|
+
});
|