@izara_project/izara-core-generate-service-code 1.0.82 → 1.0.84
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 +34 -0
- package/src/compile/loadSchemas.js +121 -7
- package/src/emit/attributeTree/emitAttributeTreeSchemas.js +388 -0
- package/src/emit/coreFunction/emitCoreFunctionArtifacts.js +29 -1
- package/src/emit/coreFunction/templates/InitialSetupConfig.ejs +16 -3
- package/src/emit/crud/crudActionPlan.js +43 -7
- package/src/emit/crud/emitCrudApplicationArtifacts.js +19 -4
- package/src/emit/crud/emitDynamicCrudFlowSchemas.js +27 -6
- 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/CreateEndpoint_Main.ejs +75 -21
- package/src/emit/crud/templates/CreateLogicalLib.ejs +73 -8
- package/src/emit/crud/templates/DeleteComplete_Main.ejs +1 -1
- package/src/emit/crud/templates/DeleteEndpoint_Main.ejs +39 -11
- package/src/emit/crud/templates/DeleteLogicalLib.ejs +6 -3
- package/src/emit/crud/templates/FlowEndpointRbacCallback_Main.ejs +2 -2
- package/src/emit/crud/templates/FlowEndpoint_HdrWbs.ejs +7 -0
- package/src/emit/crud/templates/FlowMain_Wbs.ejs +5 -2
- 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 +53 -4
- package/src/emit/crud/templates/UpdateLogicalLib.ejs +4 -3
- package/src/emit/custom/customFlows.js +49 -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 +103 -0
- package/src/emit/rbac/templates/ConfirmUsage_Main.ejs +71 -0
- package/src/emit/rbac/templates/CreateTargetRole_Main.ejs +49 -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 +147 -0
- package/src/emit/rbac/templates/UserRbacFlow_Main.ejs +59 -23
- package/src/emit/rbac/templates/UserRoleMutation_Main.ejs +1 -1
- package/src/emit/relationship/emitDynamicRelationshipFlowSchemas.js +1 -1
- package/src/emit/relationship/templates/ChangeRelationship_Main.ejs +10 -3
- package/src/emit/resource/emitResourceArtifacts.js +350 -112
- package/src/emit/resource/templates/SystemDynamoDB_Yaml.ejs +53 -2
- package/src/emit/system/emitSystemWebSocketArtifacts.js +6 -4
- package/src/emit/system/templates/WebSocketConnect.ejs +71 -12
- package/src/emit/system/templates/WebSocketConnect_Yaml.ejs +7 -0
- package/src/emit/systemText/emitSystemTextSchemas.js +3 -2
- 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 +23 -6
- package/test/customFlowApplicationArtifacts.test.js +5 -5
- package/test/dynamicCrudFlowSchemas.test.js +110 -13
- package/test/dynamicRbacFlowSchemas.test.js +15 -2
- package/test/publicApi.test.js +7 -7
- package/test/resourceArtifacts.test.js +70 -29
- package/test/systemTextSchemas.test.js +1 -1
|
@@ -70,6 +70,10 @@ const externalServices = {
|
|
|
70
70
|
dynamoTableNames.add('RolePermissions');
|
|
71
71
|
dynamoTableNames.add('RoleUsers');
|
|
72
72
|
dynamoTableNames.add('UserRoles');
|
|
73
|
+
dynamoTableNames.add('RbacPermissionCaches');
|
|
74
|
+
dynamoTableNames.add('RoleLimit');
|
|
75
|
+
dynamoTableNames.add('RunningTotalUsage');
|
|
76
|
+
dynamoTableNames.add('RunningTotalReservedUsage');
|
|
73
77
|
}
|
|
74
78
|
if (typeof s3Flows !== 'undefined' && (s3Flows || []).length > 0) {
|
|
75
79
|
dynamoTableNames.add('ReservedDataMain');
|
|
@@ -176,16 +180,25 @@ const tableConfigs = {
|
|
|
176
180
|
if (crud && typeof rbacValidatorServiceTags !== 'undefined' && rbacValidatorServiceTags && rbacValidatorServiceTags.length > 0) {
|
|
177
181
|
const allRbacTags = Array.from(new Set(['Rbac', ...rbacValidatorServiceTags]));
|
|
178
182
|
const hasGraph = typeof objectGraphServiceTags !== 'undefined' && objectGraphServiceTags && objectGraphServiceTags.length > 0;
|
|
183
|
+
const createEndpoint = hasGraph ? 'CreateRbacCallbackHdrSqs' : 'CreateCompleteHdrSqs';
|
|
179
184
|
const updateEndpoint = hasGraph ? 'UpdateRbacCallbackHdrSqs' : 'UpdateCompleteHdrSqs';
|
|
180
185
|
const deleteEndpoint = hasGraph ? 'DeleteRbacCallbackHdrSqs' : 'DeleteCompleteHdrSqs';
|
|
181
186
|
allRbacTags.forEach(function(tag) {
|
|
182
|
-
|
|
183
|
-
rbacSubs.push({ serviceTag: tag, topicName: 'ValidatorRbac_Out', sqsEndpoint: 'CreateCompleteHdrSqs' });
|
|
184
|
-
}
|
|
187
|
+
rbacSubs.push({ serviceTag: tag, topicName: 'ValidatorRbac_Out', sqsEndpoint: createEndpoint });
|
|
185
188
|
rbacSubs.push({ serviceTag: tag, topicName: 'ValidatorRbac_Out', sqsEndpoint: updateEndpoint });
|
|
186
189
|
rbacSubs.push({ serviceTag: tag, topicName: 'ValidatorRbac_Out', sqsEndpoint: deleteEndpoint });
|
|
187
190
|
});
|
|
188
191
|
}
|
|
192
|
+
|
|
193
|
+
if (typeof customRbacFlowTags !== 'undefined' && customRbacFlowTags && customRbacFlowTags.length > 0) {
|
|
194
|
+
const allRbacTags = Array.from(new Set(['Rbac', ...(typeof rbacValidatorServiceTags !== 'undefined' ? rbacValidatorServiceTags : [])]));
|
|
195
|
+
customRbacFlowTags.forEach(function(flowTag) {
|
|
196
|
+
const tagUpper = flowTag[0].toUpperCase() + flowTag.slice(1);
|
|
197
|
+
allRbacTags.forEach(function(tag) {
|
|
198
|
+
rbacSubs.push({ serviceTag: tag, topicName: 'ValidatorRbac_Out', sqsEndpoint: `${tagUpper}RbacCallbackHdrSqs` });
|
|
199
|
+
});
|
|
200
|
+
});
|
|
201
|
+
}
|
|
189
202
|
-%>
|
|
190
203
|
const snsTopicSubscriptions = [
|
|
191
204
|
<% if (relSubs.length > 0) { -%>
|
|
@@ -5,37 +5,45 @@ export function createCrudActionPlans(objects = []) {
|
|
|
5
5
|
const hasRbac = objects.some(
|
|
6
6
|
(object) => isCrudObject(object) && hasRbacObject(object, objects)
|
|
7
7
|
);
|
|
8
|
+
const isBillable = objects.some(
|
|
9
|
+
(object) => isCrudObject(object) && isBillableObject(object, objects)
|
|
10
|
+
);
|
|
8
11
|
|
|
9
12
|
return Object.fromEntries(
|
|
10
13
|
CRUD_ACTIONS.map((action) => [
|
|
11
14
|
action,
|
|
12
|
-
createCrudActionPlan(action, { hasGraph, hasRbac })
|
|
15
|
+
createCrudActionPlan(action, { hasGraph, hasRbac, isBillable })
|
|
13
16
|
])
|
|
14
17
|
);
|
|
15
18
|
}
|
|
16
19
|
|
|
17
20
|
export function createCrudActionPlan(
|
|
18
21
|
action,
|
|
19
|
-
{ hasGraph = false, hasRbac = false } = {}
|
|
22
|
+
{ hasGraph = false, hasRbac = false, isBillable = true } = {}
|
|
20
23
|
) {
|
|
21
|
-
const actionHasRbac = action !== '
|
|
24
|
+
const actionHasRbac = action !== 'Get' && hasRbac;
|
|
22
25
|
const outputTopic = action !== 'Get';
|
|
26
|
+
const hasQuotaReservation = action === 'Create' && hasRbac && isBillable;
|
|
23
27
|
|
|
24
28
|
return {
|
|
25
29
|
action,
|
|
26
30
|
outputTopic,
|
|
27
31
|
hasGraph: outputTopic && hasGraph,
|
|
28
32
|
hasRbac: actionHasRbac,
|
|
33
|
+
hasQuotaReservation,
|
|
29
34
|
hasComplete: outputTopic && (actionHasRbac || hasGraph),
|
|
30
35
|
hasRbacCallback: outputTopic && actionHasRbac && hasGraph
|
|
31
36
|
};
|
|
32
37
|
}
|
|
33
38
|
|
|
39
|
+
export const VALID_CRUD_GENERATED_BY = new Set([
|
|
40
|
+
'user',
|
|
41
|
+
'systemWithUser',
|
|
42
|
+
'systemNoUser'
|
|
43
|
+
]);
|
|
44
|
+
|
|
34
45
|
export function isCrudObject(object) {
|
|
35
|
-
return (
|
|
36
|
-
object?.generatedBy === 'userGenerated' ||
|
|
37
|
-
object?.generatedBy === 'systemGenerated'
|
|
38
|
-
);
|
|
46
|
+
return VALID_CRUD_GENERATED_BY.has(object?.generatedBy);
|
|
39
47
|
}
|
|
40
48
|
|
|
41
49
|
export function hasGraphStorageResource(objects = []) {
|
|
@@ -80,3 +88,31 @@ function normalizeBelongTo(object) {
|
|
|
80
88
|
if (!object?.belongTo) return [];
|
|
81
89
|
return Array.isArray(object.belongTo) ? object.belongTo : [object.belongTo];
|
|
82
90
|
}
|
|
91
|
+
|
|
92
|
+
export function isBillableObject(object, objects = []) {
|
|
93
|
+
if (!isCrudObject(object)) return false;
|
|
94
|
+
|
|
95
|
+
const targets = normalizeBelongTo(object);
|
|
96
|
+
if (targets.length > 0) {
|
|
97
|
+
for (const target of targets) {
|
|
98
|
+
if (typeof target?.billable === 'boolean') {
|
|
99
|
+
return target.billable;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
if (Array.isArray(object?.addOnDataStructure)) {
|
|
105
|
+
const rbacAddOn = object.addOnDataStructure.find(
|
|
106
|
+
(addOn) => addOn?.type === 'rbac'
|
|
107
|
+
);
|
|
108
|
+
if (typeof rbacAddOn?.billable === 'boolean') {
|
|
109
|
+
return rbacAddOn.billable;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
if (typeof object?.billable === 'boolean') {
|
|
114
|
+
return object.billable;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
return true;
|
|
118
|
+
}
|
|
@@ -11,7 +11,8 @@ import {
|
|
|
11
11
|
import {
|
|
12
12
|
CRUD_ACTIONS,
|
|
13
13
|
createCrudActionPlans,
|
|
14
|
-
isCrudObject
|
|
14
|
+
isCrudObject,
|
|
15
|
+
VALID_CRUD_GENERATED_BY
|
|
15
16
|
} from './crudActionPlan.js';
|
|
16
17
|
|
|
17
18
|
const ACTIONS = CRUD_ACTIONS;
|
|
@@ -22,12 +23,26 @@ const SHARED_TEMPLATE_URL = new URL('../shared/templates/', import.meta.url);
|
|
|
22
23
|
export async function emitCrudApplicationArtifacts({
|
|
23
24
|
objects,
|
|
24
25
|
flows = [],
|
|
25
|
-
serviceTag
|
|
26
|
+
serviceTag,
|
|
27
|
+
logger
|
|
26
28
|
}) {
|
|
27
29
|
if (!Array.isArray(objects) || !Array.isArray(flows)) {
|
|
28
30
|
throw new TypeError('objects and flows must be arrays');
|
|
29
31
|
}
|
|
30
|
-
if (!objects.some(isCrudObject))
|
|
32
|
+
if (!objects.some(isCrudObject)) {
|
|
33
|
+
if (objects.length > 0) {
|
|
34
|
+
const summary = objects.map((obj) => ({
|
|
35
|
+
objectType: obj?.objectType ?? '(undefined)',
|
|
36
|
+
generatedBy: obj?.generatedBy ?? '(missing)'
|
|
37
|
+
}));
|
|
38
|
+
logger?.warn?.(
|
|
39
|
+
`[WARN] [CRUD Application] Skipped FlowObjects application artifacts generation: No valid CRUD ObjectSchema found. ` +
|
|
40
|
+
`Checked ${objects.length} object(s): ${JSON.stringify(summary)}. ` +
|
|
41
|
+
`Expected "generatedBy" to be one of: ${Array.from(VALID_CRUD_GENERATED_BY).join(', ')}`
|
|
42
|
+
);
|
|
43
|
+
}
|
|
44
|
+
return [];
|
|
45
|
+
}
|
|
31
46
|
|
|
32
47
|
const handlers = await Promise.all(
|
|
33
48
|
ACTIONS.map((action) => emitAction(action, objects, serviceTag))
|
|
@@ -87,7 +102,7 @@ async function emitAction(action, objects, serviceTag) {
|
|
|
87
102
|
flow: null,
|
|
88
103
|
flowStepName: '',
|
|
89
104
|
startConfig: null,
|
|
90
|
-
objects:
|
|
105
|
+
objects: objects,
|
|
91
106
|
isCrudObject,
|
|
92
107
|
hasRbacAddOn: (object) => hasRbacAddOn(object, objects),
|
|
93
108
|
plan
|
|
@@ -3,7 +3,8 @@ import {
|
|
|
3
3
|
CRUD_ACTIONS,
|
|
4
4
|
createCrudActionPlans,
|
|
5
5
|
hasGraphStorageResource,
|
|
6
|
-
isCrudObject
|
|
6
|
+
isCrudObject,
|
|
7
|
+
VALID_CRUD_GENERATED_BY
|
|
7
8
|
} from './crudActionPlan.js';
|
|
8
9
|
|
|
9
10
|
const MESSAGE_ATTRIBUTES = ['userId', 'correlationId'];
|
|
@@ -13,24 +14,44 @@ export const dynamicCrudFlowSchemaPaths = CRUD_ACTIONS.map(
|
|
|
13
14
|
`app/src/schemas/FlowSchemas/generateCode/FlowObjects/${action}.js`
|
|
14
15
|
);
|
|
15
16
|
|
|
16
|
-
export function emitDynamicCrudFlowSchemas({
|
|
17
|
+
export function emitDynamicCrudFlowSchemas({
|
|
18
|
+
objects,
|
|
19
|
+
flows = [],
|
|
20
|
+
serviceTag,
|
|
21
|
+
logger
|
|
22
|
+
}) {
|
|
17
23
|
if (!Array.isArray(objects) || !Array.isArray(flows)) {
|
|
18
24
|
throw new TypeError('objects and flows must be arrays');
|
|
19
25
|
}
|
|
20
|
-
if (!objects.some(isCrudObject))
|
|
26
|
+
if (!objects.some(isCrudObject)) {
|
|
27
|
+
if (objects.length > 0) {
|
|
28
|
+
const summary = objects.map((obj) => ({
|
|
29
|
+
objectType: obj?.objectType ?? '(undefined)',
|
|
30
|
+
generatedBy: obj?.generatedBy ?? '(missing)'
|
|
31
|
+
}));
|
|
32
|
+
logger?.warn?.(
|
|
33
|
+
`[WARN] [CRUD FlowSchemas] Skipped FlowObjects FlowSchemas generation: No valid CRUD ObjectSchema found. ` +
|
|
34
|
+
`Checked ${objects.length} object(s): ${JSON.stringify(summary)}. ` +
|
|
35
|
+
`Expected "generatedBy" to be one of: ${Array.from(VALID_CRUD_GENERATED_BY).join(', ')}`
|
|
36
|
+
);
|
|
37
|
+
}
|
|
38
|
+
return [];
|
|
39
|
+
}
|
|
21
40
|
|
|
22
41
|
const plans = createCrudActionPlans(objects);
|
|
42
|
+
const primaryObject = objects.find(isCrudObject);
|
|
43
|
+
const initiateBy = primaryObject?.generatedBy || 'user';
|
|
23
44
|
|
|
24
45
|
return CRUD_ACTIONS.map((action, index) => ({
|
|
25
46
|
path: dynamicCrudFlowSchemaPaths[index],
|
|
26
47
|
content: renderDynamicCrudFlowSchema(
|
|
27
48
|
action,
|
|
28
|
-
_createDynamicFlow(action, plans[action], serviceTag)
|
|
49
|
+
_createDynamicFlow(action, plans[action], serviceTag, initiateBy)
|
|
29
50
|
)
|
|
30
51
|
}));
|
|
31
52
|
}
|
|
32
53
|
|
|
33
|
-
function _createDynamicFlow(action, plan, serviceTag = '') {
|
|
54
|
+
function _createDynamicFlow(action, plan, serviceTag = '', initiateBy = 'user') {
|
|
34
55
|
const flowSteps = [
|
|
35
56
|
{
|
|
36
57
|
stepName: 'Start',
|
|
@@ -103,7 +124,7 @@ function _createDynamicFlow(action, plan, serviceTag = '') {
|
|
|
103
124
|
|
|
104
125
|
return {
|
|
105
126
|
flowTag: action,
|
|
106
|
-
initiateBy
|
|
127
|
+
initiateBy,
|
|
107
128
|
handleObj: 'one',
|
|
108
129
|
statusType: 'none',
|
|
109
130
|
event: plan.outputTopic ? ['ownTopic'] : ['lambdaSyncInv', 'lambdaSyncApi'],
|
|
@@ -9,10 +9,11 @@ import {
|
|
|
9
9
|
|
|
10
10
|
export async function generateCrudApplicationArtifacts(rootPath, options = {}) {
|
|
11
11
|
const project = compileProject({ ...options, rootPath });
|
|
12
|
-
const schemas = await loadLocalSchemaArrays(project);
|
|
12
|
+
const schemas = await loadLocalSchemaArrays(project, options);
|
|
13
13
|
const artifacts = await emitCrudApplicationArtifacts({
|
|
14
14
|
...schemas,
|
|
15
|
-
serviceTag: project.serviceTag
|
|
15
|
+
serviceTag: project.serviceTag,
|
|
16
|
+
logger: options.logger
|
|
16
17
|
});
|
|
17
18
|
const files = await commitArtifacts(
|
|
18
19
|
buildGenerationPlan(project, artifacts, {
|
|
@@ -9,12 +9,13 @@ import { loadLocalSchemaArrays } from './loadLocalSchemaArrays.js';
|
|
|
9
9
|
|
|
10
10
|
export async function generateDynamicCrudFlowSchemas(rootPath, options = {}) {
|
|
11
11
|
const project = compileProject({ ...options, rootPath });
|
|
12
|
-
const schemaInputs = await loadLocalSchemaArrays(project);
|
|
12
|
+
const schemaInputs = await loadLocalSchemaArrays(project, options);
|
|
13
13
|
const plan = buildGenerationPlan(
|
|
14
14
|
project,
|
|
15
15
|
emitDynamicCrudFlowSchemas({
|
|
16
16
|
...schemaInputs,
|
|
17
|
-
serviceTag: project.serviceTag
|
|
17
|
+
serviceTag: project.serviceTag,
|
|
18
|
+
logger: options.logger
|
|
18
19
|
}),
|
|
19
20
|
{
|
|
20
21
|
managedPaths: dynamicCrudFlowSchemaPaths,
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { loadLocalSchemaDirectory } from '../../compile/loadSchemas.js';
|
|
2
2
|
|
|
3
|
-
export async function loadLocalSchemaArrays(project) {
|
|
3
|
+
export async function loadLocalSchemaArrays(project, options = {}) {
|
|
4
4
|
return {
|
|
5
|
-
objects: await loadLocalSchemaDirectory(project, 'ObjectSchemas'),
|
|
6
|
-
flows: await loadLocalSchemaDirectory(project, 'FlowSchemas')
|
|
5
|
+
objects: await loadLocalSchemaDirectory(project, 'ObjectSchemas', options),
|
|
6
|
+
flows: await loadLocalSchemaDirectory(project, 'FlowSchemas', options)
|
|
7
7
|
};
|
|
8
8
|
}
|
|
@@ -52,7 +52,7 @@ export default async function CreateComplete(
|
|
|
52
52
|
//(</additionalParams>)
|
|
53
53
|
) {
|
|
54
54
|
try {
|
|
55
|
-
_izContext.logger.debug(
|
|
55
|
+
_izContext.logger.debug(`[${process.env.iz_serviceTag}:CreateComplete] started`, {
|
|
56
56
|
requestParams
|
|
57
57
|
});
|
|
58
58
|
const {
|
|
@@ -65,7 +65,7 @@ export default async function <%- flowTag %>(
|
|
|
65
65
|
//(</additionalParams>)
|
|
66
66
|
) {
|
|
67
67
|
try {
|
|
68
|
-
_izContext.logger.debug(
|
|
68
|
+
_izContext.logger.debug(`[${process.env.iz_serviceTag}:<%- flowTag %>] createMain:`, {
|
|
69
69
|
requestParams,
|
|
70
70
|
callingFlowConfig
|
|
71
71
|
});
|
|
@@ -78,16 +78,42 @@ export default async function <%- flowTag %>(
|
|
|
78
78
|
_izContext,
|
|
79
79
|
objType
|
|
80
80
|
);
|
|
81
|
-
_izContext.logger.debug(
|
|
82
|
-
|
|
83
|
-
// ── Resolve
|
|
84
|
-
let
|
|
85
|
-
if (
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
81
|
+
_izContext.logger.debug(`[${process.env.iz_serviceTag}:<%- flowTag %>] objectSchema:`, objectSchema);
|
|
82
|
+
|
|
83
|
+
// ── Resolve submittedByUserId / targetIdentifiers ─────────────────────────
|
|
84
|
+
let submittedByUserId, targetIdentifiers;
|
|
85
|
+
if (
|
|
86
|
+
objectSchema.generatedBy === 'user' ||
|
|
87
|
+
objectSchema.generatedBy === 'systemWithUser'
|
|
88
|
+
) {
|
|
89
|
+
submittedByUserId =
|
|
90
|
+
requestParams.submittedByUserId ||
|
|
91
|
+
_izContext.correlationIds.get(coreConsts.SUBMITTED_BY_USER_ID);
|
|
92
|
+
|
|
93
|
+
targetIdentifiers = requestParams.targetIdentifiers;
|
|
94
|
+
|
|
95
|
+
if (!targetIdentifiers && objectSchema.belongTo?.objectType === 'user' && submittedByUserId) {
|
|
96
|
+
targetIdentifiers = { submittedByUserId };
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
if (!submittedByUserId) errorsFound.push('Not have submittedByUserId');
|
|
100
|
+
if (objectSchema.hasOwnProperty('belongTo') && !targetIdentifiers)
|
|
101
|
+
errorsFound.push('not have targetIdentifiers');
|
|
102
|
+
|
|
103
|
+
requestParams.submittedByUserId = submittedByUserId;
|
|
104
|
+
if (targetIdentifiers) {
|
|
105
|
+
if (!targetIdentifiers.submittedByUserId && submittedByUserId) {
|
|
106
|
+
targetIdentifiers.submittedByUserId = submittedByUserId;
|
|
107
|
+
}
|
|
108
|
+
requestParams.targetIdentifiers = targetIdentifiers;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
_izContext.logger.debug(`[${process.env.iz_serviceTag}:<%- flowTag %>] Identity & Target Context Resolved:`, {
|
|
112
|
+
submittedByUserId: requestParams.submittedByUserId,
|
|
113
|
+
targetIdentifiers: requestParams.targetIdentifiers,
|
|
114
|
+
belongTo: objectSchema.belongTo,
|
|
115
|
+
generatedBy: objectSchema.generatedBy
|
|
116
|
+
});
|
|
91
117
|
} else if (objectSchema.generatedBy === 'searchResultGenerated') {
|
|
92
118
|
throw new NoRetryError(
|
|
93
119
|
'error searchResultGenerated should not happen here'
|
|
@@ -103,14 +129,14 @@ export default async function <%- flowTag %>(
|
|
|
103
129
|
_izContext,
|
|
104
130
|
objectSchema
|
|
105
131
|
);
|
|
106
|
-
_izContext.logger.debug(
|
|
132
|
+
_izContext.logger.debug(`[${process.env.iz_serviceTag}:<%- flowTag %>] objectSchemas:`, objectSchemas);
|
|
107
133
|
|
|
108
134
|
// ── Build createDataDetails ───────────────────────────────────────────────
|
|
109
135
|
const createDataDetails = await createDataDetailsLib(
|
|
110
136
|
_izContext,
|
|
111
137
|
objectSchemas
|
|
112
138
|
);
|
|
113
|
-
_izContext.logger.debug(
|
|
139
|
+
_izContext.logger.debug(`[${process.env.iz_serviceTag}:<%- flowTag %>] createDataDetails:`, createDataDetails);
|
|
114
140
|
|
|
115
141
|
if (requestParams.relationships?.length > 0) {
|
|
116
142
|
//(<beforeValidateRelationships>)
|
|
@@ -124,9 +150,35 @@ export default async function <%- flowTag %>(
|
|
|
124
150
|
requestParams.relationships
|
|
125
151
|
))
|
|
126
152
|
);
|
|
127
|
-
_izContext.logger.debug(
|
|
153
|
+
_izContext.logger.debug(`[${process.env.iz_serviceTag}:<%- flowTag %>] errorsFound:`, errorsFound);
|
|
154
|
+
|
|
155
|
+
// ── Resolve fromRequiredOnCreate fields ──────────────────────────────────
|
|
156
|
+
if (objectSchemas.fieldNames) {
|
|
157
|
+
if (!requestParams.fieldNames) requestParams.fieldNames = {};
|
|
158
|
+
for (const [fieldName, val] of Object.entries(objectSchemas.fieldNames)) {
|
|
159
|
+
if (val.fromRequiredOnCreate && requestParams.fieldNames[fieldName] === undefined) {
|
|
160
|
+
const fromConfig = val.fromRequiredOnCreate;
|
|
161
|
+
const sourceField = fromConfig.fieldName || fieldName;
|
|
162
|
+
if (fromConfig.belongToObjType === true && targetIdentifiers) {
|
|
163
|
+
const targetValue =
|
|
164
|
+
targetIdentifiers[sourceField] !== undefined
|
|
165
|
+
? targetIdentifiers[sourceField]
|
|
166
|
+
: Object.values(targetIdentifiers)[0];
|
|
167
|
+
requestParams.fieldNames[fieldName] = targetValue;
|
|
168
|
+
} else if (fromConfig.relType && requestParams.relationships?.length > 0) {
|
|
169
|
+
const matchedRel = requestParams.relationships.find(
|
|
170
|
+
(rel) =>
|
|
171
|
+
rel.relType?.serviceTag === fromConfig.relType.serviceTag &&
|
|
172
|
+
rel.relType?.relationshipTag === fromConfig.relType.relationshipTag
|
|
173
|
+
);
|
|
174
|
+
if (matchedRel?.targetIdentifiers?.[sourceField] !== undefined) {
|
|
175
|
+
requestParams.fieldNames[fieldName] = matchedRel.targetIdentifiers[sourceField];
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
}
|
|
128
181
|
|
|
129
|
-
// ── Build field lists ─────────────────────────────────────────────────────
|
|
130
182
|
const listOfRequiredOnCreate = [];
|
|
131
183
|
const listOfOptionalOnCreate = [];
|
|
132
184
|
|
|
@@ -134,6 +186,7 @@ export default async function <%- flowTag %>(
|
|
|
134
186
|
if (
|
|
135
187
|
val.randomOnCreate === true ||
|
|
136
188
|
val.requiredOnCreate === true ||
|
|
189
|
+
val.fromRequiredOnCreate ||
|
|
137
190
|
val.hashOnCreate?.length
|
|
138
191
|
) {
|
|
139
192
|
listOfRequiredOnCreate.push(key);
|
|
@@ -177,9 +230,9 @@ export default async function <%- flowTag %>(
|
|
|
177
230
|
}
|
|
178
231
|
}
|
|
179
232
|
|
|
180
|
-
_izContext.logger.debug(
|
|
233
|
+
_izContext.logger.debug(`[${process.env.iz_serviceTag}:<%- flowTag %>] requestParams:`, requestParams);
|
|
181
234
|
errorsFound.push(...errors);
|
|
182
|
-
_izContext.logger.debug(
|
|
235
|
+
_izContext.logger.debug(`[${process.env.iz_serviceTag}:<%- flowTag %>] errorsFound after identifiers:`, errorsFound);
|
|
183
236
|
|
|
184
237
|
if (errorsFound.length > 0)
|
|
185
238
|
return await <%- flowTag %>LogicalLib(
|
|
@@ -216,13 +269,13 @@ export default async function <%- flowTag %>(
|
|
|
216
269
|
});
|
|
217
270
|
}
|
|
218
271
|
if (errorsFound.length > 0) {
|
|
219
|
-
_izContext.logger.debug(
|
|
272
|
+
_izContext.logger.debug(`[${process.env.iz_serviceTag}:<%- flowTag %>] HaveError:`, errorsFound);
|
|
220
273
|
break;
|
|
221
274
|
}
|
|
222
275
|
}
|
|
223
276
|
|
|
224
277
|
<%_
|
|
225
|
-
const rbacObjects = objects.filter(o => (o
|
|
278
|
+
const rbacObjects = objects.filter(o => isCrudObject(o) && hasRbacAddOn(o));
|
|
226
279
|
const rbacObjectTypes = rbacObjects.map(o => o.objectType);
|
|
227
280
|
const rbacServiceTagMap = {};
|
|
228
281
|
for (const o of rbacObjects) {
|
|
@@ -265,12 +318,12 @@ export default async function <%- flowTag %>(
|
|
|
265
318
|
serviceTag: <%- rbacServiceTags.length === 1 ? rbacServiceTags[0] : `{ ${Object.entries(rbacServiceTagMap).map(([k, v]) => `'${k}': ${v}`).join(', ')} }[requestParams.objectType] || process.env.iz_serviceTag` %>
|
|
266
319
|
},
|
|
267
320
|
requestParams: requestParams,
|
|
268
|
-
nextFlowStepName: '<%- flowTag %>
|
|
321
|
+
nextFlowStepName: '<%- plan?.hasRbacCallback ? `${flowTag}RbacCallback` : `${flowTag}Complete` %>'
|
|
269
322
|
}
|
|
270
323
|
);
|
|
271
324
|
|
|
272
325
|
_izContext.logger.debug(
|
|
273
|
-
|
|
326
|
+
`[${process.env.iz_serviceTag}:<%- flowTag %>] checkRbacPermission result:`,
|
|
274
327
|
resultPermissionCheck
|
|
275
328
|
);
|
|
276
329
|
|
|
@@ -436,6 +489,7 @@ export default async function <%- flowTag %>(
|
|
|
436
489
|
errorsFound
|
|
437
490
|
);
|
|
438
491
|
} catch (err) {
|
|
492
|
+
_izContext.logger.error(`[${process.env.iz_serviceTag}:<%- flowTag %>] error:`, err);
|
|
439
493
|
throw err;
|
|
440
494
|
}
|
|
441
495
|
}
|
|
@@ -77,10 +77,11 @@ export async function <%- flowTag %>LogicalLib(
|
|
|
77
77
|
phaseResults = {}
|
|
78
78
|
) {
|
|
79
79
|
try {
|
|
80
|
-
_izContext.logger.debug(
|
|
80
|
+
_izContext.logger.debug(`[${process.env.iz_serviceTag}:<%- flowTag %>LogicalLib] started`, {
|
|
81
81
|
requestParams,
|
|
82
82
|
callingFlowConfig,
|
|
83
|
-
phaseResults
|
|
83
|
+
phaseResults,
|
|
84
|
+
targetIdentifiers: requestParams.targetIdentifiers
|
|
84
85
|
});
|
|
85
86
|
|
|
86
87
|
//(<beforeCreateMainLogical>)
|
|
@@ -93,14 +94,14 @@ export async function <%- flowTag %>LogicalLib(
|
|
|
93
94
|
_izContext,
|
|
94
95
|
objType
|
|
95
96
|
);
|
|
96
|
-
_izContext.logger.debug(
|
|
97
|
+
_izContext.logger.debug(`[${process.env.iz_serviceTag}:<%- flowTag %>LogicalLib] objectSchema:`, objectSchema);
|
|
97
98
|
|
|
98
99
|
const objectSchemas =
|
|
99
100
|
uploadUseCase.generateObjectSchemaForCombineFieldNames(
|
|
100
101
|
_izContext,
|
|
101
102
|
objectSchema
|
|
102
103
|
);
|
|
103
|
-
_izContext.logger.debug(
|
|
104
|
+
_izContext.logger.debug(`[${process.env.iz_serviceTag}:<%- flowTag %>LogicalLib] objectSchemas:`, objectSchemas);
|
|
104
105
|
|
|
105
106
|
// ── Parent object ─────────────────────────────────────────────────────────
|
|
106
107
|
let parentObject;
|
|
@@ -121,7 +122,7 @@ export async function <%- flowTag %>LogicalLib(
|
|
|
121
122
|
_izContext,
|
|
122
123
|
objectSchemas
|
|
123
124
|
);
|
|
124
|
-
_izContext.logger.debug(
|
|
125
|
+
_izContext.logger.debug(`[${process.env.iz_serviceTag}:<%- flowTag %>LogicalLib] createDataDetails:`, createDataDetails);
|
|
125
126
|
|
|
126
127
|
// ── Build objInstanceFull identifiers ─────────────────────────────────────
|
|
127
128
|
const objInstanceFull = { identifiers: {}, fields: {} };
|
|
@@ -177,7 +178,7 @@ export async function <%- flowTag %>LogicalLib(
|
|
|
177
178
|
|
|
178
179
|
// ── DynamoDB ──────────────────────────────────────────────────────────
|
|
179
180
|
if (createDataDetail.storageType === consts.STORAGE_TYPES.dynamoDB) {
|
|
180
|
-
_izContext.logger.debug(
|
|
181
|
+
_izContext.logger.debug(`[${process.env.iz_serviceTag}:<%- flowTag %>LogicalLib] DynamoDB:`, {
|
|
181
182
|
storageTag,
|
|
182
183
|
objInstanceFull
|
|
183
184
|
});
|
|
@@ -256,6 +257,66 @@ export async function <%- flowTag %>LogicalLib(
|
|
|
256
257
|
);
|
|
257
258
|
|
|
258
259
|
objInstanceFullForDynamoDb.fields = {};
|
|
260
|
+
|
|
261
|
+
// ── Auto-provision owner TargetRole for Root Object with RBAC ─────
|
|
262
|
+
const hasRbacAddOn = Array.isArray(objectSchema?.addOnDataStructure) &&
|
|
263
|
+
objectSchema.addOnDataStructure.some((addOn) => addOn?.type === 'rbac');
|
|
264
|
+
const isRootRbacObject =
|
|
265
|
+
hasRbacAddOn &&
|
|
266
|
+
!objectSchema?.belongTo &&
|
|
267
|
+
objectSchema?.objectType !== 'user' &&
|
|
268
|
+
objectSchema?.generatedBy !== 'systemNoUser';
|
|
269
|
+
|
|
270
|
+
if (isRootRbacObject) {
|
|
271
|
+
try {
|
|
272
|
+
const submittedByUserId = requestParams.submittedByUserId || _izContext.correlationIds.get(coreConsts.SUBMITTED_BY_USER_ID);
|
|
273
|
+
if (submittedByUserId) {
|
|
274
|
+
const targetIdentKeys = Object.entries(identifiersForCreateData)
|
|
275
|
+
.map(([k, v]) => `${k}#${v}`)
|
|
276
|
+
.join('_');
|
|
277
|
+
const targetIdentifiersConcat = targetIdentKeys || (identifiersForCreateData[Object.keys(identifiersForCreateData)[0]] ? `${Object.keys(identifiersForCreateData)[0]}#${identifiersForCreateData[Object.keys(identifiersForCreateData)[0]]}` : '');
|
|
278
|
+
|
|
279
|
+
if (targetIdentifiersConcat) {
|
|
280
|
+
const roleIdKey = `${targetIdentifiersConcat}_owner`;
|
|
281
|
+
_izContext.logger.debug('[CreateLogicalLib] Auto-provisioning owner TargetRole:', {
|
|
282
|
+
identifiersConcat: targetIdentifiersConcat,
|
|
283
|
+
roleIdKey,
|
|
284
|
+
submittedByUserId,
|
|
285
|
+
roleName: 'owner'
|
|
286
|
+
});
|
|
287
|
+
|
|
288
|
+
await dynamodbSharedLib.putItem(
|
|
289
|
+
_izContext,
|
|
290
|
+
dynamodbSharedLib.tableName(_izContext, 'TargetRoles'),
|
|
291
|
+
{
|
|
292
|
+
identifiersConcat: targetIdentifiersConcat,
|
|
293
|
+
roleIdKey,
|
|
294
|
+
submittedByUserId,
|
|
295
|
+
roleName: 'owner',
|
|
296
|
+
assignedAt: new Date().toISOString()
|
|
297
|
+
}
|
|
298
|
+
).catch(() => {});
|
|
299
|
+
|
|
300
|
+
await dynamodbSharedLib.transactWriteItems(_izContext, [
|
|
301
|
+
{
|
|
302
|
+
Put: {
|
|
303
|
+
TableName: dynamodbSharedLib.tableName(_izContext, 'RoleUsers'),
|
|
304
|
+
Item: { roleIdKey, submittedByUserId }
|
|
305
|
+
}
|
|
306
|
+
},
|
|
307
|
+
{
|
|
308
|
+
Put: {
|
|
309
|
+
TableName: dynamodbSharedLib.tableName(_izContext, 'UserRoles'),
|
|
310
|
+
Item: { submittedByUserId, roleIdKey }
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
]).catch(() => {});
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
} catch (roleError) {
|
|
317
|
+
_izContext.logger.warn('[CreateLogicalLib] Failed to auto-provision owner TargetRole:', { roleError });
|
|
318
|
+
}
|
|
319
|
+
}
|
|
259
320
|
}
|
|
260
321
|
|
|
261
322
|
//(<afterCreateRecordDynamo>)
|
|
@@ -267,7 +328,7 @@ export async function <%- flowTag %>LogicalLib(
|
|
|
267
328
|
) {
|
|
268
329
|
//(<beforeCreateNode>)
|
|
269
330
|
//(</beforeCreateNode>)
|
|
270
|
-
_izContext.logger.debug(
|
|
331
|
+
_izContext.logger.debug(`[${process.env.iz_serviceTag}:<%- flowTag %>LogicalLib] Graph:`, {
|
|
271
332
|
storageTag,
|
|
272
333
|
objInstanceFull
|
|
273
334
|
});
|
|
@@ -435,6 +496,7 @@ export async function <%- flowTag %>LogicalLib(
|
|
|
435
496
|
objType,
|
|
436
497
|
objInstanceFull: objInstanceFullForGraph,
|
|
437
498
|
relationships: requestParams.relationships || [],
|
|
499
|
+
targetIdentifiers: requestParams.targetIdentifiers,
|
|
438
500
|
status: 'complete',
|
|
439
501
|
errorsFound
|
|
440
502
|
};
|
|
@@ -444,7 +506,7 @@ export async function <%- flowTag %>LogicalLib(
|
|
|
444
506
|
|
|
445
507
|
// ── Handle errors ─────────────────────────────────────────────────────────
|
|
446
508
|
if (errorsFound.length > 0) {
|
|
447
|
-
_izContext.logger.debug(
|
|
509
|
+
_izContext.logger.debug(`[${process.env.iz_serviceTag}:<%- flowTag %>LogicalLib] errorsFound:`, errorsFound);
|
|
448
510
|
|
|
449
511
|
await asyncFlowSharedLib.clearAllAwaitingSteps(
|
|
450
512
|
_izContext,
|
|
@@ -479,6 +541,7 @@ export async function <%- flowTag %>LogicalLib(
|
|
|
479
541
|
objType,
|
|
480
542
|
objInstanceFull,
|
|
481
543
|
relationships: requestParams.relationships || [],
|
|
544
|
+
targetIdentifiers: requestParams.targetIdentifiers,
|
|
482
545
|
status: 'error',
|
|
483
546
|
errorsFound
|
|
484
547
|
};
|
|
@@ -529,10 +592,12 @@ export async function <%- flowTag %>LogicalLib(
|
|
|
529
592
|
fields: objInstanceFullForDynamoDb.fields
|
|
530
593
|
},
|
|
531
594
|
relationships: requestParams.relationships || [],
|
|
595
|
+
targetIdentifiers: requestParams.targetIdentifiers,
|
|
532
596
|
status: 'complete',
|
|
533
597
|
errorsFound
|
|
534
598
|
};
|
|
535
599
|
} catch (err) {
|
|
600
|
+
_izContext.logger.error(`[${process.env.iz_serviceTag}:<%- flowTag %>LogicalLib] error:`, err);
|
|
536
601
|
throw err;
|
|
537
602
|
}
|
|
538
603
|
}
|
|
@@ -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 {
|