@izara_project/izara-core-generate-service-code 1.0.83 → 1.0.85
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 +4 -4
- package/src/compile/flowValidator.js +13 -2
- package/src/compile/loadSchemas.js +116 -7
- package/src/emit/attributeTree/emitAttributeTreeSchemas.js +388 -0
- package/src/emit/coreFunction/emitCoreFunctionArtifacts.js +34 -1
- package/src/emit/coreFunction/templates/InitialSetupConfig.ejs +29 -7
- package/src/emit/crud/crudActionPlan.js +41 -6
- package/src/emit/crud/emitCrudApplicationArtifacts.js +56 -8
- package/src/emit/crud/emitDynamicCrudFlowSchemas.js +153 -27
- package/src/emit/crud/generateCrudApplicationArtifacts.js +3 -2
- package/src/emit/crud/generateDynamicCrudFlowSchemas.js +3 -2
- package/src/emit/crud/loadLocalSchemaArrays.js +3 -3
- package/src/emit/crud/templates/CreateComplete_Main.ejs +1 -1
- package/src/emit/crud/templates/CreateConfirmComplete_Main.ejs +54 -0
- package/src/emit/crud/templates/CreateEndpoint_Main.ejs +252 -154
- package/src/emit/crud/templates/CreateLogicalLib.ejs +1163 -236
- package/src/emit/crud/templates/CreateNodeCallback_Main.ejs +221 -0
- package/src/emit/crud/templates/DeleteComplete_Main.ejs +1 -1
- package/src/emit/crud/templates/DeleteEndpoint_Main.ejs +33 -8
- package/src/emit/crud/templates/DeleteLogicalLib.ejs +6 -3
- package/src/emit/crud/templates/FlowEndpointRbacCallback_Main.ejs +20 -120
- package/src/emit/crud/templates/FlowEndpoint_HdrWbs.ejs +79 -10
- package/src/emit/crud/templates/FlowMain_Wbs.ejs +31 -35
- package/src/emit/crud/templates/GetEndpoint_Main.ejs +13 -0
- package/src/emit/crud/templates/UpdateComplete_Main.ejs +1 -1
- package/src/emit/crud/templates/UpdateEndpoint_Main.ejs +52 -3
- package/src/emit/crud/templates/UpdateLogicalLib.ejs +4 -3
- package/src/emit/custom/customFlows.js +47 -0
- package/src/emit/custom/emitCustomFlowApplicationArtifacts.js +168 -49
- package/src/emit/custom/generateCustomFlowApplicationArtifacts.js +1 -1
- package/src/emit/custom/templates/FlowEndpointRbacCallback_Main.ejs +194 -0
- package/src/emit/custom/templates/FlowEndpoint_Main.ejs +14 -22
- package/src/emit/custom/templates/FlowStep_Main.ejs +1 -1
- package/src/emit/function/templates/WbsFunction_Yaml.ejs +0 -2
- package/src/emit/rbac/emitDynamicRbacFlowSchemas.js +33 -8
- package/src/emit/rbac/emitRbacApplicationArtifacts.js +204 -7
- package/src/emit/rbac/templates/CancelUsage_Main.ejs +163 -0
- package/src/emit/rbac/templates/ConfirmUsage_Main.ejs +187 -0
- package/src/emit/rbac/templates/CreateTargetRole_Main.ejs +68 -6
- package/src/emit/rbac/templates/ListRbac_Main.ejs +9 -3
- package/src/emit/rbac/templates/RbacMutation_Main.ejs +1 -1
- package/src/emit/rbac/templates/ReservedDynamicUsage_Main.ejs +166 -0
- package/src/emit/rbac/templates/UserRbacFlow_Main.ejs +84 -23
- package/src/emit/rbac/templates/UserRoleMutation_Main.ejs +11 -8
- package/src/emit/relationship/emitDynamicRelationshipFlowSchemas.js +1 -1
- package/src/emit/relationship/templates/ChangeRelationship_Main.ejs +4 -4
- package/src/emit/resource/emitResourceArtifacts.js +351 -108
- package/src/emit/resource/templates/GeneratedLambdaRoleServiceConfig.ejs +3 -1
- package/src/emit/resource/templates/SystemDynamoDB_Yaml.ejs +55 -2
- package/src/emit/shared/templates/FlowHandler_HdrSqs.ejs +1 -1
- package/src/emit/system/emitSystemWebSocketArtifacts.js +6 -5
- package/src/emit/system/templates/WebSocketConnect.ejs +71 -12
- package/src/emit/system/templates/WebSocketConnect_Yaml.ejs +6 -0
- package/src/emit/systemText/emitSystemTextSchemas.js +1 -1
- package/src/generate.js +41 -10
- package/test/attributeTreeSchemas.test.js +219 -0
- package/test/createTargetRoleHandler.test.js +59 -4
- package/test/crudApplicationArtifacts.test.js +20 -3
- package/test/customFlowApplicationArtifacts.test.js +5 -5
- package/test/dynamicCrudFlowSchemas.test.js +107 -6
- package/test/dynamicRbacFlowSchemas.test.js +15 -2
- package/test/publicApi.test.js +6 -6
- package/test/resourceArtifacts.test.js +89 -27
|
@@ -61,11 +61,1089 @@ const PREFIX = {
|
|
|
61
61
|
CREATE_OBJECT_EXTERNAL_TOPIC: 'CreateExternalTopicEndpoint'
|
|
62
62
|
};
|
|
63
63
|
|
|
64
|
+
// ── 1. Create_Main Helpers ───────────────────────────────────────────────────
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Loads ObjectSchema and resolves submittedByUserId and targetIdentifiers
|
|
68
|
+
* @param {Object} _izContext - Izara context object
|
|
69
|
+
* @param {Object} requestParams - Incoming request parameters
|
|
70
|
+
* @param {Array<string>} errorsFound - Array to collect validation errors
|
|
71
|
+
* @returns {Promise<{ objType: string, objectSchema: Object }>}
|
|
72
|
+
*/
|
|
73
|
+
export async function resolveSchemaAndIdentity(_izContext, requestParams, errorsFound) {
|
|
74
|
+
const objType = createObjType(requestParams.objectType);
|
|
75
|
+
const objectSchema = await getObjectSchema.getObjSchemaS3WithHierarchy(
|
|
76
|
+
_izContext,
|
|
77
|
+
objType
|
|
78
|
+
);
|
|
79
|
+
_izContext.logger.debug(`[${process.env.iz_serviceTag}:<%- flowTag %>] objectSchema:`, objectSchema);
|
|
80
|
+
|
|
81
|
+
let submittedByUserId, targetIdentifiers;
|
|
82
|
+
if (
|
|
83
|
+
objectSchema.generatedBy === 'user' ||
|
|
84
|
+
objectSchema.generatedBy === 'systemWithUser'
|
|
85
|
+
) {
|
|
86
|
+
submittedByUserId =
|
|
87
|
+
requestParams.submittedByUserId ||
|
|
88
|
+
_izContext.correlationIds.get(coreConsts.SUBMITTED_BY_USER_ID);
|
|
89
|
+
|
|
90
|
+
targetIdentifiers = requestParams.targetIdentifiers;
|
|
91
|
+
|
|
92
|
+
if (!targetIdentifiers && submittedByUserId) {
|
|
93
|
+
targetIdentifiers = { submittedByUserId };
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
if (!submittedByUserId) errorsFound.push('Not have submittedByUserId');
|
|
97
|
+
if (objectSchema.hasOwnProperty('belongTo') && !targetIdentifiers)
|
|
98
|
+
errorsFound.push('not have targetIdentifiers');
|
|
99
|
+
|
|
100
|
+
if (targetIdentifiers) {
|
|
101
|
+
if (!targetIdentifiers.submittedByUserId && submittedByUserId) {
|
|
102
|
+
targetIdentifiers.submittedByUserId = submittedByUserId;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
if (Array.isArray(objectSchema.identifiers)) {
|
|
106
|
+
for (const identifier of objectSchema.identifiers) {
|
|
107
|
+
if (identifier.fieldName) {
|
|
108
|
+
if (targetIdentifiers[identifier.fieldName] === undefined) {
|
|
109
|
+
targetIdentifiers[identifier.fieldName] = null;
|
|
110
|
+
}
|
|
111
|
+
} else if (Array.isArray(identifier.fieldNames)) {
|
|
112
|
+
for (const fn of identifier.fieldNames) {
|
|
113
|
+
if (targetIdentifiers[fn] === undefined) {
|
|
114
|
+
targetIdentifiers[fn] = null;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
} else if (identifier.name) {
|
|
118
|
+
if (targetIdentifiers[identifier.name] === undefined) {
|
|
119
|
+
targetIdentifiers[identifier.name] = null;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
requestParams.targetIdentifiers = targetIdentifiers;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
_izContext.logger.debug(`[${process.env.iz_serviceTag}:<%- flowTag %>] Identity & Target Context Resolved:`, {
|
|
129
|
+
submittedByUserId: requestParams.submittedByUserId,
|
|
130
|
+
targetIdentifiers: requestParams.targetIdentifiers,
|
|
131
|
+
belongTo: objectSchema.belongTo,
|
|
132
|
+
generatedBy: objectSchema.generatedBy
|
|
133
|
+
});
|
|
134
|
+
} else if (objectSchema.generatedBy === 'searchResultGenerated') {
|
|
135
|
+
submittedByUserId = requestParams.submittedByUserId;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
requestParams.submittedByUserId = submittedByUserId;
|
|
139
|
+
return { objType, objectSchema };
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Resolves and generates primary identifiers for the object
|
|
144
|
+
* @param {Object} _izContext - Izara context object
|
|
145
|
+
* @param {Object} objectSchemas - Combined object schema
|
|
146
|
+
* @param {Object} requestParams - Incoming request parameters
|
|
147
|
+
* @returns {Promise<void>}
|
|
148
|
+
*/
|
|
149
|
+
export async function resolveAndGenerateIdentifiers(_izContext, objectSchemas, requestParams) {
|
|
150
|
+
const identifiers = await createIdentifiersByUseCase(
|
|
151
|
+
_izContext,
|
|
152
|
+
objectSchemas,
|
|
153
|
+
requestParams.fieldNames
|
|
154
|
+
);
|
|
155
|
+
|
|
156
|
+
for (const [key, value] of Object.entries(identifiers)) {
|
|
157
|
+
if (!requestParams.fieldNames.hasOwnProperty(key)) {
|
|
158
|
+
requestParams.fieldNames[key] = value;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
_izContext.logger.debug(
|
|
163
|
+
`[${process.env.iz_serviceTag}:<%- flowTag %>] Identifiers generated:`,
|
|
164
|
+
identifiers
|
|
165
|
+
);
|
|
166
|
+
}
|
|
167
|
+
|
|
64
168
|
/**
|
|
65
|
-
*
|
|
169
|
+
* Validates request field names against schema definition
|
|
170
|
+
* @param {Object} _izContext - Izara context object
|
|
171
|
+
* @param {Object} objectSchemas - Combined object schema
|
|
172
|
+
* @param {Object} requestParams - Incoming request parameters
|
|
173
|
+
* @param {Array<string>} errorsFound - Array to collect validation errors
|
|
174
|
+
*/
|
|
175
|
+
export function validateFieldNames(_izContext, objectSchemas, requestParams, errorsFound) {
|
|
176
|
+
const invalidFieldNames = [];
|
|
177
|
+
for (const fieldName of Object.keys(requestParams.fieldNames || {})) {
|
|
178
|
+
if (!objectSchemas.fieldNames.includes(fieldName)) {
|
|
179
|
+
invalidFieldNames.push(fieldName);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
if (invalidFieldNames.length > 0) {
|
|
184
|
+
errorsFound.push(
|
|
185
|
+
`Invalid fieldName not match from Schema: ${invalidFieldNames.join(',')}`
|
|
186
|
+
);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
// ── 2. CreateRbacCallback_Main Helpers ────────────────────────────────────────
|
|
191
|
+
|
|
192
|
+
/**
|
|
193
|
+
* Checks awaiting steps status and collects returned results from App and Target RBAC
|
|
194
|
+
* @param {Object} _izContext - Izara context object
|
|
195
|
+
* @param {Object} requestParams - Request parameters with parentFlowId
|
|
196
|
+
* @returns {Promise<{ isComplete: boolean, rbacResults?: Object, originalRequestParams?: Object, collectedErrors?: Array<string> }>}
|
|
197
|
+
*/
|
|
198
|
+
export async function collectRbacAwaitingResults(_izContext, requestParams) {
|
|
199
|
+
const parts = requestParams.parentFlowId.split('_');
|
|
200
|
+
const rbacType = parts.pop();
|
|
201
|
+
const rbacPendingStepId = '<%- flowTag %>RbacCallback_' + parts.join('_');
|
|
202
|
+
const currentAwaitingStepId = requestParams.parentFlowId;
|
|
203
|
+
|
|
204
|
+
_izContext.logger.debug(
|
|
205
|
+
'[<%- flowTag %>RbacCallbackMain] Parsed RBAC pending details:',
|
|
206
|
+
{
|
|
207
|
+
rbacType,
|
|
208
|
+
rbacPendingStepId,
|
|
209
|
+
currentAwaitingStepId,
|
|
210
|
+
parentFlowId: requestParams.parentFlowId
|
|
211
|
+
}
|
|
212
|
+
);
|
|
213
|
+
|
|
214
|
+
const rbacAwaitingStepsResult =
|
|
215
|
+
await asyncFlowSharedLib.checkAllAwaitingStepsFinishedWithReturnParams(
|
|
216
|
+
_izContext,
|
|
217
|
+
rbacPendingStepId,
|
|
218
|
+
currentAwaitingStepId,
|
|
219
|
+
requestParams.errorsFound,
|
|
220
|
+
{
|
|
221
|
+
returnValue: requestParams.returnValue,
|
|
222
|
+
rbacType
|
|
223
|
+
}
|
|
224
|
+
);
|
|
225
|
+
|
|
226
|
+
_izContext.logger.debug(
|
|
227
|
+
'[<%- flowTag %>RbacCallbackMain] checkAllAwaitingStepsFinishedWithReturnParams result:',
|
|
228
|
+
{
|
|
229
|
+
rbacAwaitingStepsResult
|
|
230
|
+
}
|
|
231
|
+
);
|
|
232
|
+
|
|
233
|
+
const {
|
|
234
|
+
isComplete,
|
|
235
|
+
collectedReturnValueByAwaitingStepId,
|
|
236
|
+
collectedErrors: errorsFound = [],
|
|
237
|
+
additionalAttributes
|
|
238
|
+
} = rbacAwaitingStepsResult;
|
|
239
|
+
|
|
240
|
+
if (isComplete === false) {
|
|
241
|
+
_izContext.logger.debug(
|
|
242
|
+
'[<%- flowTag %>RbacCallbackMain] Awaiting steps still pending completion:',
|
|
243
|
+
{
|
|
244
|
+
rbacPendingStepId,
|
|
245
|
+
isComplete
|
|
246
|
+
}
|
|
247
|
+
);
|
|
248
|
+
return { isComplete: false };
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
_izContext.logger.debug(
|
|
252
|
+
'[<%- flowTag %>RbacCallbackMain] All awaiting steps completed — clearing awaiting steps:',
|
|
253
|
+
{
|
|
254
|
+
rbacPendingStepId
|
|
255
|
+
}
|
|
256
|
+
);
|
|
257
|
+
|
|
258
|
+
await asyncFlowSharedLib.clearAllAwaitingSteps(
|
|
259
|
+
_izContext,
|
|
260
|
+
rbacPendingStepId
|
|
261
|
+
);
|
|
262
|
+
|
|
263
|
+
const originalRequestParams = additionalAttributes?.requestParams || {};
|
|
264
|
+
const rbacResults = Object.fromEntries(
|
|
265
|
+
Object.entries(collectedReturnValueByAwaitingStepId || {}).map(
|
|
266
|
+
([stepId, attrs]) => {
|
|
267
|
+
const type = stepId.split('_').pop();
|
|
268
|
+
return [type, attrs];
|
|
269
|
+
}
|
|
270
|
+
)
|
|
271
|
+
);
|
|
272
|
+
|
|
273
|
+
return {
|
|
274
|
+
isComplete: true,
|
|
275
|
+
rbacResults,
|
|
276
|
+
originalRequestParams,
|
|
277
|
+
collectedErrors: errorsFound
|
|
278
|
+
};
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
/**
|
|
282
|
+
* Asserts RBAC permission and publishes rejected response if unauthorized
|
|
283
|
+
* @param {Object} _izContext - Izara context object
|
|
284
|
+
* @param {Object} options - Validation options
|
|
285
|
+
* @returns {Promise<{ hasError: boolean, errorResult?: Object, rbacCallbackResults: Object }>}
|
|
286
|
+
*/
|
|
287
|
+
export async function assertRbacPermission(_izContext, { rbacResults, originalRequestParams, errorsFound }) {
|
|
288
|
+
const rbacCallbackResults = {};
|
|
289
|
+
const hasError = Object.entries(rbacResults).some(([type, result]) => {
|
|
290
|
+
if (result && result.error) {
|
|
291
|
+
errorsFound.push(result.error);
|
|
292
|
+
return true;
|
|
293
|
+
}
|
|
294
|
+
rbacCallbackResults[type] = result;
|
|
295
|
+
return false;
|
|
296
|
+
});
|
|
297
|
+
|
|
298
|
+
const isAllowed = Object.values(rbacCallbackResults).some(
|
|
299
|
+
item => item?.returnValue?.permission === true
|
|
300
|
+
);
|
|
301
|
+
|
|
302
|
+
if (!isAllowed) {
|
|
303
|
+
errorsFound.push('Permission denied');
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
_izContext.logger.debug(
|
|
307
|
+
'[<%- flowTag %>RbacCallbackMain] Final rbacCallbackResults before calling <%- flowTag %>MainLogical:',
|
|
308
|
+
{
|
|
309
|
+
rbacCallbackResults,
|
|
310
|
+
isAllowed,
|
|
311
|
+
errorsFound
|
|
312
|
+
}
|
|
313
|
+
);
|
|
314
|
+
|
|
315
|
+
if (hasError || errorsFound.length > 0) {
|
|
316
|
+
const errorResult = {
|
|
317
|
+
errorsFound,
|
|
318
|
+
status: 'rejected',
|
|
319
|
+
requestParams: originalRequestParams
|
|
320
|
+
};
|
|
321
|
+
|
|
322
|
+
_izContext.logger.debug(
|
|
323
|
+
'[<%- flowTag %>RbacCallbackMain] RBAC check failed, publishing rejected status:',
|
|
324
|
+
errorResult
|
|
325
|
+
);
|
|
326
|
+
|
|
327
|
+
await sns.publishAsync(_izContext, {
|
|
328
|
+
TopicArn: snsSharedLib.snsTopicArnByFlowSchema(
|
|
329
|
+
_izContext,
|
|
330
|
+
'<%- upperCaseFlowTag %>_Out',
|
|
331
|
+
process.env.iz_serviceTag
|
|
332
|
+
),
|
|
333
|
+
Message: JSON.stringify(errorResult)
|
|
334
|
+
});
|
|
335
|
+
|
|
336
|
+
return { hasError: true, errorResult, rbacCallbackResults };
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
return { hasError: false, rbacCallbackResults };
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
// ── 3. CreateNodeCallback_Main Helpers ────────────────────────────────────────
|
|
343
|
+
|
|
344
|
+
/**
|
|
345
|
+
* Saves DynamoDB records from listOfRecords
|
|
346
|
+
* @param {Object} _izContext - Izara context object
|
|
347
|
+
* @param {Array<Object>} listOfRecords - Records to persist
|
|
348
|
+
* @returns {Promise<void>}
|
|
349
|
+
*/
|
|
350
|
+
export async function saveDynamoDbRecords(_izContext, listOfRecords) {
|
|
351
|
+
if (!Array.isArray(listOfRecords) || listOfRecords.length === 0) {
|
|
352
|
+
return;
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
await Promise.all(
|
|
356
|
+
listOfRecords.flatMap((records) =>
|
|
357
|
+
Object.values(records).map(async (record) =>
|
|
358
|
+
dynamodbSharedLib.putItem(
|
|
359
|
+
_izContext,
|
|
360
|
+
await dynamodbSharedLib.tableName(
|
|
361
|
+
_izContext,
|
|
362
|
+
record.tableName,
|
|
363
|
+
record.serviceTag
|
|
364
|
+
),
|
|
365
|
+
{
|
|
366
|
+
...record.objInstanceFull.identifiers,
|
|
367
|
+
...record.objInstanceFull.fields
|
|
368
|
+
}
|
|
369
|
+
)
|
|
370
|
+
)
|
|
371
|
+
)
|
|
372
|
+
);
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
/**
|
|
376
|
+
* Auto-provisions owner TargetRole for Root RBAC object after Graph and DynamoDB write
|
|
377
|
+
* @param {Object} _izContext - Izara context object
|
|
378
|
+
* @param {Object} options - Target node and submitter details
|
|
379
|
+
* @returns {Promise<void>}
|
|
380
|
+
*/
|
|
381
|
+
export async function autoProvisionOwnerTargetRole(_izContext, { node, submittedByUserId }) {
|
|
382
|
+
try {
|
|
383
|
+
if (!submittedByUserId || !node?.objInstanceFull?.identifiers) {
|
|
384
|
+
return;
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
const identifiers = node.objInstanceFull.identifiers;
|
|
388
|
+
const targetIdentKeys = Object.entries(identifiers)
|
|
389
|
+
.filter(([k]) => k !== 'submittedByUserId')
|
|
390
|
+
.map(([k, v]) => `${k}#${v}`)
|
|
391
|
+
.join('|');
|
|
392
|
+
|
|
393
|
+
const targetIdentifiersConcat =
|
|
394
|
+
targetIdentKeys ||
|
|
395
|
+
(identifiers[Object.keys(identifiers)[0]]
|
|
396
|
+
? `${Object.keys(identifiers)[0]}#${identifiers[Object.keys(identifiers)[0]]}`
|
|
397
|
+
: '');
|
|
398
|
+
|
|
399
|
+
if (!targetIdentifiersConcat) {
|
|
400
|
+
return;
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
const roleIdKey = `${targetIdentifiersConcat}_owner`;
|
|
404
|
+
_izContext.logger.debug(
|
|
405
|
+
'[CreateNodeCallback] Auto-provisioning owner TargetRole:',
|
|
406
|
+
{
|
|
407
|
+
identifiersConcat: targetIdentifiersConcat,
|
|
408
|
+
roleIdKey,
|
|
409
|
+
submittedByUserId,
|
|
410
|
+
roleName: 'owner'
|
|
411
|
+
}
|
|
412
|
+
);
|
|
413
|
+
|
|
414
|
+
await dynamodbSharedLib.putItem(
|
|
415
|
+
_izContext,
|
|
416
|
+
dynamodbSharedLib.tableName(_izContext, 'TargetRoles'),
|
|
417
|
+
{
|
|
418
|
+
identifiersConcat: targetIdentifiersConcat,
|
|
419
|
+
roleIdKey,
|
|
420
|
+
submittedByUserId,
|
|
421
|
+
roleName: 'owner',
|
|
422
|
+
assignedAt: new Date().toISOString()
|
|
423
|
+
}
|
|
424
|
+
);
|
|
425
|
+
|
|
426
|
+
await dynamodbSharedLib.transactWriteItems(_izContext, [
|
|
427
|
+
{
|
|
428
|
+
action: 'put',
|
|
429
|
+
params: {
|
|
430
|
+
tableName: dynamodbSharedLib.tableName(
|
|
431
|
+
_izContext,
|
|
432
|
+
'RoleUsers'
|
|
433
|
+
),
|
|
434
|
+
attributes: {
|
|
435
|
+
roleIdKey,
|
|
436
|
+
userId: submittedByUserId,
|
|
437
|
+
submittedByUserId
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
},
|
|
441
|
+
{
|
|
442
|
+
action: 'put',
|
|
443
|
+
params: {
|
|
444
|
+
tableName: dynamodbSharedLib.tableName(
|
|
445
|
+
_izContext,
|
|
446
|
+
'UserRoles'
|
|
447
|
+
),
|
|
448
|
+
attributes: {
|
|
449
|
+
userId: submittedByUserId,
|
|
450
|
+
roleIdKey,
|
|
451
|
+
submittedByUserId
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
},
|
|
455
|
+
{
|
|
456
|
+
action: 'put',
|
|
457
|
+
params: {
|
|
458
|
+
tableName: dynamodbSharedLib.tableName(
|
|
459
|
+
_izContext,
|
|
460
|
+
'RolePermissions'
|
|
461
|
+
),
|
|
462
|
+
attributes: {
|
|
463
|
+
roleIdKey,
|
|
464
|
+
flowTypeConcat: `${process.env.iz_serviceTag}_Update`,
|
|
465
|
+
permission: true,
|
|
466
|
+
allow: 'accept',
|
|
467
|
+
parameterGroups: {},
|
|
468
|
+
submittedByUserId
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
},
|
|
472
|
+
{
|
|
473
|
+
action: 'put',
|
|
474
|
+
params: {
|
|
475
|
+
tableName: dynamodbSharedLib.tableName(
|
|
476
|
+
_izContext,
|
|
477
|
+
'RolePermissions'
|
|
478
|
+
),
|
|
479
|
+
attributes: {
|
|
480
|
+
roleIdKey,
|
|
481
|
+
flowTypeConcat: `${process.env.iz_serviceTag}_Delete`,
|
|
482
|
+
permission: true,
|
|
483
|
+
allow: 'accept',
|
|
484
|
+
parameterGroups: {},
|
|
485
|
+
submittedByUserId
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
]);
|
|
490
|
+
} catch (roleError) {
|
|
491
|
+
_izContext.logger.error(
|
|
492
|
+
'[CreateNodeCallback] Failed to auto-provision owner TargetRole:',
|
|
493
|
+
{ roleError }
|
|
494
|
+
);
|
|
495
|
+
}
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
/**
|
|
499
|
+
* Resolves keys and identifiers for Quota Deduction / Confirmation
|
|
500
|
+
* @param {Object} requestParams - Request parameters
|
|
501
|
+
* @param {Object} passBackProperties - Pass back properties
|
|
502
|
+
* @param {Object} returnValue - Return value from graph service
|
|
503
|
+
* @param {Object} callingFlowConfig - Calling flow configuration
|
|
504
|
+
* @param {Object} _izContext - Izara context object
|
|
505
|
+
* @returns {Object} Quota deduction keys
|
|
506
|
+
*/
|
|
507
|
+
export function resolveQuotaDeductionKeys(
|
|
508
|
+
requestParams,
|
|
509
|
+
passBackProperties,
|
|
510
|
+
returnValue,
|
|
511
|
+
callingFlowConfig,
|
|
512
|
+
_izContext
|
|
513
|
+
) {
|
|
514
|
+
const targetIdentifiers =
|
|
515
|
+
requestParams?.passBackProperties?.targetIdentifiers ||
|
|
516
|
+
passBackProperties?.passBackProperties?.targetIdentifiers ||
|
|
517
|
+
passBackProperties?.targetIdentifiers ||
|
|
518
|
+
returnValue?.requestParams?.targetIdentifiers;
|
|
519
|
+
|
|
520
|
+
const submittedByUserId =
|
|
521
|
+
returnValue?.requestParams?.submittedByUserId ||
|
|
522
|
+
targetIdentifiers?.submittedByUserId ||
|
|
523
|
+
requestParams?.submittedByUserId ||
|
|
524
|
+
requestParams?.passBackProperties?.submittedByUserId ||
|
|
525
|
+
passBackProperties?.passBackProperties?.submittedByUserId ||
|
|
526
|
+
passBackProperties?.submittedByUserId ||
|
|
527
|
+
_izContext.correlationIds?.get(coreConsts.SUBMITTED_BY_USER_ID) ||
|
|
528
|
+
_izContext.correlationIds?.get('submittedByUserId') ||
|
|
529
|
+
_izContext.correlationIds?.get('userId');
|
|
530
|
+
|
|
531
|
+
let identifiersConcat =
|
|
532
|
+
requestParams?.passBackProperties?.identifiersConcat ||
|
|
533
|
+
passBackProperties?.passBackProperties?.identifiersConcat ||
|
|
534
|
+
passBackProperties?.identifiersConcat ||
|
|
535
|
+
null;
|
|
536
|
+
|
|
537
|
+
if (!identifiersConcat && targetIdentifiers && typeof targetIdentifiers === 'object') {
|
|
538
|
+
if (targetIdentifiers.identifierConcat) {
|
|
539
|
+
identifiersConcat = targetIdentifiers.identifierConcat;
|
|
540
|
+
} else {
|
|
541
|
+
const sortedKeys = Object.keys(targetIdentifiers).sort();
|
|
542
|
+
const parts = [];
|
|
543
|
+
for (const key of sortedKeys) {
|
|
544
|
+
const value = targetIdentifiers[key];
|
|
545
|
+
if (
|
|
546
|
+
key !== 'submittedByUserId' &&
|
|
547
|
+
key !== 'identifierConcat' &&
|
|
548
|
+
value !== undefined &&
|
|
549
|
+
value !== null
|
|
550
|
+
) {
|
|
551
|
+
parts.push(`${key}#${value}`);
|
|
552
|
+
}
|
|
553
|
+
}
|
|
554
|
+
if (parts.length > 0) {
|
|
555
|
+
identifiersConcat = parts.join('|');
|
|
556
|
+
}
|
|
557
|
+
}
|
|
558
|
+
}
|
|
559
|
+
if (!identifiersConcat) {
|
|
560
|
+
identifiersConcat = submittedByUserId;
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
const limitTag =
|
|
564
|
+
requestParams?.passBackProperties?.limitTag ||
|
|
565
|
+
passBackProperties?.passBackProperties?.limitTag ||
|
|
566
|
+
passBackProperties?.limitTag ||
|
|
567
|
+
callingFlowConfig?.limitTag ||
|
|
568
|
+
requestParams?.passBackProperties?.flowTypeConcat ||
|
|
569
|
+
passBackProperties?.passBackProperties?.flowTypeConcat ||
|
|
570
|
+
passBackProperties?.flowTypeConcat ||
|
|
571
|
+
callingFlowConfig?.flowTypeConcat ||
|
|
572
|
+
`${process.env.iz_serviceTag}_<%- flowTag %>`;
|
|
573
|
+
|
|
574
|
+
const flowTypeConcat = limitTag;
|
|
575
|
+
|
|
576
|
+
const uniqueIdentify =
|
|
577
|
+
requestParams?.passBackProperties?.uniqueIdentify ||
|
|
578
|
+
passBackProperties?.passBackProperties?.uniqueIdentify ||
|
|
579
|
+
passBackProperties?.uniqueIdentify ||
|
|
580
|
+
callingFlowConfig?.uniqueIdentify ||
|
|
581
|
+
_izContext.uniqueRequestId;
|
|
582
|
+
|
|
583
|
+
const usedTimestampId = uniqueIdentify;
|
|
584
|
+
|
|
585
|
+
const runningTotalReservedId =
|
|
586
|
+
requestParams?.passBackProperties?.runningTotalReservedId ||
|
|
587
|
+
passBackProperties?.passBackProperties?.runningTotalReservedId ||
|
|
588
|
+
passBackProperties?.runningTotalReservedId ||
|
|
589
|
+
callingFlowConfig?.runningTotalReservedId ||
|
|
590
|
+
(identifiersConcat && limitTag
|
|
591
|
+
? `${identifiersConcat}_${limitTag}`
|
|
592
|
+
: null);
|
|
593
|
+
|
|
594
|
+
const rbacType =
|
|
595
|
+
requestParams?.passBackProperties?.rbacType ||
|
|
596
|
+
passBackProperties?.passBackProperties?.rbacType ||
|
|
597
|
+
passBackProperties?.rbacType ||
|
|
598
|
+
callingFlowConfig?.rbacType;
|
|
599
|
+
|
|
600
|
+
return {
|
|
601
|
+
limitTag,
|
|
602
|
+
flowTypeConcat,
|
|
603
|
+
uniqueIdentify,
|
|
604
|
+
usedTimestampId,
|
|
605
|
+
runningTotalReservedId,
|
|
606
|
+
identifiersConcat,
|
|
607
|
+
targetIdentifiers,
|
|
608
|
+
rbacType
|
|
609
|
+
};
|
|
610
|
+
}
|
|
611
|
+
|
|
612
|
+
/**
|
|
613
|
+
* Forwards quota confirmation message to ConfirmUsage_In or CancelUsage_In
|
|
614
|
+
* @param {Object} _izContext - Izara context object
|
|
615
|
+
* @param {Object} options - Message forwarding options
|
|
616
|
+
* @returns {Promise<void>}
|
|
617
|
+
*/
|
|
618
|
+
export async function forwardToQuotaConfirmation(
|
|
619
|
+
_izContext,
|
|
620
|
+
{
|
|
621
|
+
status,
|
|
622
|
+
errorsFound,
|
|
623
|
+
quotaKeys,
|
|
624
|
+
actionData,
|
|
625
|
+
callingFlowConfig
|
|
626
|
+
}
|
|
627
|
+
) {
|
|
628
|
+
const nextTargetTopic =
|
|
629
|
+
status === 'complete' && errorsFound.length === 0
|
|
630
|
+
? 'ConfirmUsage_In'
|
|
631
|
+
: 'CancelUsage_In';
|
|
632
|
+
|
|
633
|
+
const forwardMessage =
|
|
634
|
+
callingFlowSharedLib.addCallingFlowToSnsRequestMessageObject(
|
|
635
|
+
{
|
|
636
|
+
...quotaKeys,
|
|
637
|
+
parentPassBackProperties: actionData
|
|
638
|
+
},
|
|
639
|
+
callingFlowSharedLib.addParentCallingFlowConfig(
|
|
640
|
+
callingFlowConfig,
|
|
641
|
+
callingFlowSharedLib.createCallingFlowConfig(
|
|
642
|
+
await lambdaSharedLib.lambdaFunctionName(
|
|
643
|
+
_izContext,
|
|
644
|
+
'CreateCompleteHdrSqs'
|
|
645
|
+
),
|
|
646
|
+
{}
|
|
647
|
+
)
|
|
648
|
+
)
|
|
649
|
+
);
|
|
650
|
+
|
|
651
|
+
const topicArn = snsSharedLib.snsTopicArnByFlowSchema(
|
|
652
|
+
_izContext,
|
|
653
|
+
nextTargetTopic,
|
|
654
|
+
'Rbac'
|
|
655
|
+
);
|
|
656
|
+
|
|
657
|
+
_izContext.logger.debug('[CreateNodeCallback] forwarding to RBAC', {
|
|
658
|
+
nextTargetTopic,
|
|
659
|
+
TopicArn: topicArn,
|
|
660
|
+
forwardMessage
|
|
661
|
+
});
|
|
662
|
+
|
|
663
|
+
await sns.publishAsync(_izContext, {
|
|
664
|
+
Message: JSON.stringify(forwardMessage),
|
|
665
|
+
TopicArn: topicArn
|
|
666
|
+
});
|
|
667
|
+
}
|
|
668
|
+
|
|
669
|
+
// ── 4. CreateComplete_Main Helpers ───────────────────────────────────────────
|
|
670
|
+
|
|
671
|
+
/**
|
|
672
|
+
* Builds response payload and message attributes for Calling Flow
|
|
673
|
+
* @param {Object} callingFlowConfig - Calling flow configuration
|
|
674
|
+
* @param {Object} parentPassBack - Parent pass-back data
|
|
675
|
+
* @returns {{ message: Object, messageAttributes: Object }}
|
|
676
|
+
*/
|
|
677
|
+
export function buildCompletionPayload(callingFlowConfig, parentPassBack) {
|
|
678
|
+
const message =
|
|
679
|
+
callingFlowSharedLib.addParentPassBackPropertiesToSnsResponseMessageObject(
|
|
680
|
+
callingFlowConfig,
|
|
681
|
+
parentPassBack
|
|
682
|
+
);
|
|
683
|
+
|
|
684
|
+
const messageAttributes =
|
|
685
|
+
callingFlowSharedLib.addParentPassBackCallingFlowToSnsResponseMessageAttributes(
|
|
686
|
+
callingFlowConfig,
|
|
687
|
+
{}
|
|
688
|
+
);
|
|
689
|
+
|
|
690
|
+
return { message, messageAttributes };
|
|
691
|
+
}
|
|
692
|
+
|
|
693
|
+
/**
|
|
694
|
+
* Publishes completion response message to outCreateNodeComplete
|
|
695
|
+
* @param {Object} _izContext - Izara context object
|
|
696
|
+
* @param {Object} message - SNS message payload
|
|
697
|
+
* @param {Object} messageAttributes - SNS message attributes
|
|
698
|
+
* @returns {Promise<void>}
|
|
699
|
+
*/
|
|
700
|
+
export async function publishCompletionMessage(_izContext, message, messageAttributes) {
|
|
701
|
+
const topicArn = snsSharedLib.snsTopicArnByFlowSchema(
|
|
702
|
+
_izContext,
|
|
703
|
+
TOPIC_NAME_GENERATE_CODE.outCreateNodeComplete
|
|
704
|
+
);
|
|
705
|
+
|
|
706
|
+
_izContext.logger.debug('[CreateComplete] publishing to SNS', {
|
|
707
|
+
TopicArn: topicArn,
|
|
708
|
+
message
|
|
709
|
+
});
|
|
710
|
+
|
|
711
|
+
await sns.publishAsync(_izContext, {
|
|
712
|
+
Message: JSON.stringify(message),
|
|
713
|
+
MessageAttributes: sns.createStringMessageAttributes(
|
|
714
|
+
_izContext,
|
|
715
|
+
messageAttributes
|
|
716
|
+
),
|
|
717
|
+
TopicArn: topicArn
|
|
718
|
+
});
|
|
719
|
+
}
|
|
720
|
+
|
|
721
|
+
// ── 5. CreateLogicalLib Internal Helpers ──────────────────────────────────────
|
|
722
|
+
|
|
723
|
+
/**
|
|
724
|
+
* Resolves and combines object schemas from S3/hierarchy
|
|
725
|
+
* @param {Object} _izContext - Izara context object
|
|
726
|
+
* @param {string} objectType - Object type identifier
|
|
727
|
+
* @returns {Promise<{ objType: Object, objectSchema: Object, objectSchemas: Object, parentObject?: Object }>}
|
|
728
|
+
*/
|
|
729
|
+
export async function resolveObjectSchemas(_izContext, objectType) {
|
|
730
|
+
const objType = createObjType(objectType);
|
|
731
|
+
const objectSchema = await getObjectSchema.getObjSchemaS3WithHierarchy(
|
|
732
|
+
_izContext,
|
|
733
|
+
objType
|
|
734
|
+
);
|
|
735
|
+
_izContext.logger.debug(`[${process.env.iz_serviceTag}:<%- flowTag %>LogicalLib] objectSchema:`, objectSchema);
|
|
736
|
+
|
|
737
|
+
const objectSchemas =
|
|
738
|
+
uploadUseCase.generateObjectSchemaForCombineFieldNames(
|
|
739
|
+
_izContext,
|
|
740
|
+
objectSchema
|
|
741
|
+
);
|
|
742
|
+
_izContext.logger.debug(`[${process.env.iz_serviceTag}:<%- flowTag %>LogicalLib] objectSchemas:`, objectSchemas);
|
|
743
|
+
|
|
744
|
+
let parentObject;
|
|
745
|
+
if (objectSchemas.hasOwnProperty('extendObjType')) {
|
|
746
|
+
parentObject = await getObjectSchema.getObjSchemaS3WithHierarchy(
|
|
747
|
+
_izContext,
|
|
748
|
+
objectSchema.extendObjType
|
|
749
|
+
);
|
|
750
|
+
}
|
|
751
|
+
|
|
752
|
+
return { objType, objectSchema, objectSchemas, parentObject };
|
|
753
|
+
}
|
|
754
|
+
|
|
755
|
+
/**
|
|
756
|
+
* Extracts field values matching storage resource specifications
|
|
757
|
+
* @param {Object} _izContext - Izara context object
|
|
758
|
+
* @param {string} storageTag - Storage resource tag
|
|
759
|
+
* @param {Object} createDataDetails - Complete data details map
|
|
760
|
+
* @param {Object} createDataDetail - Current storage data detail
|
|
761
|
+
* @param {Object} requestParams - Request parameters
|
|
762
|
+
* @param {Object} objInstanceFull - Full object instance with identifiers
|
|
763
|
+
* @returns {Object} Extracted fields object
|
|
764
|
+
*/
|
|
765
|
+
export function extractFieldsByStorageTag(
|
|
766
|
+
_izContext,
|
|
767
|
+
storageTag,
|
|
768
|
+
createDataDetails,
|
|
769
|
+
createDataDetail,
|
|
770
|
+
requestParams,
|
|
771
|
+
objInstanceFull
|
|
772
|
+
) {
|
|
773
|
+
const fields = {};
|
|
774
|
+
for (const fieldName of Object.keys(requestParams.fieldNames || {})) {
|
|
775
|
+
if (
|
|
776
|
+
createDataDetails[storageTag].fieldNames.includes(fieldName) &&
|
|
777
|
+
createDataDetail.fieldNames.includes(fieldName) &&
|
|
778
|
+
!objInstanceFull.identifiers.hasOwnProperty(fieldName) &&
|
|
779
|
+
!fields.hasOwnProperty(fieldName)
|
|
780
|
+
) {
|
|
781
|
+
Object.assign(fields, {
|
|
782
|
+
[fieldName]: requestParams.fieldNames[fieldName]
|
|
783
|
+
});
|
|
784
|
+
}
|
|
785
|
+
}
|
|
786
|
+
return fields;
|
|
787
|
+
}
|
|
788
|
+
|
|
789
|
+
/**
|
|
790
|
+
* Auto-provisions owner TargetRole for DynamoDB-only objects (no Graph)
|
|
791
|
+
* @param {Object} _izContext - Izara context object
|
|
792
|
+
* @param {Object} options - Schema and identity parameters
|
|
793
|
+
* @returns {Promise<void>}
|
|
794
|
+
*/
|
|
795
|
+
export async function autoProvisionOwnerTargetRoleForDynamoOnly(
|
|
796
|
+
_izContext,
|
|
797
|
+
{ objectSchema, identifiersForCreateData, requestParams }
|
|
798
|
+
) {
|
|
799
|
+
const hasRbacAddOn =
|
|
800
|
+
Array.isArray(objectSchema?.addOnDataStructure) &&
|
|
801
|
+
objectSchema.addOnDataStructure.some(addOn => addOn?.type === 'rbac');
|
|
802
|
+
|
|
803
|
+
const isRootRbacObject =
|
|
804
|
+
hasRbacAddOn &&
|
|
805
|
+
!objectSchema?.belongTo &&
|
|
806
|
+
objectSchema?.objectType !== 'user' &&
|
|
807
|
+
objectSchema?.generatedBy !== 'systemNoUser';
|
|
808
|
+
|
|
809
|
+
if (!isRootRbacObject) {
|
|
810
|
+
return;
|
|
811
|
+
}
|
|
812
|
+
|
|
813
|
+
try {
|
|
814
|
+
const submittedByUserId =
|
|
815
|
+
requestParams.submittedByUserId ||
|
|
816
|
+
_izContext.correlationIds?.get(coreConsts.SUBMITTED_BY_USER_ID);
|
|
817
|
+
|
|
818
|
+
if (submittedByUserId) {
|
|
819
|
+
const targetIdentKeys = Object.entries(identifiersForCreateData)
|
|
820
|
+
.map(([k, v]) => `${k}#${v}`)
|
|
821
|
+
.join('|');
|
|
822
|
+
const targetIdentifiersConcat =
|
|
823
|
+
targetIdentKeys ||
|
|
824
|
+
(identifiersForCreateData[Object.keys(identifiersForCreateData)[0]]
|
|
825
|
+
? `${Object.keys(identifiersForCreateData)[0]}#${identifiersForCreateData[Object.keys(identifiersForCreateData)[0]]}`
|
|
826
|
+
: '');
|
|
827
|
+
|
|
828
|
+
if (targetIdentifiersConcat) {
|
|
829
|
+
const roleIdKey = `${targetIdentifiersConcat}_owner`;
|
|
830
|
+
_izContext.logger.debug(
|
|
831
|
+
'[<%- flowTag %>LogicalLib] Auto-provisioning owner TargetRole for DynamoDB-only:',
|
|
832
|
+
{
|
|
833
|
+
identifiersConcat: targetIdentifiersConcat,
|
|
834
|
+
roleIdKey,
|
|
835
|
+
submittedByUserId,
|
|
836
|
+
roleName: 'owner'
|
|
837
|
+
}
|
|
838
|
+
);
|
|
839
|
+
|
|
840
|
+
await dynamodbSharedLib.putItem(
|
|
841
|
+
_izContext,
|
|
842
|
+
dynamodbSharedLib.tableName(_izContext, 'TargetRoles'),
|
|
843
|
+
{
|
|
844
|
+
identifiersConcat: targetIdentifiersConcat,
|
|
845
|
+
roleIdKey,
|
|
846
|
+
submittedByUserId,
|
|
847
|
+
roleName: 'owner',
|
|
848
|
+
assignedAt: new Date().toISOString()
|
|
849
|
+
}
|
|
850
|
+
);
|
|
851
|
+
|
|
852
|
+
await dynamodbSharedLib.transactWriteItems(_izContext, [
|
|
853
|
+
{
|
|
854
|
+
action: 'put',
|
|
855
|
+
params: {
|
|
856
|
+
tableName: dynamodbSharedLib.tableName(
|
|
857
|
+
_izContext,
|
|
858
|
+
'RoleUsers'
|
|
859
|
+
),
|
|
860
|
+
attributes: {
|
|
861
|
+
roleIdKey,
|
|
862
|
+
userId: submittedByUserId,
|
|
863
|
+
submittedByUserId
|
|
864
|
+
}
|
|
865
|
+
}
|
|
866
|
+
},
|
|
867
|
+
{
|
|
868
|
+
action: 'put',
|
|
869
|
+
params: {
|
|
870
|
+
tableName: dynamodbSharedLib.tableName(
|
|
871
|
+
_izContext,
|
|
872
|
+
'UserRoles'
|
|
873
|
+
),
|
|
874
|
+
attributes: {
|
|
875
|
+
userId: submittedByUserId,
|
|
876
|
+
roleIdKey,
|
|
877
|
+
submittedByUserId
|
|
878
|
+
}
|
|
879
|
+
}
|
|
880
|
+
},
|
|
881
|
+
{
|
|
882
|
+
action: 'put',
|
|
883
|
+
params: {
|
|
884
|
+
tableName: dynamodbSharedLib.tableName(
|
|
885
|
+
_izContext,
|
|
886
|
+
'RolePermissions'
|
|
887
|
+
),
|
|
888
|
+
attributes: {
|
|
889
|
+
roleIdKey,
|
|
890
|
+
flowTypeConcat: `${process.env.iz_serviceTag}_Update`,
|
|
891
|
+
permission: true,
|
|
892
|
+
allow: 'accept',
|
|
893
|
+
parameterGroups: {},
|
|
894
|
+
submittedByUserId
|
|
895
|
+
}
|
|
896
|
+
}
|
|
897
|
+
},
|
|
898
|
+
{
|
|
899
|
+
action: 'put',
|
|
900
|
+
params: {
|
|
901
|
+
tableName: dynamodbSharedLib.tableName(
|
|
902
|
+
_izContext,
|
|
903
|
+
'RolePermissions'
|
|
904
|
+
),
|
|
905
|
+
attributes: {
|
|
906
|
+
roleIdKey,
|
|
907
|
+
flowTypeConcat: `${process.env.iz_serviceTag}_Delete`,
|
|
908
|
+
permission: true,
|
|
909
|
+
allow: 'accept',
|
|
910
|
+
parameterGroups: {},
|
|
911
|
+
submittedByUserId
|
|
912
|
+
}
|
|
913
|
+
}
|
|
914
|
+
}
|
|
915
|
+
]);
|
|
916
|
+
}
|
|
917
|
+
}
|
|
918
|
+
} catch (roleError) {
|
|
919
|
+
_izContext.logger.error(
|
|
920
|
+
'[<%- flowTag %>LogicalLib] Failed to auto-provision owner TargetRole for DynamoDB-only:',
|
|
921
|
+
{ roleError }
|
|
922
|
+
);
|
|
923
|
+
}
|
|
924
|
+
}
|
|
925
|
+
|
|
926
|
+
/**
|
|
927
|
+
* Resolves callback properties to attach to Graph dispatch message
|
|
928
|
+
* @param {Object} phaseResults - Results from previous phases
|
|
929
|
+
* @param {Object} requestParams - Request parameters
|
|
930
|
+
* @returns {Object} Formatted callback properties
|
|
931
|
+
*/
|
|
932
|
+
export function resolveCallbackRbacProperties(phaseResults, requestParams) {
|
|
933
|
+
const uniqueIdentify =
|
|
934
|
+
phaseResults?.uniqueIdentify ||
|
|
935
|
+
Object.values(phaseResults || {}).find(
|
|
936
|
+
(r) => r?.returnValue?.uniqueIdentify
|
|
937
|
+
)?.returnValue?.uniqueIdentify;
|
|
938
|
+
|
|
939
|
+
const rbacType =
|
|
940
|
+
phaseResults?.rbacType ||
|
|
941
|
+
phaseResults?.target?.rbacType ||
|
|
942
|
+
phaseResults?.target?.returnValue?.rbacType ||
|
|
943
|
+
phaseResults?.app?.rbacType ||
|
|
944
|
+
phaseResults?.app?.returnValue?.rbacType ||
|
|
945
|
+
Object.values(phaseResults || {}).find(
|
|
946
|
+
(r) => r?.rbacType || r?.returnValue?.rbacType
|
|
947
|
+
)?.rbacType;
|
|
948
|
+
|
|
949
|
+
return {
|
|
950
|
+
uniqueIdentify,
|
|
951
|
+
targetIdentifiers: requestParams?.targetIdentifiers,
|
|
952
|
+
rbacType,
|
|
953
|
+
phaseResults
|
|
954
|
+
};
|
|
955
|
+
}
|
|
956
|
+
|
|
957
|
+
/**
|
|
958
|
+
* Dispatches node creation request to Graph Service
|
|
959
|
+
* @param {Object} _izContext - Izara context object
|
|
960
|
+
* @param {Object} options - Graph dispatch configuration
|
|
961
|
+
* @returns {Promise<void>}
|
|
962
|
+
*/
|
|
963
|
+
export async function dispatchToGraphEngine(
|
|
964
|
+
_izContext,
|
|
965
|
+
{
|
|
966
|
+
objType,
|
|
967
|
+
objectForCreate,
|
|
968
|
+
graphServiceName,
|
|
969
|
+
requestParams,
|
|
970
|
+
parentFlowId,
|
|
971
|
+
callingFlowConfig,
|
|
972
|
+
phaseResults
|
|
973
|
+
}
|
|
974
|
+
) {
|
|
975
|
+
let messageObject = {
|
|
976
|
+
objType,
|
|
977
|
+
objInstanceFull: objectForCreate.objInstanceFull,
|
|
978
|
+
deepPathConditional: requestParams.deepPathConditional || [],
|
|
979
|
+
setFieldConditionals: requestParams.setFieldConditionals || [],
|
|
980
|
+
relationships: requestParams.relationships || [],
|
|
981
|
+
targetIdentifiers: requestParams.targetIdentifiers,
|
|
982
|
+
parentFlowId: parentFlowId,
|
|
983
|
+
settings: { updatePropertiesOnMatch: false },
|
|
984
|
+
originTimestamp: Date.now()
|
|
985
|
+
};
|
|
986
|
+
|
|
987
|
+
const callbackProps = resolveCallbackRbacProperties(
|
|
988
|
+
phaseResults,
|
|
989
|
+
requestParams
|
|
990
|
+
);
|
|
991
|
+
|
|
992
|
+
messageObject =
|
|
993
|
+
callingFlowSharedLib.addCallingFlowToSnsRequestMessageObject(
|
|
994
|
+
messageObject,
|
|
995
|
+
callingFlowSharedLib.addParentCallingFlowConfig(
|
|
996
|
+
callingFlowConfig,
|
|
997
|
+
callingFlowSharedLib.createCallingFlowConfig(
|
|
998
|
+
//(<callingFlowProperties>)
|
|
999
|
+
await lambdaSharedLib.lambdaFunctionName(
|
|
1000
|
+
_izContext,
|
|
1001
|
+
<% if (plan.hasCreateNodeCallback) { -%>
|
|
1002
|
+
'CreateNodeCallbackHdrSqs'
|
|
1003
|
+
<% } else { -%>
|
|
1004
|
+
TOPIC_NAME_GENERATE_CODE.createNodeComplete
|
|
1005
|
+
<% } -%>
|
|
1006
|
+
),
|
|
1007
|
+
<% if (plan.hasCreateNodeCallback) { -%>
|
|
1008
|
+
callbackProps
|
|
1009
|
+
<% } else { -%>
|
|
1010
|
+
{}
|
|
1011
|
+
<% } -%>
|
|
1012
|
+
//(</callingFlowProperties>)
|
|
1013
|
+
)
|
|
1014
|
+
)
|
|
1015
|
+
);
|
|
1016
|
+
|
|
1017
|
+
_izContext.logger.debug(
|
|
1018
|
+
`[${process.env.iz_serviceTag}:<%- flowTag %>LogicalLib] message to graph:`,
|
|
1019
|
+
{
|
|
1020
|
+
graphServiceName,
|
|
1021
|
+
messageObject
|
|
1022
|
+
}
|
|
1023
|
+
);
|
|
1024
|
+
|
|
1025
|
+
await sns.publishAsync(_izContext, {
|
|
1026
|
+
Message: JSON.stringify(messageObject),
|
|
1027
|
+
TopicArn: snsSharedLib.snsTopicArnByFlowSchema(
|
|
1028
|
+
_izContext,
|
|
1029
|
+
TOPIC_NAME_GRAPH_HANDLER.inCreateNode,
|
|
1030
|
+
graphServiceName
|
|
1031
|
+
)
|
|
1032
|
+
});
|
|
1033
|
+
}
|
|
1034
|
+
|
|
1035
|
+
/**
|
|
1036
|
+
* Handles creation errors and publishes error response
|
|
1037
|
+
* @param {Object} _izContext - Izara context object
|
|
1038
|
+
* @param {Object} options - Error context details
|
|
1039
|
+
* @returns {Promise<Object>} Error status result
|
|
1040
|
+
*/
|
|
1041
|
+
export async function handleCreateError(
|
|
1042
|
+
_izContext,
|
|
1043
|
+
{
|
|
1044
|
+
objType,
|
|
1045
|
+
objInstanceFull,
|
|
1046
|
+
requestParams,
|
|
1047
|
+
callingFlowConfig,
|
|
1048
|
+
errorsFound
|
|
1049
|
+
}
|
|
1050
|
+
) {
|
|
1051
|
+
_izContext.logger.debug(`[${process.env.iz_serviceTag}:<%- flowTag %>LogicalLib] errorsFound:`, errorsFound);
|
|
1052
|
+
|
|
1053
|
+
await asyncFlowSharedLib.clearAllAwaitingSteps(
|
|
1054
|
+
_izContext,
|
|
1055
|
+
asyncFlowSharedLib.createPendingStepId(
|
|
1056
|
+
_izContext.uniqueRequestId,
|
|
1057
|
+
PREFIX.CREATE_OBJECT_ASYNC_COMPLETE
|
|
1058
|
+
)
|
|
1059
|
+
);
|
|
1060
|
+
|
|
1061
|
+
const messageObject =
|
|
1062
|
+
callingFlowSharedLib.addPassBackPropertiesToSnsResponseMessageObject(
|
|
1063
|
+
callingFlowConfig,
|
|
1064
|
+
{ objType, identifiers: null, errorsFound }
|
|
1065
|
+
);
|
|
1066
|
+
|
|
1067
|
+
await sns.publishAsync(_izContext, {
|
|
1068
|
+
Message: JSON.stringify(messageObject),
|
|
1069
|
+
MessageAttributes: sns.createStringMessageAttributes(
|
|
1070
|
+
_izContext,
|
|
1071
|
+
callingFlowSharedLib.addCallingFlowToSnsResponseMessageAttributes(
|
|
1072
|
+
callingFlowConfig,
|
|
1073
|
+
{}
|
|
1074
|
+
)
|
|
1075
|
+
),
|
|
1076
|
+
TopicArn: snsSharedLib.snsTopicArnByFlowSchema(
|
|
1077
|
+
_izContext,
|
|
1078
|
+
TOPIC_NAME_GENERATE_CODE.outCreateNodeComplete
|
|
1079
|
+
)
|
|
1080
|
+
});
|
|
1081
|
+
|
|
1082
|
+
return {
|
|
1083
|
+
objType,
|
|
1084
|
+
objInstanceFull,
|
|
1085
|
+
relationships: requestParams.relationships || [],
|
|
1086
|
+
targetIdentifiers: requestParams.targetIdentifiers,
|
|
1087
|
+
status: 'error',
|
|
1088
|
+
errorsFound
|
|
1089
|
+
};
|
|
1090
|
+
}
|
|
1091
|
+
|
|
1092
|
+
/**
|
|
1093
|
+
* Handles DynamoDB-only complete notification when no Graph callback is required
|
|
1094
|
+
* @param {Object} _izContext - Izara context object
|
|
1095
|
+
* @param {Object} options - Completion parameters
|
|
1096
|
+
* @returns {Promise<void>}
|
|
1097
|
+
*/
|
|
1098
|
+
export async function handleDynamoDbOnlyComplete(
|
|
1099
|
+
_izContext,
|
|
1100
|
+
{
|
|
1101
|
+
objType,
|
|
1102
|
+
objInstanceFullForDynamoDb,
|
|
1103
|
+
callingFlowConfig
|
|
1104
|
+
}
|
|
1105
|
+
) {
|
|
1106
|
+
const outMessage =
|
|
1107
|
+
callingFlowSharedLib.addPassBackPropertiesToSnsResponseMessageObject(
|
|
1108
|
+
callingFlowConfig,
|
|
1109
|
+
{
|
|
1110
|
+
objType: objType,
|
|
1111
|
+
objInstanceFull: {
|
|
1112
|
+
identifiers: objInstanceFullForDynamoDb.identifiers,
|
|
1113
|
+
fields: objInstanceFullForDynamoDb.fields
|
|
1114
|
+
}
|
|
1115
|
+
}
|
|
1116
|
+
);
|
|
1117
|
+
|
|
1118
|
+
if (
|
|
1119
|
+
callingFlowConfig[callingFlowSharedLib.consts.CALLINGFLOW_PROPERTYNAME]
|
|
1120
|
+
) {
|
|
1121
|
+
_izContext.logger.debug('HAVE CallingFlow');
|
|
1122
|
+
await sns.publishAsync(_izContext, {
|
|
1123
|
+
Message: JSON.stringify(outMessage),
|
|
1124
|
+
MessageAttributes: sns.createStringMessageAttributes(
|
|
1125
|
+
_izContext,
|
|
1126
|
+
callingFlowSharedLib.addCallingFlowToSnsResponseMessageAttributes(
|
|
1127
|
+
callingFlowConfig,
|
|
1128
|
+
{}
|
|
1129
|
+
)
|
|
1130
|
+
),
|
|
1131
|
+
TopicArn: snsSharedLib.snsTopicArnByFlowSchema(
|
|
1132
|
+
_izContext,
|
|
1133
|
+
TOPIC_NAME_GENERATE_CODE.outCreateNodeComplete
|
|
1134
|
+
)
|
|
1135
|
+
});
|
|
1136
|
+
}
|
|
1137
|
+
}
|
|
1138
|
+
|
|
1139
|
+
// ── 6. Main Logical Function ──────────────────────────────────────────────────
|
|
1140
|
+
|
|
1141
|
+
/**
|
|
1142
|
+
* Core logical processing library for <%- flowTag %> flow
|
|
66
1143
|
* @param {Object} _izContext - Context object with logger
|
|
67
|
-
* @param {Object} requestParams - { fieldNames, relationships[] }
|
|
1144
|
+
* @param {Object} requestParams - Request parameters { fieldNames, relationships[] }
|
|
68
1145
|
* @param {Object} callingFlowConfig - Calling flow configuration
|
|
1146
|
+
* @param {Array<string>} errorsFound - Array of preceding errors
|
|
69
1147
|
* @param {Object} phaseResults - Results from preceding phases
|
|
70
1148
|
* @returns {Promise<Object>} Result with objType, objInstanceFull, relationships, status, errorsFound
|
|
71
1149
|
*/
|
|
@@ -77,56 +1155,33 @@ export async function <%- flowTag %>LogicalLib(
|
|
|
77
1155
|
phaseResults = {}
|
|
78
1156
|
) {
|
|
79
1157
|
try {
|
|
80
|
-
_izContext.logger.debug(
|
|
1158
|
+
_izContext.logger.debug(`[${process.env.iz_serviceTag}:<%- flowTag %>LogicalLib] started`, {
|
|
81
1159
|
requestParams,
|
|
82
1160
|
callingFlowConfig,
|
|
83
|
-
phaseResults
|
|
1161
|
+
phaseResults,
|
|
1162
|
+
targetIdentifiers: requestParams.targetIdentifiers
|
|
84
1163
|
});
|
|
85
1164
|
|
|
86
1165
|
//(<beforeCreateMainLogical>)
|
|
87
1166
|
//(</beforeCreateMainLogical>)
|
|
88
1167
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
const objectSchema = await getObjectSchema.getObjSchemaS3WithHierarchy(
|
|
93
|
-
_izContext,
|
|
94
|
-
objType
|
|
95
|
-
);
|
|
96
|
-
_izContext.logger.debug('objectSchema', objectSchema);
|
|
1168
|
+
// 1. Load and resolve Schema
|
|
1169
|
+
const { objType, objectSchema, objectSchemas, parentObject } =
|
|
1170
|
+
await resolveObjectSchemas(_izContext, requestParams.objectType);
|
|
97
1171
|
|
|
98
|
-
const objectSchemas =
|
|
99
|
-
uploadUseCase.generateObjectSchemaForCombineFieldNames(
|
|
100
|
-
_izContext,
|
|
101
|
-
objectSchema
|
|
102
|
-
);
|
|
103
|
-
_izContext.logger.debug('objectSchemas', objectSchemas);
|
|
104
|
-
|
|
105
|
-
// ── Parent object ─────────────────────────────────────────────────────────
|
|
106
|
-
let parentObject;
|
|
107
|
-
if (objectSchemas.hasOwnProperty('extendObjType')) {
|
|
108
|
-
parentObject = await getObjectSchema.getObjSchemaS3WithHierarchy(
|
|
109
|
-
_izContext,
|
|
110
|
-
objectSchema.extendObjType
|
|
111
|
-
);
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
// ── Detect invocation type ────────────────────────────────────────────────
|
|
115
1172
|
const directInvoke =
|
|
116
1173
|
requestParams.hasOwnProperty('__context__') &&
|
|
117
1174
|
requestParams.izEventSource?.eventSourceTag === 'DirectInvoke';
|
|
118
1175
|
|
|
119
|
-
// ── Build createDataDetails ───────────────────────────────────────────────
|
|
120
1176
|
const createDataDetails = await createDataDetailsLib(
|
|
121
1177
|
_izContext,
|
|
122
1178
|
objectSchemas
|
|
123
1179
|
);
|
|
124
|
-
_izContext.logger.debug(
|
|
1180
|
+
_izContext.logger.debug(`[${process.env.iz_serviceTag}:<%- flowTag %>LogicalLib] createDataDetails:`, createDataDetails);
|
|
125
1181
|
|
|
126
|
-
//
|
|
1182
|
+
// 2. Prepare objInstanceFull
|
|
127
1183
|
const objInstanceFull = { identifiers: {}, fields: {} };
|
|
128
|
-
|
|
129
|
-
for (const fieldName of Object.keys(requestParams.fieldNames)) {
|
|
1184
|
+
for (const fieldName of Object.keys(requestParams.fieldNames || {})) {
|
|
130
1185
|
if (objectSchemas.identifierFieldNames.includes(fieldName)) {
|
|
131
1186
|
Object.assign(objInstanceFull.identifiers, {
|
|
132
1187
|
[fieldName]: requestParams.fieldNames[fieldName]
|
|
@@ -134,29 +1189,6 @@ export async function <%- flowTag %>LogicalLib(
|
|
|
134
1189
|
}
|
|
135
1190
|
}
|
|
136
1191
|
|
|
137
|
-
// ── Helper: extract fields per storageTag ─────────────────────────────────
|
|
138
|
-
function createObjInstanceFullFieldsByStorageTag(
|
|
139
|
-
_izContext,
|
|
140
|
-
storageTag,
|
|
141
|
-
createDataDetail
|
|
142
|
-
) {
|
|
143
|
-
const fields = {};
|
|
144
|
-
for (const fieldName of Object.keys(requestParams.fieldNames)) {
|
|
145
|
-
if (
|
|
146
|
-
createDataDetails[storageTag].fieldNames.includes(fieldName) &&
|
|
147
|
-
createDataDetail.fieldNames.includes(fieldName) &&
|
|
148
|
-
!objInstanceFull.identifiers.hasOwnProperty(fieldName) &&
|
|
149
|
-
!fields.hasOwnProperty(fieldName)
|
|
150
|
-
) {
|
|
151
|
-
Object.assign(fields, {
|
|
152
|
-
[fieldName]: requestParams.fieldNames[fieldName]
|
|
153
|
-
});
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
return fields;
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
// ── Process storage resources ─────────────────────────────────────────────
|
|
160
1192
|
const objInstanceFullForDynamoDb = structuredClone(objInstanceFull);
|
|
161
1193
|
const objInstanceFullForGraph = structuredClone(objInstanceFull);
|
|
162
1194
|
const objInstanceFullForExternalTopic = structuredClone(objInstanceFull);
|
|
@@ -165,19 +1197,22 @@ export async function <%- flowTag %>LogicalLib(
|
|
|
165
1197
|
const listOfObjectForCreates = [];
|
|
166
1198
|
const listOfRecords = [];
|
|
167
1199
|
|
|
1200
|
+
// 3. Process storage resources
|
|
168
1201
|
if (errorsFound.length === 0) {
|
|
169
1202
|
//(<validateBeforeCreate>)
|
|
170
1203
|
//(</validateBeforeCreate>)
|
|
171
1204
|
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
)
|
|
1205
|
+
const hasGraphStorage = Object.values(createDataDetails).some(
|
|
1206
|
+
(detail) => detail.storageType === consts.STORAGE_TYPES.graph
|
|
1207
|
+
);
|
|
1208
|
+
|
|
1209
|
+
for (const [storageTag, createDataDetail] of Object.entries(createDataDetails)) {
|
|
175
1210
|
//(<beforeCreate>)
|
|
176
1211
|
//(</beforeCreate>)
|
|
177
1212
|
|
|
178
|
-
// ── DynamoDB
|
|
1213
|
+
// ── DynamoDB ──
|
|
179
1214
|
if (createDataDetail.storageType === consts.STORAGE_TYPES.dynamoDB) {
|
|
180
|
-
_izContext.logger.debug(
|
|
1215
|
+
_izContext.logger.debug(`[${process.env.iz_serviceTag}:<%- flowTag %>LogicalLib] DynamoDB:`, {
|
|
181
1216
|
storageTag,
|
|
182
1217
|
objInstanceFull
|
|
183
1218
|
});
|
|
@@ -196,18 +1231,16 @@ export async function <%- flowTag %>LogicalLib(
|
|
|
196
1231
|
|
|
197
1232
|
Object.assign(
|
|
198
1233
|
objInstanceFullForDynamoDb.fields,
|
|
199
|
-
|
|
1234
|
+
extractFieldsByStorageTag(
|
|
200
1235
|
_izContext,
|
|
201
1236
|
storageTag,
|
|
202
|
-
|
|
1237
|
+
createDataDetails,
|
|
1238
|
+
createDataDetail,
|
|
1239
|
+
requestParams,
|
|
1240
|
+
objInstanceFull
|
|
203
1241
|
)
|
|
204
1242
|
);
|
|
205
1243
|
|
|
206
|
-
_izContext.logger.debug(
|
|
207
|
-
'objInstanceFull before create item in dynamoDB',
|
|
208
|
-
objInstanceFullForDynamoDb
|
|
209
|
-
);
|
|
210
|
-
|
|
211
1244
|
const identifiersForCreateData =
|
|
212
1245
|
await dynamoDbIdentifiersByStorageResource(
|
|
213
1246
|
_izContext,
|
|
@@ -215,20 +1248,11 @@ export async function <%- flowTag %>LogicalLib(
|
|
|
215
1248
|
createDataDetails,
|
|
216
1249
|
objInstanceFullForDynamoDb.identifiers
|
|
217
1250
|
);
|
|
218
|
-
_izContext.logger.debug(
|
|
219
|
-
'identifiersForCreateData',
|
|
220
|
-
identifiersForCreateData
|
|
221
|
-
);
|
|
222
1251
|
|
|
223
1252
|
//(<beforeCreateRecordDynamo>)
|
|
224
1253
|
//(</beforeCreateRecordDynamo>)
|
|
225
1254
|
|
|
226
|
-
if (
|
|
227
|
-
Object.values(createDataDetails).some(
|
|
228
|
-
(createDataDetail) =>
|
|
229
|
-
createDataDetail.storageType === consts.STORAGE_TYPES.graph
|
|
230
|
-
)
|
|
231
|
-
) {
|
|
1255
|
+
if (hasGraphStorage) {
|
|
232
1256
|
_izContext.logger.debug('must process graph first');
|
|
233
1257
|
listOfRecords.push({
|
|
234
1258
|
[storageTag]: {
|
|
@@ -256,34 +1280,39 @@ export async function <%- flowTag %>LogicalLib(
|
|
|
256
1280
|
);
|
|
257
1281
|
|
|
258
1282
|
objInstanceFullForDynamoDb.fields = {};
|
|
1283
|
+
|
|
1284
|
+
// Auto-provision owner TargetRole for DynamoDB-only
|
|
1285
|
+
await autoProvisionOwnerTargetRoleForDynamoOnly(_izContext, {
|
|
1286
|
+
objectSchema,
|
|
1287
|
+
identifiersForCreateData,
|
|
1288
|
+
requestParams
|
|
1289
|
+
});
|
|
259
1290
|
}
|
|
260
1291
|
|
|
261
1292
|
//(<afterCreateRecordDynamo>)
|
|
262
1293
|
//(</afterCreateRecordDynamo>)
|
|
263
1294
|
|
|
264
|
-
|
|
265
|
-
} else if (
|
|
266
|
-
createDataDetail.storageType === consts.STORAGE_TYPES.graph
|
|
267
|
-
) {
|
|
1295
|
+
// ── Graph ──
|
|
1296
|
+
} else if (createDataDetail.storageType === consts.STORAGE_TYPES.graph) {
|
|
268
1297
|
//(<beforeCreateNode>)
|
|
269
1298
|
//(</beforeCreateNode>)
|
|
270
|
-
|
|
1299
|
+
|
|
1300
|
+
_izContext.logger.debug(`[${process.env.iz_serviceTag}:<%- flowTag %>LogicalLib] Graph:`, {
|
|
271
1301
|
storageTag,
|
|
272
1302
|
objInstanceFull
|
|
273
1303
|
});
|
|
274
1304
|
|
|
275
1305
|
Object.assign(
|
|
276
1306
|
objInstanceFullForGraph.fields,
|
|
277
|
-
|
|
1307
|
+
extractFieldsByStorageTag(
|
|
278
1308
|
_izContext,
|
|
279
1309
|
storageTag,
|
|
280
|
-
|
|
1310
|
+
createDataDetails,
|
|
1311
|
+
createDataDetail,
|
|
1312
|
+
requestParams,
|
|
1313
|
+
objInstanceFull
|
|
281
1314
|
)
|
|
282
1315
|
);
|
|
283
|
-
_izContext.logger.debug(
|
|
284
|
-
'objInstanceFull before send to Graph',
|
|
285
|
-
objInstanceFullForGraph
|
|
286
|
-
);
|
|
287
1316
|
|
|
288
1317
|
//(<additionalAttributeCreateNode>)
|
|
289
1318
|
const additionalAttributes = {};
|
|
@@ -311,29 +1340,22 @@ export async function <%- flowTag %>LogicalLib(
|
|
|
311
1340
|
}
|
|
312
1341
|
});
|
|
313
1342
|
|
|
314
|
-
|
|
315
|
-
} else if (
|
|
316
|
-
createDataDetail.storageType === consts.STORAGE_TYPES.externalTopic
|
|
317
|
-
) {
|
|
318
|
-
_izContext.logger.debug('::::::externalTopic::::::', {
|
|
319
|
-
storageTag,
|
|
320
|
-
createDataDetail
|
|
321
|
-
});
|
|
1343
|
+
// ── External Topic ──
|
|
1344
|
+
} else if (createDataDetail.storageType === consts.STORAGE_TYPES.externalTopic) {
|
|
322
1345
|
//(<beforeSendMessageToExternalTopic>)
|
|
323
1346
|
//(</beforeSendMessageToExternalTopic>)
|
|
324
1347
|
|
|
325
1348
|
Object.assign(
|
|
326
1349
|
objInstanceFullForExternalTopic.fields,
|
|
327
|
-
|
|
1350
|
+
extractFieldsByStorageTag(
|
|
328
1351
|
_izContext,
|
|
329
1352
|
storageTag,
|
|
330
|
-
|
|
1353
|
+
createDataDetails,
|
|
1354
|
+
createDataDetail,
|
|
1355
|
+
requestParams,
|
|
1356
|
+
objInstanceFull
|
|
331
1357
|
)
|
|
332
1358
|
);
|
|
333
|
-
_izContext.logger.debug(
|
|
334
|
-
'objInstanceFull before send to external topic',
|
|
335
|
-
objInstanceFullForExternalTopic
|
|
336
|
-
);
|
|
337
1359
|
|
|
338
1360
|
allAwaitingStepsId.push({
|
|
339
1361
|
awaitingStepId: await asyncFlowSharedLib.createAwaitingStepId(
|
|
@@ -355,9 +1377,8 @@ export async function <%- flowTag %>LogicalLib(
|
|
|
355
1377
|
}
|
|
356
1378
|
}
|
|
357
1379
|
|
|
358
|
-
//
|
|
1380
|
+
// 4. Create awaiting multiple steps
|
|
359
1381
|
if (allAwaitingStepsId.length > 0) {
|
|
360
|
-
_izContext.logger.debug('not api will create awaitingStep');
|
|
361
1382
|
await asyncFlowSharedLib.createAwaitingMultipleSteps(
|
|
362
1383
|
_izContext,
|
|
363
1384
|
asyncFlowSharedLib.createPendingStepId(
|
|
@@ -373,153 +1394,57 @@ export async function <%- flowTag %>LogicalLib(
|
|
|
373
1394
|
);
|
|
374
1395
|
}
|
|
375
1396
|
|
|
376
|
-
//
|
|
377
|
-
let messageObject = {};
|
|
1397
|
+
// 5. Dispatch to Graph Service
|
|
378
1398
|
for (const objectCreate of listOfObjectForCreates) {
|
|
379
|
-
for (const [graphServiceName, objectForCreate] of Object.entries(
|
|
380
|
-
|
|
381
|
-
)) {
|
|
382
|
-
_izContext.logger.debug('Loop each graph:', {
|
|
383
|
-
[graphServiceName]: objectForCreate
|
|
384
|
-
});
|
|
385
|
-
|
|
386
|
-
if (!objectForCreate.allStorageTagComplete) {
|
|
1399
|
+
for (const [graphServiceName, objectForCreate] of Object.entries(objectCreate)) {
|
|
1400
|
+
if (!objectForCreate.allStorageTagComplete && errorsFound.length === 0) {
|
|
387
1401
|
//(<beforeSendMessageToGraph>)
|
|
388
1402
|
//(</beforeSendMessageToGraph>)
|
|
389
|
-
|
|
1403
|
+
|
|
1404
|
+
await dispatchToGraphEngine(_izContext, {
|
|
1405
|
+
objType,
|
|
1406
|
+
objectForCreate,
|
|
1407
|
+
graphServiceName,
|
|
1408
|
+
requestParams,
|
|
1409
|
+
parentFlowId,
|
|
1410
|
+
callingFlowConfig,
|
|
1411
|
+
phaseResults
|
|
1412
|
+
});
|
|
1413
|
+
|
|
1414
|
+
//(<afterSendMessageToGraph>)
|
|
1415
|
+
//(</afterSendMessageToGraph>)
|
|
1416
|
+
|
|
1417
|
+
return {
|
|
390
1418
|
objType,
|
|
391
|
-
objInstanceFull:
|
|
392
|
-
deepPathConditional: requestParams.deepPathConditional || [],
|
|
393
|
-
setFieldConditionals: requestParams.setFieldConditionals || [],
|
|
1419
|
+
objInstanceFull: objInstanceFullForGraph,
|
|
394
1420
|
relationships: requestParams.relationships || [],
|
|
395
|
-
|
|
1421
|
+
targetIdentifiers: requestParams.targetIdentifiers,
|
|
1422
|
+
status: 'complete',
|
|
1423
|
+
errorsFound
|
|
396
1424
|
};
|
|
397
1425
|
}
|
|
398
|
-
|
|
399
|
-
if (errorsFound.length > 0) break;
|
|
400
|
-
|
|
401
|
-
Object.assign(messageObject, {
|
|
402
|
-
settings: { updatePropertiesOnMatch: false },
|
|
403
|
-
originTimestamp: Date.now()
|
|
404
|
-
});
|
|
405
|
-
|
|
406
|
-
messageObject =
|
|
407
|
-
callingFlowSharedLib.addCallingFlowToSnsRequestMessageObject(
|
|
408
|
-
messageObject,
|
|
409
|
-
callingFlowSharedLib.addParentCallingFlowConfig(
|
|
410
|
-
callingFlowConfig,
|
|
411
|
-
callingFlowSharedLib.createCallingFlowConfig(
|
|
412
|
-
//(<callingFlowProperties>)
|
|
413
|
-
await lambdaSharedLib.lambdaFunctionName(
|
|
414
|
-
_izContext,
|
|
415
|
-
TOPIC_NAME_GENERATE_CODE.createNodeComplete
|
|
416
|
-
),
|
|
417
|
-
{}
|
|
418
|
-
//(</callingFlowProperties>)
|
|
419
|
-
)
|
|
420
|
-
)
|
|
421
|
-
);
|
|
422
|
-
|
|
423
|
-
await sns.publishAsync(_izContext, {
|
|
424
|
-
Message: JSON.stringify(messageObject),
|
|
425
|
-
TopicArn: snsSharedLib.snsTopicArnByFlowSchema(
|
|
426
|
-
_izContext,
|
|
427
|
-
TOPIC_NAME_GRAPH_HANDLER.inCreateNode,
|
|
428
|
-
graphServiceName
|
|
429
|
-
)
|
|
430
|
-
});
|
|
431
|
-
|
|
432
|
-
//(<afterSendMessageToGraph>)
|
|
433
|
-
//(</afterSendMessageToGraph>)
|
|
434
|
-
return {
|
|
435
|
-
objType,
|
|
436
|
-
objInstanceFull: objInstanceFullForGraph,
|
|
437
|
-
relationships: requestParams.relationships || [],
|
|
438
|
-
status: 'complete',
|
|
439
|
-
errorsFound
|
|
440
|
-
};
|
|
441
1426
|
}
|
|
442
1427
|
if (errorsFound.length > 0) break;
|
|
443
1428
|
}
|
|
444
1429
|
|
|
445
|
-
//
|
|
1430
|
+
// 6. Handle Errors
|
|
446
1431
|
if (errorsFound.length > 0) {
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
await asyncFlowSharedLib.clearAllAwaitingSteps(
|
|
450
|
-
_izContext,
|
|
451
|
-
asyncFlowSharedLib.createPendingStepId(
|
|
452
|
-
_izContext.uniqueRequestId,
|
|
453
|
-
PREFIX.CREATE_OBJECT_ASYNC_COMPLETE
|
|
454
|
-
)
|
|
455
|
-
);
|
|
456
|
-
|
|
457
|
-
messageObject =
|
|
458
|
-
callingFlowSharedLib.addPassBackPropertiesToSnsResponseMessageObject(
|
|
459
|
-
callingFlowConfig,
|
|
460
|
-
{ objType, identifiers: null, errorsFound }
|
|
461
|
-
);
|
|
462
|
-
|
|
463
|
-
await sns.publishAsync(_izContext, {
|
|
464
|
-
Message: JSON.stringify(messageObject),
|
|
465
|
-
MessageAttributes: sns.createStringMessageAttributes(
|
|
466
|
-
_izContext,
|
|
467
|
-
callingFlowSharedLib.addCallingFlowToSnsResponseMessageAttributes(
|
|
468
|
-
callingFlowConfig,
|
|
469
|
-
{}
|
|
470
|
-
)
|
|
471
|
-
),
|
|
472
|
-
TopicArn: snsSharedLib.snsTopicArnByFlowSchema(
|
|
473
|
-
_izContext,
|
|
474
|
-
TOPIC_NAME_GENERATE_CODE.outCreateNodeComplete
|
|
475
|
-
)
|
|
476
|
-
});
|
|
477
|
-
|
|
478
|
-
return {
|
|
1432
|
+
return await handleCreateError(_izContext, {
|
|
479
1433
|
objType,
|
|
480
1434
|
objInstanceFull,
|
|
481
|
-
|
|
482
|
-
|
|
1435
|
+
requestParams,
|
|
1436
|
+
callingFlowConfig,
|
|
483
1437
|
errorsFound
|
|
484
|
-
};
|
|
1438
|
+
});
|
|
485
1439
|
}
|
|
486
1440
|
|
|
487
|
-
//
|
|
488
|
-
if (
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
callingFlowConfig,
|
|
495
|
-
{
|
|
496
|
-
objType: objType,
|
|
497
|
-
objInstanceFull: {
|
|
498
|
-
identifiers: objInstanceFullForDynamoDb.identifiers,
|
|
499
|
-
fields: objInstanceFullForDynamoDb.fields
|
|
500
|
-
}
|
|
501
|
-
}
|
|
502
|
-
);
|
|
503
|
-
|
|
504
|
-
if (
|
|
505
|
-
callingFlowConfig[callingFlowSharedLib.consts.CALLINGFLOW_PROPERTYNAME]
|
|
506
|
-
) {
|
|
507
|
-
_izContext.logger.debug('HAVE CallingFlow');
|
|
508
|
-
await sns.publishAsync(_izContext, {
|
|
509
|
-
Message: JSON.stringify(outMessage),
|
|
510
|
-
MessageAttributes: sns.createStringMessageAttributes(
|
|
511
|
-
_izContext,
|
|
512
|
-
callingFlowSharedLib.addCallingFlowToSnsResponseMessageAttributes(
|
|
513
|
-
callingFlowConfig,
|
|
514
|
-
{}
|
|
515
|
-
)
|
|
516
|
-
),
|
|
517
|
-
TopicArn: snsSharedLib.snsTopicArnByFlowSchema(
|
|
518
|
-
_izContext,
|
|
519
|
-
TOPIC_NAME_GENERATE_CODE.outCreateNodeComplete
|
|
520
|
-
)
|
|
521
|
-
});
|
|
522
|
-
}
|
|
1441
|
+
// 7. Handle DynamoDB-only Complete Path
|
|
1442
|
+
if (allAwaitingStepsId.length === 0 && listOfObjectForCreates.length === 0) {
|
|
1443
|
+
await handleDynamoDbOnlyComplete(_izContext, {
|
|
1444
|
+
objType,
|
|
1445
|
+
objInstanceFullForDynamoDb,
|
|
1446
|
+
callingFlowConfig
|
|
1447
|
+
});
|
|
523
1448
|
}
|
|
524
1449
|
|
|
525
1450
|
return {
|
|
@@ -529,10 +1454,12 @@ export async function <%- flowTag %>LogicalLib(
|
|
|
529
1454
|
fields: objInstanceFullForDynamoDb.fields
|
|
530
1455
|
},
|
|
531
1456
|
relationships: requestParams.relationships || [],
|
|
1457
|
+
targetIdentifiers: requestParams.targetIdentifiers,
|
|
532
1458
|
status: 'complete',
|
|
533
1459
|
errorsFound
|
|
534
1460
|
};
|
|
535
1461
|
} catch (err) {
|
|
1462
|
+
_izContext.logger.error(`[${process.env.iz_serviceTag}:<%- flowTag %>LogicalLib] error:`, err);
|
|
536
1463
|
throw err;
|
|
537
1464
|
}
|
|
538
1465
|
}
|