@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
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Copyright (C) 2021 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 asyncFlowSharedLib from '@izara_project/izara-core-library-asynchronous-flow';
|
|
19
|
+
import callingFlowSharedLib from '@izara_project/izara-core-library-calling-flow';
|
|
20
|
+
import dynamodbSharedLib from '@izara_project/izara-core-library-dynamodb';
|
|
21
|
+
import lambdaSharedLib from '@izara_project/izara-core-library-lambda';
|
|
22
|
+
import snsSharedLib from '@izara_project/izara-core-library-sns';
|
|
23
|
+
import { sns } from '@izara_project/izara-core-library-external-request';
|
|
24
|
+
import { consts } from '@izara_project/izara-core-library-service-schemas';
|
|
25
|
+
import {
|
|
26
|
+
consts as coreConsts,
|
|
27
|
+
NoRetryError
|
|
28
|
+
} from '@izara_project/izara-core-library-core';
|
|
29
|
+
|
|
30
|
+
import {
|
|
31
|
+
saveDynamoDbRecords,
|
|
32
|
+
autoProvisionOwnerTargetRole,
|
|
33
|
+
resolveQuotaDeductionKeys,
|
|
34
|
+
forwardToQuotaConfirmation
|
|
35
|
+
} from './CreateLogicalLib.js';
|
|
36
|
+
|
|
37
|
+
//(<optionalRequire>)
|
|
38
|
+
//(</optionalRequire>)
|
|
39
|
+
|
|
40
|
+
const PREFIX = { ASYNC: 'CreateAsyncEndpoint' };
|
|
41
|
+
|
|
42
|
+
function empty(value) {
|
|
43
|
+
return (
|
|
44
|
+
value == null ||
|
|
45
|
+
(typeof value === 'object' && Object.keys(value).length === 0)
|
|
46
|
+
);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function validateInput(returnValue, status, graphServiceTag, errorsFound) {
|
|
50
|
+
if (!returnValue?.queryResult)
|
|
51
|
+
errorsFound.push(
|
|
52
|
+
'message is not have property queryResult, should be not happen'
|
|
53
|
+
);
|
|
54
|
+
if (!returnValue?.requestParams?.objType)
|
|
55
|
+
errorsFound.push(
|
|
56
|
+
'message is not have property objType, should be not happen'
|
|
57
|
+
);
|
|
58
|
+
if (!returnValue?.requestParams?.objInstanceFull)
|
|
59
|
+
errorsFound.push(
|
|
60
|
+
'message is not have property objInstance, should be not objInstance'
|
|
61
|
+
);
|
|
62
|
+
if (status === 'error' && errorsFound.length === 0)
|
|
63
|
+
errorsFound.push(
|
|
64
|
+
'[invalid]status is error not have errorsFound form graphService'
|
|
65
|
+
);
|
|
66
|
+
if (status === 'complete' && errorsFound.length > 0)
|
|
67
|
+
errorsFound.push(
|
|
68
|
+
'[Invalid] status is complete should be not have errorsFound'
|
|
69
|
+
);
|
|
70
|
+
if (graphServiceTag == null)
|
|
71
|
+
errorsFound.push('[Invalid] graphServerTag is not empty string');
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Handles callback after Graph creation node completion
|
|
76
|
+
* @param {Object} _izContext - Izara context object
|
|
77
|
+
* @param {Object} requestParams - Callback request parameters
|
|
78
|
+
* @param {Object} passBackProperties - Pass-back properties
|
|
79
|
+
* @returns {Promise<Object>} Result object
|
|
80
|
+
*/
|
|
81
|
+
export default async function CreateNodeCallbackMain(
|
|
82
|
+
_izContext,
|
|
83
|
+
requestParams,
|
|
84
|
+
passBackProperties
|
|
85
|
+
//(<additionalParams>)
|
|
86
|
+
//(</additionalParams>)
|
|
87
|
+
) {
|
|
88
|
+
try {
|
|
89
|
+
_izContext.logger.debug(`[${process.env.iz_serviceTag}:CreateNodeCallback] started`, {
|
|
90
|
+
requestParams,
|
|
91
|
+
passBackProperties
|
|
92
|
+
});
|
|
93
|
+
const {
|
|
94
|
+
returnValue,
|
|
95
|
+
status,
|
|
96
|
+
errorsFound = [],
|
|
97
|
+
graphServiceTag,
|
|
98
|
+
parentFlowId
|
|
99
|
+
} = requestParams;
|
|
100
|
+
if (empty(returnValue?.requestParams))
|
|
101
|
+
throw new NoRetryError('message not an object');
|
|
102
|
+
validateInput(returnValue, status, graphServiceTag, errorsFound);
|
|
103
|
+
if (errorsFound.length > 0) errorsFound.push(errorsFound.join(','));
|
|
104
|
+
|
|
105
|
+
const awaitingStepId = await asyncFlowSharedLib.createAwaitingStepId(
|
|
106
|
+
parentFlowId,
|
|
107
|
+
PREFIX.ASYNC
|
|
108
|
+
);
|
|
109
|
+
const pending =
|
|
110
|
+
await asyncFlowSharedLib.findPendingStepAwaitingMultipleSteps(
|
|
111
|
+
_izContext,
|
|
112
|
+
awaitingStepId
|
|
113
|
+
);
|
|
114
|
+
_izContext.logger.debug('[CreateNodeCallback] awaiting step', {
|
|
115
|
+
awaitingStepId,
|
|
116
|
+
pending
|
|
117
|
+
});
|
|
118
|
+
if (!pending) {
|
|
119
|
+
_izContext.logger.warn(
|
|
120
|
+
`No pending step found for awaitingStepId: ${awaitingStepId}`
|
|
121
|
+
);
|
|
122
|
+
return { returnValue, status, errorsFound };
|
|
123
|
+
}
|
|
124
|
+
const result =
|
|
125
|
+
await asyncFlowSharedLib.checkAllAwaitingStepsFinishedWithReturnParams(
|
|
126
|
+
_izContext,
|
|
127
|
+
pending.pendingStepId,
|
|
128
|
+
awaitingStepId,
|
|
129
|
+
errorsFound
|
|
130
|
+
);
|
|
131
|
+
_izContext.logger.debug(
|
|
132
|
+
'[CreateNodeCallback] all awaiting steps result',
|
|
133
|
+
{
|
|
134
|
+
isComplete: result.isComplete,
|
|
135
|
+
awaitingStepId,
|
|
136
|
+
pendingStepId: pending.pendingStepId
|
|
137
|
+
}
|
|
138
|
+
);
|
|
139
|
+
|
|
140
|
+
if (result.isComplete) {
|
|
141
|
+
const nodeResultKey = `returnCreatedNode`;
|
|
142
|
+
const fallbackNodeResultKey = `returnCreateNode`;
|
|
143
|
+
const nodeResult =
|
|
144
|
+
returnValue.queryResult[nodeResultKey] ??
|
|
145
|
+
returnValue.queryResult[fallbackNodeResultKey] ??
|
|
146
|
+
{};
|
|
147
|
+
const node = nodeResult.createNodeResult ?? nodeResult;
|
|
148
|
+
const existsNode =
|
|
149
|
+
node.existsNode && Object.keys(node.existsNode).length
|
|
150
|
+
? {
|
|
151
|
+
objType: returnValue.requestParams.objType,
|
|
152
|
+
objInstanceFull: node.existsNode.objInstanceFull
|
|
153
|
+
}
|
|
154
|
+
: null;
|
|
155
|
+
|
|
156
|
+
// ── Step 1: Persist DynamoDB records ──────────────────────────────────
|
|
157
|
+
if (status === 'complete' && errorsFound.length === 0) {
|
|
158
|
+
const listOfRecords = result?.additionalAttributes?.listOfRecords ?? [];
|
|
159
|
+
await saveDynamoDbRecords(_izContext, listOfRecords);
|
|
160
|
+
|
|
161
|
+
// ── Step 2: Auto-provision TargetRole (Owner) after DynamoDB write ─
|
|
162
|
+
const submittedByUserId =
|
|
163
|
+
returnValue?.requestParams?.submittedByUserId ||
|
|
164
|
+
node?.objInstanceFull?.identifiers?.submittedByUserId ||
|
|
165
|
+
requestParams?.passBackProperties?.submittedByUserId ||
|
|
166
|
+
passBackProperties?.passBackProperties?.submittedByUserId ||
|
|
167
|
+
_izContext.correlationIds?.get(coreConsts.SUBMITTED_BY_USER_ID) ||
|
|
168
|
+
_izContext.correlationIds?.get('submittedByUserId');
|
|
169
|
+
|
|
170
|
+
await autoProvisionOwnerTargetRole(_izContext, {
|
|
171
|
+
node,
|
|
172
|
+
submittedByUserId
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
const callingFlowConfig =
|
|
177
|
+
result?.additionalAttributes?.callingFlowConfig ||
|
|
178
|
+
requestParams?.passBackProperties?.parentPassBackProperties ||
|
|
179
|
+
passBackProperties?.passBackProperties?.parentPassBackProperties ||
|
|
180
|
+
passBackProperties;
|
|
181
|
+
|
|
182
|
+
const actionData = {
|
|
183
|
+
objType: returnValue.requestParams.objType,
|
|
184
|
+
objInstanceFull: node.objInstanceFull,
|
|
185
|
+
relationships: node.relationships,
|
|
186
|
+
parentFlowId: parentFlowId || returnValue?.parentFlowId,
|
|
187
|
+
existsNode,
|
|
188
|
+
status,
|
|
189
|
+
errorsFound
|
|
190
|
+
};
|
|
191
|
+
|
|
192
|
+
// ── Step 3: Resolve Quota deduction keys and forward confirmation ─────
|
|
193
|
+
const quotaKeys = resolveQuotaDeductionKeys(
|
|
194
|
+
requestParams,
|
|
195
|
+
passBackProperties,
|
|
196
|
+
returnValue,
|
|
197
|
+
callingFlowConfig,
|
|
198
|
+
_izContext
|
|
199
|
+
);
|
|
200
|
+
|
|
201
|
+
await forwardToQuotaConfirmation(_izContext, {
|
|
202
|
+
status,
|
|
203
|
+
errorsFound,
|
|
204
|
+
quotaKeys,
|
|
205
|
+
actionData,
|
|
206
|
+
callingFlowConfig
|
|
207
|
+
});
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
await asyncFlowSharedLib.removeAwaitingMultipleStep(
|
|
211
|
+
_izContext,
|
|
212
|
+
awaitingStepId,
|
|
213
|
+
pending.pendingStepId,
|
|
214
|
+
errorsFound
|
|
215
|
+
);
|
|
216
|
+
return { returnValue, status, errorsFound };
|
|
217
|
+
} catch (error) {
|
|
218
|
+
_izContext.logger.error('[CreateNodeCallback] error:', error);
|
|
219
|
+
throw error;
|
|
220
|
+
}
|
|
221
|
+
}
|
|
@@ -52,7 +52,7 @@ export default async function DeleteComplete(
|
|
|
52
52
|
//(</additionalParams>)
|
|
53
53
|
) {
|
|
54
54
|
try {
|
|
55
|
-
_izContext.logger.debug(
|
|
55
|
+
_izContext.logger.debug(`[${process.env.iz_serviceTag}:DeleteComplete] started`, {
|
|
56
56
|
requestParams
|
|
57
57
|
});
|
|
58
58
|
const {
|
|
@@ -56,7 +56,7 @@ export default async function <%- flowTag %>(
|
|
|
56
56
|
//(</additionalParams>)
|
|
57
57
|
) {
|
|
58
58
|
try {
|
|
59
|
-
_izContext.logger.debug(
|
|
59
|
+
_izContext.logger.debug(`[${process.env.iz_serviceTag}:<%- flowTag %>] deleteMain:`, {
|
|
60
60
|
requestParams,
|
|
61
61
|
callingFlowConfig
|
|
62
62
|
});
|
|
@@ -72,18 +72,42 @@ export default async function <%- flowTag %>(
|
|
|
72
72
|
_izContext,
|
|
73
73
|
objType
|
|
74
74
|
);
|
|
75
|
-
_izContext.logger.debug(
|
|
75
|
+
_izContext.logger.debug(`[${process.env.iz_serviceTag}:<%- flowTag %>] objectSchema:`, objectSchema);
|
|
76
76
|
|
|
77
|
-
// ── Resolve
|
|
77
|
+
// ── Resolve submittedByUserId / targetIdentifiers ─────────────────────────
|
|
78
|
+
let submittedByUserId, targetIdentifiers;
|
|
78
79
|
if (
|
|
79
80
|
objectSchema.generatedBy === 'user' ||
|
|
80
81
|
objectSchema.generatedBy === 'systemWithUser'
|
|
81
82
|
) {
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
83
|
+
submittedByUserId =
|
|
84
|
+
requestParams.submittedByUserId ||
|
|
85
|
+
_izContext.correlationIds.get(coreConsts.SUBMITTED_BY_USER_ID);
|
|
86
|
+
|
|
87
|
+
targetIdentifiers = requestParams.targetIdentifiers;
|
|
88
|
+
|
|
89
|
+
if (!targetIdentifiers && objectSchema.belongTo?.objectType === 'user' && submittedByUserId) {
|
|
90
|
+
targetIdentifiers = { submittedByUserId };
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
if (!submittedByUserId) errorsFound.push('Not have submittedByUserId');
|
|
94
|
+
if (objectSchema.hasOwnProperty('belongTo') && !targetIdentifiers)
|
|
95
|
+
errorsFound.push('not have targetIdentifiers');
|
|
96
|
+
|
|
97
|
+
requestParams.submittedByUserId = submittedByUserId;
|
|
98
|
+
if (targetIdentifiers) {
|
|
99
|
+
if (!targetIdentifiers.submittedByUserId && submittedByUserId) {
|
|
100
|
+
targetIdentifiers.submittedByUserId = submittedByUserId;
|
|
101
|
+
}
|
|
102
|
+
requestParams.targetIdentifiers = targetIdentifiers;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
_izContext.logger.debug(`[${process.env.iz_serviceTag}:<%- flowTag %>] Identity & Target Context Resolved:`, {
|
|
106
|
+
submittedByUserId: requestParams.submittedByUserId,
|
|
107
|
+
targetIdentifiers: requestParams.targetIdentifiers,
|
|
108
|
+
belongTo: objectSchema.belongTo,
|
|
109
|
+
generatedBy: objectSchema.generatedBy
|
|
110
|
+
});
|
|
87
111
|
}
|
|
88
112
|
|
|
89
113
|
//(<beforeQuery>)
|
|
@@ -315,6 +339,7 @@ export default async function <%- flowTag %>(
|
|
|
315
339
|
errorsFound
|
|
316
340
|
);
|
|
317
341
|
} catch (err) {
|
|
342
|
+
_izContext.logger.error(`[${process.env.iz_serviceTag}:<%- flowTag %>] error:`, err);
|
|
318
343
|
throw err;
|
|
319
344
|
}
|
|
320
345
|
}
|
|
@@ -62,7 +62,7 @@ export async function <%- flowTag %>LogicalLib(
|
|
|
62
62
|
phaseResults = {}
|
|
63
63
|
) {
|
|
64
64
|
try {
|
|
65
|
-
_izContext.logger.debug(
|
|
65
|
+
_izContext.logger.debug(`[${process.env.iz_serviceTag}:<%- flowTag %>LogicalLib] started`, {
|
|
66
66
|
requestParams,
|
|
67
67
|
callingFlowConfig,
|
|
68
68
|
phaseResults
|
|
@@ -78,14 +78,14 @@ export async function <%- flowTag %>LogicalLib(
|
|
|
78
78
|
_izContext,
|
|
79
79
|
objType
|
|
80
80
|
);
|
|
81
|
-
_izContext.logger.debug(
|
|
81
|
+
_izContext.logger.debug(`[${process.env.iz_serviceTag}:<%- flowTag %>LogicalLib] objectSchema:`, objectSchema);
|
|
82
82
|
|
|
83
83
|
// ── Build deleteDataDetails ───────────────────────────────────────────────
|
|
84
84
|
const deleteDataDetails = await createDeleteDataDetail(
|
|
85
85
|
_izContext,
|
|
86
86
|
objectSchema
|
|
87
87
|
);
|
|
88
|
-
_izContext.logger.debug(
|
|
88
|
+
_izContext.logger.debug(`[${process.env.iz_serviceTag}:<%- flowTag %>LogicalLib] deleteDataDetails:`, deleteDataDetails);
|
|
89
89
|
|
|
90
90
|
if (objectSchema.canDelete === false || objectSchema.canDelete == null) {
|
|
91
91
|
errorsFound.push("this objectSchema can't delete");
|
|
@@ -119,6 +119,7 @@ export async function <%- flowTag %>LogicalLib(
|
|
|
119
119
|
return {
|
|
120
120
|
objType,
|
|
121
121
|
identifiers: requestParams.identifiers,
|
|
122
|
+
targetIdentifiers: requestParams.targetIdentifiers,
|
|
122
123
|
status: 'error',
|
|
123
124
|
errorsFound
|
|
124
125
|
};
|
|
@@ -201,10 +202,12 @@ export async function <%- flowTag %>LogicalLib(
|
|
|
201
202
|
return {
|
|
202
203
|
objType,
|
|
203
204
|
identifiers: requestParams.identifiers,
|
|
205
|
+
targetIdentifiers: requestParams.targetIdentifiers,
|
|
204
206
|
status: 'complete',
|
|
205
207
|
errorsFound
|
|
206
208
|
};
|
|
207
209
|
} catch (err) {
|
|
210
|
+
_izContext.logger.error(`[${process.env.iz_serviceTag}:<%- flowTag %>LogicalLib] error:`, err);
|
|
208
211
|
throw err;
|
|
209
212
|
}
|
|
210
213
|
}
|
|
@@ -30,7 +30,11 @@ import { sns } from '@izara_project/izara-core-library-external-request';
|
|
|
30
30
|
|
|
31
31
|
const { createObjType } = utils;
|
|
32
32
|
|
|
33
|
-
import {
|
|
33
|
+
import {
|
|
34
|
+
<%- flowTag %>LogicalLib,
|
|
35
|
+
collectRbacAwaitingResults,
|
|
36
|
+
assertRbacPermission
|
|
37
|
+
} from './<%- upperCaseFlowTag %>LogicalLib.js';
|
|
34
38
|
|
|
35
39
|
//(<optionalRequire>)
|
|
36
40
|
//(</optionalRequire>)
|
|
@@ -39,6 +43,7 @@ import { <%- flowTag %>LogicalLib } from './<%- upperCaseFlowTag %>LogicalLib.js
|
|
|
39
43
|
* Handles callback after RbacCallback phase — verifies awaitingStep then proceeds to next phase
|
|
40
44
|
* @param {Object} _izContext - Context object with logger
|
|
41
45
|
* @param {Object} requestParams - { fieldNames, relationships[] }
|
|
46
|
+
* @param {string} flowTag - Flow tag name
|
|
42
47
|
* @param {Object} callingFlowConfig - Calling flow configuration
|
|
43
48
|
* @returns {Promise<Object>}
|
|
44
49
|
*/
|
|
@@ -49,149 +54,44 @@ export default async function <%- flowTag %>RbacCallbackMain(
|
|
|
49
54
|
callingFlowConfig = {}
|
|
50
55
|
) {
|
|
51
56
|
try {
|
|
52
|
-
_izContext.logger.debug(
|
|
57
|
+
_izContext.logger.debug(`[${process.env.iz_serviceTag}:<%- flowTag %>RbacCallback] Started with params:`, {
|
|
53
58
|
requestParams,
|
|
54
59
|
flowTag,
|
|
55
60
|
callingFlowConfig
|
|
56
61
|
});
|
|
57
62
|
|
|
58
|
-
|
|
59
|
-
const rbacType = parts.pop();
|
|
60
|
-
const rbacPendingStepId = '<%- flowTag %>RbacCallback_' + parts.join('_');
|
|
61
|
-
const currentAwaitingStepId = requestParams.parentFlowId;
|
|
62
|
-
|
|
63
|
-
_izContext.logger.debug(
|
|
64
|
-
'[<%- flowTag %>RbacCallbackMain] Parsed RBAC pending details:',
|
|
65
|
-
{
|
|
66
|
-
rbacType,
|
|
67
|
-
rbacPendingStepId,
|
|
68
|
-
currentAwaitingStepId,
|
|
69
|
-
parentFlowId: requestParams.parentFlowId
|
|
70
|
-
}
|
|
71
|
-
);
|
|
72
|
-
|
|
73
|
-
const rbacAwaitingStepsResult =
|
|
74
|
-
await asyncFlowSharedLib.checkAllAwaitingStepsFinishedWithReturnParams(
|
|
75
|
-
_izContext,
|
|
76
|
-
rbacPendingStepId,
|
|
77
|
-
currentAwaitingStepId,
|
|
78
|
-
requestParams.errorsFound,
|
|
79
|
-
{
|
|
80
|
-
returnValue: requestParams.returnValue,
|
|
81
|
-
rbacType
|
|
82
|
-
}
|
|
83
|
-
);
|
|
84
|
-
|
|
85
|
-
_izContext.logger.debug(
|
|
86
|
-
'[<%- flowTag %>RbacCallbackMain] checkAllAwaitingStepsFinishedWithReturnParams result:',
|
|
87
|
-
{
|
|
88
|
-
rbacAwaitingStepsResult
|
|
89
|
-
}
|
|
90
|
-
);
|
|
91
|
-
|
|
63
|
+
// 1. Wait until all awaiting steps (App/Target RBAC) are complete
|
|
92
64
|
const {
|
|
93
65
|
isComplete,
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
} =
|
|
66
|
+
rbacResults,
|
|
67
|
+
originalRequestParams,
|
|
68
|
+
collectedErrors = []
|
|
69
|
+
} = await collectRbacAwaitingResults(_izContext, requestParams);
|
|
98
70
|
|
|
99
71
|
if (isComplete === false) {
|
|
100
|
-
_izContext.logger.debug(
|
|
101
|
-
'[<%- flowTag %>RbacCallbackMain] Awaiting steps still pending completion:',
|
|
102
|
-
{
|
|
103
|
-
rbacPendingStepId,
|
|
104
|
-
isComplete
|
|
105
|
-
}
|
|
106
|
-
);
|
|
107
|
-
|
|
108
72
|
return 'all task not completed';
|
|
109
73
|
}
|
|
110
74
|
|
|
111
|
-
|
|
112
|
-
'[<%- flowTag %>RbacCallbackMain] All awaiting steps completed — clearing awaiting steps:',
|
|
113
|
-
{
|
|
114
|
-
rbacPendingStepId
|
|
115
|
-
}
|
|
116
|
-
);
|
|
75
|
+
const errorsFound = [...collectedErrors];
|
|
117
76
|
|
|
118
|
-
|
|
77
|
+
// 2. Validate RBAC permission results
|
|
78
|
+
const { hasError, errorResult, rbacCallbackResults } = await assertRbacPermission(
|
|
119
79
|
_izContext,
|
|
120
|
-
rbacPendingStepId
|
|
121
|
-
);
|
|
122
|
-
|
|
123
|
-
const originalRequestParams = additionalAttributes?.requestParams || {};
|
|
124
|
-
|
|
125
|
-
_izContext.logger.debug(
|
|
126
|
-
'[<%- flowTag %>RbacCallbackMain] Retrieved originalRequestParams:',
|
|
127
80
|
{
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
);
|
|
131
|
-
|
|
132
|
-
const rbacResults = Object.fromEntries(
|
|
133
|
-
Object.entries(collectedReturnValueByAwaitingStepId || {}).map(
|
|
134
|
-
([stepId, attrs]) => {
|
|
135
|
-
const type = stepId.split('_').pop();
|
|
136
|
-
return [type, attrs];
|
|
137
|
-
}
|
|
138
|
-
)
|
|
139
|
-
);
|
|
140
|
-
|
|
141
|
-
const rbacCallbackResults = {};
|
|
142
|
-
const hasError = Object.entries(rbacResults).some(([type, result]) => {
|
|
143
|
-
if (result && result.error) {
|
|
144
|
-
errorsFound.push(result.error);
|
|
145
|
-
return true;
|
|
146
|
-
}
|
|
147
|
-
rbacCallbackResults[type] = result;
|
|
148
|
-
return false;
|
|
149
|
-
});
|
|
150
|
-
|
|
151
|
-
const isAllowed = Object.values(rbacCallbackResults).some(
|
|
152
|
-
item => item?.returnValue?.permission === true
|
|
153
|
-
);
|
|
154
|
-
|
|
155
|
-
if (!isAllowed) {
|
|
156
|
-
errorsFound.push('Permission denied');
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
_izContext.logger.debug(
|
|
160
|
-
'[<%- flowTag %>RbacCallbackMain] Final rbacCallbackResults before calling <%- flowTag %>MainLogical:',
|
|
161
|
-
{
|
|
162
|
-
rbacCallbackResults,
|
|
163
|
-
isAllowed,
|
|
81
|
+
rbacResults,
|
|
82
|
+
originalRequestParams,
|
|
164
83
|
errorsFound
|
|
165
84
|
}
|
|
166
85
|
);
|
|
167
86
|
|
|
168
|
-
if (hasError
|
|
169
|
-
const errorResult = {
|
|
170
|
-
errorsFound,
|
|
171
|
-
status: 'rejected',
|
|
172
|
-
requestParams: originalRequestParams
|
|
173
|
-
};
|
|
174
|
-
|
|
175
|
-
_izContext.logger.debug(
|
|
176
|
-
'[<%- flowTag %>RbacCallbackMain] RBAC check failed, publishing rejected status:',
|
|
177
|
-
errorResult
|
|
178
|
-
);
|
|
179
|
-
|
|
180
|
-
await sns.publishAsync(_izContext, {
|
|
181
|
-
TopicArn: snsSharedLib.snsTopicArnByFlowSchema(
|
|
182
|
-
_izContext,
|
|
183
|
-
'<%- upperCaseFlowTag %>_Out',
|
|
184
|
-
process.env.iz_serviceTag
|
|
185
|
-
),
|
|
186
|
-
Message: JSON.stringify(errorResult)
|
|
187
|
-
});
|
|
188
|
-
|
|
87
|
+
if (hasError) {
|
|
189
88
|
return errorResult;
|
|
190
89
|
}
|
|
191
90
|
|
|
192
91
|
//(<rbacCallbackMain>)
|
|
193
92
|
//(</rbacCallbackMain>)
|
|
194
93
|
|
|
94
|
+
// 3. Permission granted -> Proceed with core logical processing
|
|
195
95
|
const logicalResult = await <%- flowTag %>LogicalLib(
|
|
196
96
|
_izContext,
|
|
197
97
|
originalRequestParams,
|
|
@@ -209,7 +109,7 @@ export default async function <%- flowTag %>RbacCallbackMain(
|
|
|
209
109
|
|
|
210
110
|
return logicalResult;
|
|
211
111
|
} catch (err) {
|
|
212
|
-
_izContext.logger.error(
|
|
112
|
+
_izContext.logger.error(`[${process.env.iz_serviceTag}:<%- flowTag %>RbacCallback] Error caught:`, {
|
|
213
113
|
error: err
|
|
214
114
|
});
|
|
215
115
|
throw err;
|
|
@@ -39,7 +39,7 @@ import <%- typeof functionName !== 'undefined' ? functionName : upperCaseFlowTag
|
|
|
39
39
|
//(</optionalRequire>)
|
|
40
40
|
|
|
41
41
|
export const main = middleware.wrap(async (event, context) => {
|
|
42
|
-
event._izContext.logger.debug('
|
|
42
|
+
event._izContext.logger.debug('[FlowEndpoint_HdrWbs] WebSocket event received', { event });
|
|
43
43
|
|
|
44
44
|
try {
|
|
45
45
|
if (event.requestContext) {
|
|
@@ -49,12 +49,21 @@ export const main = middleware.wrap(async (event, context) => {
|
|
|
49
49
|
consts.X_CORRELATION_ID
|
|
50
50
|
);
|
|
51
51
|
|
|
52
|
+
event._izContext.logger.debug('[FlowEndpoint_HdrWbs] request context info', {
|
|
53
|
+
route,
|
|
54
|
+
connectionId,
|
|
55
|
+
correlationId
|
|
56
|
+
});
|
|
57
|
+
|
|
52
58
|
switch (route) {
|
|
53
59
|
case '$default':
|
|
54
|
-
|
|
60
|
+
event._izContext.logger.debug('[FlowEndpoint_HdrWbs] Received unknown route', { route });
|
|
55
61
|
break;
|
|
56
62
|
case '<%- flowTag %>':
|
|
57
|
-
|
|
63
|
+
event._izContext.logger.debug('[FlowEndpoint_HdrWbs] matched route <%- flowTag %>', {
|
|
64
|
+
route,
|
|
65
|
+
body: event.body
|
|
66
|
+
});
|
|
58
67
|
let eventParams = JSON.parse(event.body);
|
|
59
68
|
|
|
60
69
|
//(<createIdentifiersFlow>)
|
|
@@ -69,11 +78,22 @@ export const main = middleware.wrap(async (event, context) => {
|
|
|
69
78
|
}
|
|
70
79
|
);
|
|
71
80
|
|
|
81
|
+
event._izContext.logger.debug('[FlowEndpoint_HdrWbs] flow schema resolved', {
|
|
82
|
+
flowTag: '<%- flowTag %>',
|
|
83
|
+
statusType: flowSchema?.statusType
|
|
84
|
+
});
|
|
85
|
+
|
|
72
86
|
if (
|
|
73
87
|
flowSchema.statusType === 'statusField' ||
|
|
74
88
|
flowSchema.statusType === 'storedCache' ||
|
|
75
89
|
flowSchema.statusType === 'triggerCache'
|
|
76
90
|
) {
|
|
91
|
+
const taskKey = `${createFlowTypeConcat(event._izContext, { flowTag: '<%- flowTag %>', serviceTag: process.env.iz_serviceTag })}${identifiers}`;
|
|
92
|
+
event._izContext.logger.debug('[FlowEndpoint_HdrWbs] registering WebSocketTask with ttl', {
|
|
93
|
+
taskKey,
|
|
94
|
+
connectionId,
|
|
95
|
+
ttl: 600
|
|
96
|
+
});
|
|
77
97
|
await dynamodbSharedLib.putItem(
|
|
78
98
|
event._izContext,
|
|
79
99
|
await dynamodbSharedLib.tableName(
|
|
@@ -81,12 +101,17 @@ export const main = middleware.wrap(async (event, context) => {
|
|
|
81
101
|
'WebSocketTask'
|
|
82
102
|
),
|
|
83
103
|
{
|
|
84
|
-
taskKey
|
|
104
|
+
taskKey,
|
|
85
105
|
connectionId: connectionId,
|
|
86
106
|
ttl: 600
|
|
87
107
|
}
|
|
88
108
|
);
|
|
89
109
|
} else if (flowSchema.statusType === 'none') {
|
|
110
|
+
const taskKey = `${createFlowTypeConcat(event._izContext, { flowTag: '<%- flowTag %>', serviceTag: process.env.iz_serviceTag })}${correlationId}`;
|
|
111
|
+
event._izContext.logger.debug('[FlowEndpoint_HdrWbs] registering WebSocketTask for status none', {
|
|
112
|
+
taskKey,
|
|
113
|
+
connectionId
|
|
114
|
+
});
|
|
90
115
|
await dynamodbSharedLib.putItem(
|
|
91
116
|
event._izContext,
|
|
92
117
|
await dynamodbSharedLib.tableName(
|
|
@@ -94,15 +119,52 @@ export const main = middleware.wrap(async (event, context) => {
|
|
|
94
119
|
'WebSocketTask'
|
|
95
120
|
),
|
|
96
121
|
{
|
|
97
|
-
taskKey
|
|
122
|
+
taskKey,
|
|
98
123
|
connectionId: connectionId
|
|
99
124
|
}
|
|
100
125
|
);
|
|
101
126
|
}
|
|
102
127
|
|
|
128
|
+
const authorizerUserId =
|
|
129
|
+
event.requestContext?.authorizer?.submittedByUserId ||
|
|
130
|
+
event.requestContext?.authorizer?.principalId;
|
|
131
|
+
const resolvedUserId =
|
|
132
|
+
authorizerUserId ||
|
|
133
|
+
eventParams.submittedByUserId ||
|
|
134
|
+
event._izContext?.correlationIds?.get(consts.SUBMITTED_BY_USER_ID);
|
|
135
|
+
|
|
136
|
+
if (resolvedUserId) {
|
|
137
|
+
if (event._izContext?.correlationIds) {
|
|
138
|
+
event._izContext.correlationIds.set(
|
|
139
|
+
consts.SUBMITTED_BY_USER_ID,
|
|
140
|
+
resolvedUserId
|
|
141
|
+
);
|
|
142
|
+
}
|
|
143
|
+
if (
|
|
144
|
+
!eventParams.targetIdentifiers ||
|
|
145
|
+
typeof eventParams.targetIdentifiers !== 'object'
|
|
146
|
+
) {
|
|
147
|
+
eventParams.targetIdentifiers = {};
|
|
148
|
+
}
|
|
149
|
+
eventParams.targetIdentifiers.submittedByUserId = resolvedUserId;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
event._izContext.logger.debug('[FlowEndpoint_HdrWbs] resolved user and target identifiers', {
|
|
153
|
+
authorizerUserId,
|
|
154
|
+
resolvedUserId,
|
|
155
|
+
targetIdentifiers: eventParams.targetIdentifiers
|
|
156
|
+
});
|
|
157
|
+
|
|
103
158
|
let callingFlow = eventParams?.callingFlow
|
|
104
159
|
? eventParams.callingFlow
|
|
105
160
|
: {};
|
|
161
|
+
|
|
162
|
+
event._izContext.logger.debug('[FlowEndpoint_HdrWbs] invoking main function', {
|
|
163
|
+
flowTag: '<%- flowTag %>',
|
|
164
|
+
eventParams,
|
|
165
|
+
callingFlow
|
|
166
|
+
});
|
|
167
|
+
|
|
106
168
|
await <%- typeof functionName !== 'undefined' ? functionName : upperCaseFlowTag %>(
|
|
107
169
|
event._izContext,
|
|
108
170
|
eventParams,
|
|
@@ -115,16 +177,23 @@ export const main = middleware.wrap(async (event, context) => {
|
|
|
115
177
|
}
|
|
116
178
|
} else {
|
|
117
179
|
const connId = event.connId;
|
|
118
|
-
|
|
180
|
+
event._izContext.logger.debug('[FlowEndpoint_HdrWbs] direct postToConnection', {
|
|
181
|
+
connId,
|
|
182
|
+
message: event.message
|
|
183
|
+
});
|
|
119
184
|
await postToConnection(event._izContext, { message: event.message }, connId);
|
|
120
185
|
}
|
|
121
186
|
|
|
122
187
|
return response.webSocketSuccess();
|
|
123
188
|
} catch (err) {
|
|
124
|
-
const connId = event.requestContext
|
|
125
|
-
event._izContext.logger.error('Error, WebSocket: ',
|
|
126
|
-
|
|
127
|
-
|
|
189
|
+
const connId = event.requestContext?.connectionId;
|
|
190
|
+
event._izContext.logger.error('[FlowEndpoint_HdrWbs] Error, WebSocket: ', {
|
|
191
|
+
error: err,
|
|
192
|
+
connectionId: connId
|
|
193
|
+
});
|
|
194
|
+
if (connId) {
|
|
195
|
+
await postToConnection(event._izContext, { message: err.message }, connId);
|
|
196
|
+
}
|
|
128
197
|
return response.failure(err);
|
|
129
198
|
}
|
|
130
199
|
});
|