@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,163 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Copyright (C) 2020 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 dynamodbSharedLib from '@izara_project/izara-core-library-dynamodb';
|
|
19
|
+
import snsSharedLib from '@izara_project/izara-core-library-sns';
|
|
20
|
+
import { sns } from '@izara_project/izara-core-library-external-request';
|
|
21
|
+
import { consts, NoRetryError } from '@izara_project/izara-core-library-core';
|
|
22
|
+
|
|
23
|
+
export default async function CancelUsage(_izContext, requestParams) {
|
|
24
|
+
try {
|
|
25
|
+
let runningTotalReservedId =
|
|
26
|
+
requestParams?.runningTotalReservedId ||
|
|
27
|
+
requestParams?.reservedId ||
|
|
28
|
+
requestParams?.runningTotalReservedUsageId;
|
|
29
|
+
|
|
30
|
+
const usedTimestampId =
|
|
31
|
+
requestParams?.usedTimestampId ||
|
|
32
|
+
requestParams?.uniqueIdentify;
|
|
33
|
+
|
|
34
|
+
const submittedByUserId =
|
|
35
|
+
requestParams?.submittedByUserId ||
|
|
36
|
+
_izContext.correlationIds?.get(consts.SUBMITTED_BY_USER_ID);
|
|
37
|
+
const flowTypeConcat =
|
|
38
|
+
requestParams?.flowTypeConcat ||
|
|
39
|
+
requestParams?.limitTag;
|
|
40
|
+
|
|
41
|
+
const targetIdentifiers = requestParams?.targetIdentifiers;
|
|
42
|
+
let identifiersConcat = requestParams?.identifiersConcat;
|
|
43
|
+
if (!identifiersConcat && targetIdentifiers && typeof targetIdentifiers === 'object') {
|
|
44
|
+
if (targetIdentifiers.identifierConcat) {
|
|
45
|
+
identifiersConcat = targetIdentifiers.identifierConcat;
|
|
46
|
+
} else {
|
|
47
|
+
const sortedKeys = Object.keys(targetIdentifiers).sort();
|
|
48
|
+
const parts = [];
|
|
49
|
+
for (const key of sortedKeys) {
|
|
50
|
+
const value = targetIdentifiers[key];
|
|
51
|
+
if (
|
|
52
|
+
key !== 'submittedByUserId' &&
|
|
53
|
+
key !== 'identifierConcat' &&
|
|
54
|
+
value !== undefined &&
|
|
55
|
+
value !== null
|
|
56
|
+
) {
|
|
57
|
+
parts.push(`${key}#${value}`);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
if (parts.length > 0) {
|
|
61
|
+
identifiersConcat = parts.join('|');
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
if (!identifiersConcat) {
|
|
66
|
+
identifiersConcat = submittedByUserId;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
if (!runningTotalReservedId) {
|
|
70
|
+
if (identifiersConcat && flowTypeConcat) {
|
|
71
|
+
runningTotalReservedId = `${identifiersConcat}_${flowTypeConcat}`;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
if (!runningTotalReservedId || !usedTimestampId) {
|
|
76
|
+
throw new NoRetryError(
|
|
77
|
+
'runningTotalReservedId (or identifiersConcat + flowTypeConcat) and usedTimestampId (or uniqueIdentify) are required.'
|
|
78
|
+
);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
const reservedRecord = await dynamodbSharedLib.getItem(
|
|
82
|
+
_izContext,
|
|
83
|
+
dynamodbSharedLib.tableName(_izContext, 'RunningTotalReservedUsage'),
|
|
84
|
+
{
|
|
85
|
+
runningTotalReservedId,
|
|
86
|
+
usedTimestampId
|
|
87
|
+
}
|
|
88
|
+
);
|
|
89
|
+
|
|
90
|
+
const usageCount = reservedRecord?.usageCount || 0;
|
|
91
|
+
|
|
92
|
+
await dynamodbSharedLib.updateItem(
|
|
93
|
+
_izContext,
|
|
94
|
+
dynamodbSharedLib.tableName(_izContext, 'RunningTotalReservedUsage'),
|
|
95
|
+
{
|
|
96
|
+
runningTotalReservedId,
|
|
97
|
+
usedTimestampId
|
|
98
|
+
},
|
|
99
|
+
{
|
|
100
|
+
runningTotalUsageStatus: 'cancelled'
|
|
101
|
+
}
|
|
102
|
+
);
|
|
103
|
+
|
|
104
|
+
if (usageCount > 0 && identifiersConcat && flowTypeConcat) {
|
|
105
|
+
const usageRecord = await dynamodbSharedLib.getItem(
|
|
106
|
+
_izContext,
|
|
107
|
+
dynamodbSharedLib.tableName(_izContext, 'RunningTotalUsage'),
|
|
108
|
+
{ identifiersConcat, flowTypeConcat }
|
|
109
|
+
);
|
|
110
|
+
if (usageRecord) {
|
|
111
|
+
const currentTotal = usageRecord.totalCount || 0;
|
|
112
|
+
const newTotal = Math.max(0, currentTotal - usageCount);
|
|
113
|
+
const queryElementsWhenUpdate = {
|
|
114
|
+
additionalAttributes: { currentUuid: usageRecord.updateUuid },
|
|
115
|
+
logicalElements: [
|
|
116
|
+
{
|
|
117
|
+
type: 'logical',
|
|
118
|
+
comparison: 'equals',
|
|
119
|
+
lhsAttribute: 'updateUuid',
|
|
120
|
+
rhsReference: 'currentUuid'
|
|
121
|
+
}
|
|
122
|
+
],
|
|
123
|
+
returnValues: 'ALL_NEW'
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
const updateAttributes = [
|
|
127
|
+
{ attributeName: 'totalCount', action: 'set', value: newTotal },
|
|
128
|
+
{ attributeName: 'updateUuid', action: 'set', value: _izContext.uniqueRequestId || `${Date.now()}` }
|
|
129
|
+
];
|
|
130
|
+
|
|
131
|
+
await dynamodbSharedLib.updateItem(
|
|
132
|
+
_izContext,
|
|
133
|
+
dynamodbSharedLib.tableName(_izContext, 'RunningTotalUsage'),
|
|
134
|
+
{ identifiersConcat, flowTypeConcat },
|
|
135
|
+
updateAttributes,
|
|
136
|
+
queryElementsWhenUpdate,
|
|
137
|
+
{
|
|
138
|
+
complexAttributes: true,
|
|
139
|
+
errorOnConditionalExpNotPass: false
|
|
140
|
+
}
|
|
141
|
+
).catch(() => null);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
await sns.publishMessage(_izContext, {
|
|
146
|
+
message: {
|
|
147
|
+
returnResult: {
|
|
148
|
+
status: true,
|
|
149
|
+
uniqueIdentify: usedTimestampId,
|
|
150
|
+
usedTimestampId,
|
|
151
|
+
runningTotalReservedId
|
|
152
|
+
}
|
|
153
|
+
},
|
|
154
|
+
TopicArn: snsSharedLib.snsTopicArnByFlowSchema(
|
|
155
|
+
_izContext,
|
|
156
|
+
'CancelUsage_Out'
|
|
157
|
+
)
|
|
158
|
+
});
|
|
159
|
+
} catch (error) {
|
|
160
|
+
_izContext.logger.error(`[${process.env.iz_serviceTag}:CancelUsage] error:`, error);
|
|
161
|
+
throw error;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Copyright (C) 2020 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 dynamodbSharedLib from '@izara_project/izara-core-library-dynamodb';
|
|
19
|
+
import snsSharedLib from '@izara_project/izara-core-library-sns';
|
|
20
|
+
import { sns } from '@izara_project/izara-core-library-external-request';
|
|
21
|
+
import { consts, NoRetryError } from '@izara_project/izara-core-library-core';
|
|
22
|
+
|
|
23
|
+
export default async function ConfirmUsage(_izContext, requestParams) {
|
|
24
|
+
try {
|
|
25
|
+
let runningTotalReservedId =
|
|
26
|
+
requestParams?.runningTotalReservedId ||
|
|
27
|
+
requestParams?.reservedId ||
|
|
28
|
+
requestParams?.runningTotalReservedUsageId;
|
|
29
|
+
|
|
30
|
+
const usedTimestampId =
|
|
31
|
+
requestParams?.usedTimestampId ||
|
|
32
|
+
requestParams?.uniqueIdentify;
|
|
33
|
+
|
|
34
|
+
const submittedByUserId =
|
|
35
|
+
requestParams?.submittedByUserId ||
|
|
36
|
+
_izContext.correlationIds?.get(consts.SUBMITTED_BY_USER_ID);
|
|
37
|
+
const flowTypeConcat =
|
|
38
|
+
requestParams?.flowTypeConcat ||
|
|
39
|
+
requestParams?.limitTag;
|
|
40
|
+
|
|
41
|
+
const targetIdentifiers = requestParams?.targetIdentifiers;
|
|
42
|
+
let identifiersConcat = requestParams?.identifiersConcat;
|
|
43
|
+
if (!identifiersConcat && targetIdentifiers && typeof targetIdentifiers === 'object') {
|
|
44
|
+
if (targetIdentifiers.identifierConcat) {
|
|
45
|
+
identifiersConcat = targetIdentifiers.identifierConcat;
|
|
46
|
+
} else {
|
|
47
|
+
const sortedKeys = Object.keys(targetIdentifiers).sort();
|
|
48
|
+
const parts = [];
|
|
49
|
+
for (const key of sortedKeys) {
|
|
50
|
+
const value = targetIdentifiers[key];
|
|
51
|
+
if (
|
|
52
|
+
key !== 'submittedByUserId' &&
|
|
53
|
+
key !== 'identifierConcat' &&
|
|
54
|
+
value !== undefined &&
|
|
55
|
+
value !== null
|
|
56
|
+
) {
|
|
57
|
+
parts.push(`${key}#${value}`);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
if (parts.length > 0) {
|
|
61
|
+
identifiersConcat = parts.join('|');
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
if (!identifiersConcat) {
|
|
66
|
+
identifiersConcat = submittedByUserId;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
if (!runningTotalReservedId) {
|
|
70
|
+
if (identifiersConcat && flowTypeConcat) {
|
|
71
|
+
runningTotalReservedId = `${identifiersConcat}_${flowTypeConcat}`;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
if (!runningTotalReservedId || !usedTimestampId) {
|
|
76
|
+
throw new NoRetryError(
|
|
77
|
+
'runningTotalReservedId (or identifiersConcat + flowTypeConcat) and usedTimestampId (or uniqueIdentify) are required.'
|
|
78
|
+
);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
const reservedTable = dynamodbSharedLib.tableName(
|
|
82
|
+
_izContext,
|
|
83
|
+
'RunningTotalReservedUsage'
|
|
84
|
+
);
|
|
85
|
+
|
|
86
|
+
const reservedRecord = await dynamodbSharedLib
|
|
87
|
+
.getItem(_izContext, reservedTable, {
|
|
88
|
+
runningTotalReservedId,
|
|
89
|
+
usedTimestampId
|
|
90
|
+
})
|
|
91
|
+
.catch(() => null);
|
|
92
|
+
|
|
93
|
+
let usageCount = 1;
|
|
94
|
+
if (reservedRecord && typeof reservedRecord.usageCount === 'number') {
|
|
95
|
+
usageCount = reservedRecord.usageCount;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
await dynamodbSharedLib.updateItem(
|
|
99
|
+
_izContext,
|
|
100
|
+
reservedTable,
|
|
101
|
+
{
|
|
102
|
+
runningTotalReservedId,
|
|
103
|
+
usedTimestampId
|
|
104
|
+
},
|
|
105
|
+
{
|
|
106
|
+
runningTotalUsageStatus: 'confirmed',
|
|
107
|
+
confirmedAt: new Date().toISOString()
|
|
108
|
+
}
|
|
109
|
+
);
|
|
110
|
+
|
|
111
|
+
if (identifiersConcat && flowTypeConcat) {
|
|
112
|
+
const usageTable = dynamodbSharedLib.tableName(
|
|
113
|
+
_izContext,
|
|
114
|
+
'RunningTotalUsage'
|
|
115
|
+
);
|
|
116
|
+
|
|
117
|
+
const usageRecord = await dynamodbSharedLib
|
|
118
|
+
.getItem(_izContext, usageTable, {
|
|
119
|
+
identifiersConcat,
|
|
120
|
+
flowTypeConcat
|
|
121
|
+
})
|
|
122
|
+
.catch(() => null);
|
|
123
|
+
|
|
124
|
+
let currentTotal = 0;
|
|
125
|
+
let queryElementsWhenUpdate = {};
|
|
126
|
+
|
|
127
|
+
if (usageRecord && typeof usageRecord.totalCount === 'number') {
|
|
128
|
+
currentTotal = usageRecord.totalCount;
|
|
129
|
+
queryElementsWhenUpdate = {
|
|
130
|
+
additionalAttributes: { currentUuid: usageRecord.updateUuid },
|
|
131
|
+
logicalElements: [
|
|
132
|
+
{
|
|
133
|
+
type: 'logical',
|
|
134
|
+
comparison: 'equals',
|
|
135
|
+
lhsAttribute: 'updateUuid',
|
|
136
|
+
rhsReference: 'currentUuid'
|
|
137
|
+
}
|
|
138
|
+
],
|
|
139
|
+
returnValues: 'ALL_NEW'
|
|
140
|
+
};
|
|
141
|
+
} else {
|
|
142
|
+
queryElementsWhenUpdate = {
|
|
143
|
+
logicalElements: dynamodbSharedLib.generateNotExistLogicalElements({
|
|
144
|
+
identifiersConcat,
|
|
145
|
+
flowTypeConcat
|
|
146
|
+
}),
|
|
147
|
+
returnValues: 'ALL_NEW'
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
const updateAttributes = [
|
|
152
|
+
{ attributeName: 'totalCount', action: 'set', value: currentTotal + usageCount },
|
|
153
|
+
{ attributeName: 'updateUuid', action: 'set', value: _izContext.uniqueRequestId || `${Date.now()}` }
|
|
154
|
+
];
|
|
155
|
+
|
|
156
|
+
await dynamodbSharedLib.updateItem(
|
|
157
|
+
_izContext,
|
|
158
|
+
usageTable,
|
|
159
|
+
{ identifiersConcat, flowTypeConcat },
|
|
160
|
+
updateAttributes,
|
|
161
|
+
queryElementsWhenUpdate,
|
|
162
|
+
{
|
|
163
|
+
complexAttributes: true,
|
|
164
|
+
errorOnConditionalExpNotPass: false
|
|
165
|
+
}
|
|
166
|
+
).catch(() => null);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
await sns.publishMessage(_izContext, {
|
|
170
|
+
message: {
|
|
171
|
+
returnResult: {
|
|
172
|
+
status: true,
|
|
173
|
+
uniqueIdentify: usedTimestampId,
|
|
174
|
+
usedTimestampId,
|
|
175
|
+
runningTotalReservedId
|
|
176
|
+
}
|
|
177
|
+
},
|
|
178
|
+
TopicArn: snsSharedLib.snsTopicArnByFlowSchema(
|
|
179
|
+
_izContext,
|
|
180
|
+
'ConfirmUsage_Out'
|
|
181
|
+
)
|
|
182
|
+
});
|
|
183
|
+
} catch (error) {
|
|
184
|
+
_izContext.logger.error(`[${process.env.iz_serviceTag}:ConfirmUsage] error:`, error);
|
|
185
|
+
throw error;
|
|
186
|
+
}
|
|
187
|
+
}
|
|
@@ -23,23 +23,85 @@ import { consts } from '@izara_project/izara-core-library-core';
|
|
|
23
23
|
|
|
24
24
|
export default async function CreateTargetRole(_izContext, requestParams) {
|
|
25
25
|
try {
|
|
26
|
-
const
|
|
27
|
-
|
|
28
|
-
|
|
26
|
+
const submittedByUserId =
|
|
27
|
+
requestParams.submittedByUserId ||
|
|
28
|
+
_izContext.correlationIds?.get(consts.SUBMITTED_BY_USER_ID);
|
|
29
|
+
|
|
30
|
+
const targetIdentifiers = requestParams.targetIdentifiers;
|
|
31
|
+
let identifiersConcat = requestParams.identifiersConcat;
|
|
32
|
+
if (!identifiersConcat && targetIdentifiers && typeof targetIdentifiers === 'object') {
|
|
33
|
+
if (targetIdentifiers.identifierConcat) {
|
|
34
|
+
identifiersConcat = targetIdentifiers.identifierConcat;
|
|
35
|
+
} else {
|
|
36
|
+
const sortedKeys = Object.keys(targetIdentifiers).sort();
|
|
37
|
+
const parts = [];
|
|
38
|
+
for (const key of sortedKeys) {
|
|
39
|
+
const value = targetIdentifiers[key];
|
|
40
|
+
if (
|
|
41
|
+
key !== 'submittedByUserId' &&
|
|
42
|
+
key !== 'identifierConcat' &&
|
|
43
|
+
value !== undefined &&
|
|
44
|
+
value !== null
|
|
45
|
+
) {
|
|
46
|
+
parts.push(`${key}#${value}`);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
if (parts.length > 0) {
|
|
50
|
+
identifiersConcat = parts.join('|');
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
if (!identifiersConcat) {
|
|
55
|
+
identifiersConcat = submittedByUserId;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const { roleName = 'owner', roleId: inputRoleId } = requestParams;
|
|
59
|
+
const roleId = inputRoleId || roleName || identifierUuid();
|
|
60
|
+
const roleIdKey = `${identifiersConcat}_${roleId}`;
|
|
61
|
+
|
|
29
62
|
await dynamodbSharedLib.putItem(
|
|
30
63
|
_izContext,
|
|
31
64
|
dynamodbSharedLib.tableName(_izContext, 'TargetRoles'),
|
|
32
|
-
{
|
|
65
|
+
{
|
|
66
|
+
identifiersConcat,
|
|
67
|
+
roleIdKey,
|
|
68
|
+
roleName,
|
|
69
|
+
submittedByUserId
|
|
70
|
+
}
|
|
33
71
|
);
|
|
72
|
+
|
|
73
|
+
if (submittedByUserId) {
|
|
74
|
+
try {
|
|
75
|
+
await dynamodbSharedLib.transactWriteItems(_izContext, [
|
|
76
|
+
{
|
|
77
|
+
action: 'put',
|
|
78
|
+
params: {
|
|
79
|
+
tableName: dynamodbSharedLib.tableName(_izContext, 'RoleUsers'),
|
|
80
|
+
attributes: { roleIdKey, submittedByUserId }
|
|
81
|
+
}
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
action: 'put',
|
|
85
|
+
params: {
|
|
86
|
+
tableName: dynamodbSharedLib.tableName(_izContext, 'UserRoles'),
|
|
87
|
+
attributes: { submittedByUserId, roleIdKey }
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
]);
|
|
91
|
+
} catch (assignError) {
|
|
92
|
+
_izContext.logger.debug(`[${process.env.iz_serviceTag}:CreateTargetRole] UserRoles transactWrite ignored:`, assignError);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
34
96
|
await sns.publishMessage(_izContext, {
|
|
35
|
-
message: { returnResult: { roleId } },
|
|
97
|
+
message: { returnResult: { roleId, roleIdKey } },
|
|
36
98
|
TopicArn: snsSharedLib.snsTopicArnByFlowSchema(
|
|
37
99
|
_izContext,
|
|
38
100
|
'CreateTargetRole_Out'
|
|
39
101
|
)
|
|
40
102
|
});
|
|
41
103
|
} catch (error) {
|
|
42
|
-
_izContext.logger.error(
|
|
104
|
+
_izContext.logger.error(`[${process.env.iz_serviceTag}:CreateTargetRole] error:`, error);
|
|
43
105
|
throw error;
|
|
44
106
|
}
|
|
45
107
|
}
|
|
@@ -22,8 +22,14 @@ import { consts, NoRetryError } from '@izara_project/izara-core-library-core';
|
|
|
22
22
|
|
|
23
23
|
export default async function <%- flowTag %>(_izContext, requestParams) {
|
|
24
24
|
try {
|
|
25
|
-
<% if (
|
|
26
|
-
const userId = _izContext.correlationIds.get(consts.
|
|
25
|
+
<% if (flowTag === 'ListTargetRole') { -%>
|
|
26
|
+
const userId = requestParams.submittedByUserId || _izContext.correlationIds.get(consts.SUBMITTED_BY_USER_ID);
|
|
27
|
+
const identifiersConcat =
|
|
28
|
+
requestParams.identifiersConcat || requestParams.targetId || userId;
|
|
29
|
+
if (!identifiersConcat) throw new NoRetryError('Identifier not found.');
|
|
30
|
+
const queryParams = { identifiersConcat };
|
|
31
|
+
<% } else if (useContextUserId) { -%>
|
|
32
|
+
const userId = requestParams.submittedByUserId || _izContext.correlationIds.get(consts.SUBMITTED_BY_USER_ID);
|
|
27
33
|
if (!userId) throw new NoRetryError('User Id not found.');
|
|
28
34
|
const queryParams = { userId };
|
|
29
35
|
<% } else { -%>
|
|
@@ -43,7 +49,7 @@ export default async function <%- flowTag %>(_izContext, requestParams) {
|
|
|
43
49
|
)
|
|
44
50
|
});
|
|
45
51
|
} catch (error) {
|
|
46
|
-
_izContext.logger.error(
|
|
52
|
+
_izContext.logger.error(`[${process.env.iz_serviceTag}:<%- flowTag %>] error:`, error);
|
|
47
53
|
throw error;
|
|
48
54
|
}
|
|
49
55
|
}
|
|
@@ -36,7 +36,7 @@ export default async function <%- flowTag %>(_izContext, requestParams) {
|
|
|
36
36
|
)
|
|
37
37
|
});
|
|
38
38
|
} catch (error) {
|
|
39
|
-
_izContext.logger.error(
|
|
39
|
+
_izContext.logger.error(`[${process.env.iz_serviceTag}:<%- flowTag %>] error:`, error);
|
|
40
40
|
throw error;
|
|
41
41
|
}
|
|
42
42
|
}
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Copyright (C) 2020 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 dynamodbSharedLib from '@izara_project/izara-core-library-dynamodb';
|
|
19
|
+
import snsSharedLib from '@izara_project/izara-core-library-sns';
|
|
20
|
+
import { sns } from '@izara_project/izara-core-library-external-request';
|
|
21
|
+
import { consts, NoRetryError } from '@izara_project/izara-core-library-core';
|
|
22
|
+
|
|
23
|
+
export default async function ReservedDynamicUsage(_izContext, requestParams) {
|
|
24
|
+
try {
|
|
25
|
+
const submittedByUserId =
|
|
26
|
+
requestParams.submittedByUserId ||
|
|
27
|
+
_izContext.correlationIds?.get(consts.SUBMITTED_BY_USER_ID);
|
|
28
|
+
const flowTypeConcat =
|
|
29
|
+
requestParams.flowTypeConcat ||
|
|
30
|
+
requestParams.limitTag;
|
|
31
|
+
const {
|
|
32
|
+
value = 1,
|
|
33
|
+
usedTimestamp = new Date().toISOString(),
|
|
34
|
+
roleLimitId
|
|
35
|
+
} = requestParams;
|
|
36
|
+
|
|
37
|
+
const targetIdentifiers = requestParams.targetIdentifiers;
|
|
38
|
+
let identifiersConcat = requestParams.identifiersConcat;
|
|
39
|
+
if (!identifiersConcat && targetIdentifiers && typeof targetIdentifiers === 'object') {
|
|
40
|
+
if (targetIdentifiers.identifierConcat) {
|
|
41
|
+
identifiersConcat = targetIdentifiers.identifierConcat;
|
|
42
|
+
} else {
|
|
43
|
+
const sortedKeys = Object.keys(targetIdentifiers).sort();
|
|
44
|
+
const parts = [];
|
|
45
|
+
for (const key of sortedKeys) {
|
|
46
|
+
const value = targetIdentifiers[key];
|
|
47
|
+
if (
|
|
48
|
+
key !== 'submittedByUserId' &&
|
|
49
|
+
key !== 'identifierConcat' &&
|
|
50
|
+
value !== undefined &&
|
|
51
|
+
value !== null
|
|
52
|
+
) {
|
|
53
|
+
parts.push(`${key}#${value}`);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
if (parts.length > 0) {
|
|
57
|
+
identifiersConcat = parts.join('|');
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
if (!identifiersConcat) {
|
|
62
|
+
identifiersConcat = submittedByUserId;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
if (!identifiersConcat) {
|
|
66
|
+
throw new NoRetryError('Identifier not found.');
|
|
67
|
+
}
|
|
68
|
+
if (!flowTypeConcat) {
|
|
69
|
+
throw new NoRetryError('flowTypeConcat (or limitTag) is required.');
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
const uniqueIdentify = `${usedTimestamp}_${_izContext.uniqueRequestId || Date.now()}`;
|
|
73
|
+
const roleLimitKeys = Array.isArray(requestParams.roleLimitIds)
|
|
74
|
+
? requestParams.roleLimitIds
|
|
75
|
+
: [roleLimitId || `${identifiersConcat}_${flowTypeConcat}`];
|
|
76
|
+
|
|
77
|
+
let maxLimit = Infinity;
|
|
78
|
+
const limitRecords = [];
|
|
79
|
+
|
|
80
|
+
for (const key of roleLimitKeys) {
|
|
81
|
+
const record = await dynamodbSharedLib.getItem(
|
|
82
|
+
_izContext,
|
|
83
|
+
dynamodbSharedLib.tableName(_izContext, 'RoleLimit'),
|
|
84
|
+
{ roleLimitId: key, limitType: 'runningTotal' }
|
|
85
|
+
);
|
|
86
|
+
if (record && typeof record.limitValue === 'number') {
|
|
87
|
+
limitRecords.push(record);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
if (limitRecords.length > 0) {
|
|
92
|
+
const isDecrease = (rec) =>
|
|
93
|
+
rec.effect === 'decrease' ||
|
|
94
|
+
rec.actionType === 'decrease' ||
|
|
95
|
+
rec.action === 'decrease';
|
|
96
|
+
|
|
97
|
+
const increaseLimits = limitRecords.filter((rec) => !isDecrease(rec));
|
|
98
|
+
const decreaseLimits = limitRecords.filter((rec) => isDecrease(rec));
|
|
99
|
+
|
|
100
|
+
const maxIncrease =
|
|
101
|
+
increaseLimits.length > 0
|
|
102
|
+
? Math.max(...increaseLimits.map((r) => r.limitValue))
|
|
103
|
+
: Infinity;
|
|
104
|
+
const minDecrease =
|
|
105
|
+
decreaseLimits.length > 0
|
|
106
|
+
? Math.min(...decreaseLimits.map((r) => r.limitValue))
|
|
107
|
+
: Infinity;
|
|
108
|
+
|
|
109
|
+
maxLimit = Math.min(maxIncrease, minDecrease);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
const usageRecord = await dynamodbSharedLib.getItem(
|
|
113
|
+
_izContext,
|
|
114
|
+
dynamodbSharedLib.tableName(_izContext, 'RunningTotalUsage'),
|
|
115
|
+
{ identifiersConcat, flowTypeConcat }
|
|
116
|
+
);
|
|
117
|
+
const currentTotal = usageRecord?.totalCount || 0;
|
|
118
|
+
|
|
119
|
+
let passStatus = false;
|
|
120
|
+
if (currentTotal + value <= maxLimit) {
|
|
121
|
+
passStatus = true;
|
|
122
|
+
const ttlTimestamp = Math.floor(Date.now() / 1000) + 3600;
|
|
123
|
+
|
|
124
|
+
await dynamodbSharedLib.putItem(
|
|
125
|
+
_izContext,
|
|
126
|
+
dynamodbSharedLib.tableName(_izContext, 'RunningTotalReservedUsage'),
|
|
127
|
+
{
|
|
128
|
+
runningTotalReservedId: `${identifiersConcat}_${flowTypeConcat}`,
|
|
129
|
+
usedTimestampId: uniqueIdentify,
|
|
130
|
+
usageCount: value,
|
|
131
|
+
runningTotalUsageStatus: 'reserved',
|
|
132
|
+
ttlTimestamp
|
|
133
|
+
}
|
|
134
|
+
);
|
|
135
|
+
|
|
136
|
+
await dynamodbSharedLib.putItem(
|
|
137
|
+
_izContext,
|
|
138
|
+
dynamodbSharedLib.tableName(_izContext, 'RunningTotalUsage'),
|
|
139
|
+
{
|
|
140
|
+
identifiersConcat,
|
|
141
|
+
flowTypeConcat,
|
|
142
|
+
totalCount: currentTotal + value,
|
|
143
|
+
updateUuid: _izContext.uniqueRequestId || `${Date.now()}`
|
|
144
|
+
}
|
|
145
|
+
);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
const returnResult = {
|
|
149
|
+
passStatus,
|
|
150
|
+
uniqueIdentify,
|
|
151
|
+
flowTypeConcat,
|
|
152
|
+
identifiersConcat
|
|
153
|
+
};
|
|
154
|
+
|
|
155
|
+
await sns.publishMessage(_izContext, {
|
|
156
|
+
message: { returnResult },
|
|
157
|
+
TopicArn: snsSharedLib.snsTopicArnByFlowSchema(
|
|
158
|
+
_izContext,
|
|
159
|
+
'ReservedDynamicUsage_Out'
|
|
160
|
+
)
|
|
161
|
+
});
|
|
162
|
+
} catch (error) {
|
|
163
|
+
_izContext.logger.error(`[${process.env.iz_serviceTag}:ReservedDynamicUsage] error:`, error);
|
|
164
|
+
throw error;
|
|
165
|
+
}
|
|
166
|
+
}
|