@stamhoofd/backend 2.57.1 → 2.59.0
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/index.ts +6 -1
- package/package.json +13 -13
- package/src/audit-logs/EventLogger.ts +30 -0
- package/src/audit-logs/GroupLogger.ts +95 -0
- package/src/audit-logs/MemberLogger.ts +24 -0
- package/src/audit-logs/MemberPlatformMembershipLogger.ts +57 -0
- package/src/audit-logs/MemberResponsibilityRecordLogger.ts +69 -0
- package/src/audit-logs/ModelLogger.ts +218 -0
- package/src/audit-logs/OrderLogger.ts +57 -0
- package/src/audit-logs/OrganizationLogger.ts +26 -0
- package/src/audit-logs/OrganizationRegistrationPeriodLogger.ts +77 -0
- package/src/audit-logs/PaymentLogger.ts +43 -0
- package/src/audit-logs/PlatformLogger.ts +13 -0
- package/src/audit-logs/RegistrationLogger.ts +53 -0
- package/src/audit-logs/RegistrationPeriodLogger.ts +21 -0
- package/src/audit-logs/StripeAccountLogger.ts +47 -0
- package/src/audit-logs/WebshopLogger.ts +35 -0
- package/src/crons.ts +2 -1
- package/src/endpoints/global/events/PatchEventsEndpoint.ts +12 -24
- package/src/endpoints/global/members/PatchOrganizationMembersEndpoint.ts +4 -18
- package/src/endpoints/global/payments/StripeWebhookEndpoint.ts +6 -3
- package/src/endpoints/global/platform/PatchPlatformEnpoint.ts +3 -18
- package/src/endpoints/global/registration/PatchUserMembersEndpoint.ts +0 -15
- package/src/endpoints/global/registration/RegisterMembersEndpoint.ts +5 -2
- package/src/endpoints/global/registration-periods/PatchRegistrationPeriodsEndpoint.ts +2 -2
- package/src/endpoints/organization/dashboard/organization/PatchOrganizationEndpoint.ts +5 -15
- package/src/endpoints/organization/dashboard/registration-periods/PatchOrganizationRegistrationPeriodsEndpoint.ts +18 -28
- package/src/endpoints/organization/dashboard/stripe/ConnectStripeEndpoint.ts +2 -1
- package/src/endpoints/organization/dashboard/stripe/DeleteStripeAccountEndpoint.ts +2 -1
- package/src/endpoints/organization/dashboard/stripe/UpdateStripeAccountEndpoint.ts +6 -3
- package/src/endpoints/organization/dashboard/webshops/PatchWebshopOrdersEndpoint.ts +7 -4
- package/src/endpoints/organization/webshops/PlaceOrderEndpoint.ts +8 -2
- package/src/helpers/AuthenticatedStructures.ts +16 -1
- package/src/helpers/Context.ts +8 -2
- package/src/helpers/MemberUserSyncer.ts +45 -40
- package/src/helpers/PeriodHelper.ts +31 -27
- package/src/helpers/TagHelper.ts +23 -20
- package/src/seeds/1722344162-update-membership.ts +2 -2
- package/src/seeds/1726572303-schedule-stock-updates.ts +2 -1
- package/src/services/AuditLogService.ts +89 -216
- package/src/services/BalanceItemPaymentService.ts +1 -1
- package/src/services/BalanceItemService.ts +14 -5
- package/src/services/MemberNumberService.ts +120 -0
- package/src/services/PaymentService.ts +199 -193
- package/src/services/PlatformMembershipService.ts +284 -0
- package/src/services/RegistrationService.ts +76 -27
- package/src/services/explainPatch.ts +528 -316
- package/src/helpers/MembershipHelper.ts +0 -54
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import { ArrayDecoder, AutoEncoder,
|
|
2
|
-
import {
|
|
1
|
+
import { ArrayDecoder, AutoEncoder, BooleanDecoder, DateDecoder, EnumDecoder, Field, getOptionalId, IntegerDecoder, isPatchableArray, isPatchMap, MapDecoder, StringDecoder, SymbolDecoder } from '@simonbackx/simple-encoding';
|
|
2
|
+
import { AuditLogPatchItem, AuditLogPatchItemType, AuditLogReplacement, AuditLogReplacementType, BooleanStatus, Image, isEmptyFilter, isUuid, PropertyFilter, RichText, Version } from '@stamhoofd/structures';
|
|
3
3
|
import { Formatter } from '@stamhoofd/utility';
|
|
4
|
+
import { get } from 'http';
|
|
4
5
|
|
|
5
6
|
export type PatchExplainer = {
|
|
6
7
|
key: string;
|
|
@@ -20,14 +21,34 @@ function createStringChangeHandler(key: string) {
|
|
|
20
21
|
|
|
21
22
|
return [
|
|
22
23
|
AuditLogPatchItem.create({
|
|
23
|
-
key:
|
|
24
|
-
oldValue:
|
|
25
|
-
value:
|
|
24
|
+
key: getAutoEncoderKey(key),
|
|
25
|
+
oldValue: getAutoEncoderValue(oldValue, key) || getAutoEncoderName(oldValue) || undefined,
|
|
26
|
+
value: getAutoEncoderValue(value, key) || getAutoEncoderName(value) || undefined,
|
|
26
27
|
}).autoType(),
|
|
27
28
|
];
|
|
28
29
|
};
|
|
29
30
|
}
|
|
30
31
|
|
|
32
|
+
function createEnumChangeHandler(key: string) {
|
|
33
|
+
return (oldValue: unknown, value: unknown) => {
|
|
34
|
+
if (oldValue === value) {
|
|
35
|
+
return [];
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
if (value === undefined) {
|
|
39
|
+
// Not altered
|
|
40
|
+
return [];
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
return [
|
|
44
|
+
AuditLogPatchItem.create({
|
|
45
|
+
key: getAutoEncoderKey(key),
|
|
46
|
+
oldValue: typeof oldValue === 'string' ? AuditLogReplacement.key(oldValue) : undefined,
|
|
47
|
+
value: typeof value === 'string' ? AuditLogReplacement.key(value) : undefined,
|
|
48
|
+
}).autoType(),
|
|
49
|
+
];
|
|
50
|
+
};
|
|
51
|
+
}
|
|
31
52
|
function createIntegerChangeHandler(key: string) {
|
|
32
53
|
return (oldValue: unknown, value: unknown) => {
|
|
33
54
|
if ((typeof oldValue !== 'number' && oldValue !== null) || (typeof value !== 'number' && value !== null)) {
|
|
@@ -37,12 +58,11 @@ function createIntegerChangeHandler(key: string) {
|
|
|
37
58
|
return [];
|
|
38
59
|
}
|
|
39
60
|
|
|
40
|
-
const formatter: (typeof Formatter.price | typeof Formatter.integer) = key.toLowerCase().includes('price') ? Formatter.price.bind(Formatter) : Formatter.integer.bind(Formatter);
|
|
41
61
|
return [
|
|
42
62
|
AuditLogPatchItem.create({
|
|
43
|
-
key:
|
|
44
|
-
oldValue: oldValue !== null ?
|
|
45
|
-
value: value !== null ?
|
|
63
|
+
key: getAutoEncoderKey(key),
|
|
64
|
+
oldValue: oldValue !== null ? (getAutoEncoderValue(oldValue, key) || undefined) : undefined,
|
|
65
|
+
value: value !== null ? (getAutoEncoderValue(value, key) || undefined) : undefined,
|
|
46
66
|
}).autoType(),
|
|
47
67
|
];
|
|
48
68
|
};
|
|
@@ -50,7 +70,11 @@ function createIntegerChangeHandler(key: string) {
|
|
|
50
70
|
|
|
51
71
|
function createDateChangeHandler(key: string) {
|
|
52
72
|
return (oldValue: unknown, value: unknown) => {
|
|
53
|
-
if (
|
|
73
|
+
if (!(oldValue instanceof Date) && oldValue !== null) {
|
|
74
|
+
return [];
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
if ((!(value instanceof Date)) && value !== null) {
|
|
54
78
|
return [];
|
|
55
79
|
}
|
|
56
80
|
|
|
@@ -60,7 +84,7 @@ function createDateChangeHandler(key: string) {
|
|
|
60
84
|
let dno = oldValue ? Formatter.dateNumber(oldValue, true) : undefined;
|
|
61
85
|
let dn = value ? Formatter.dateNumber(value, true) : undefined;
|
|
62
86
|
|
|
63
|
-
if (dno && dn && (dno === dn || (Formatter.time(oldValue!) !== Formatter.time(value!)))) {
|
|
87
|
+
if (dno && dn && (dno === dn || (Formatter.time(oldValue!) !== Formatter.time(value!))) && key !== 'birthDay') {
|
|
64
88
|
// Add time
|
|
65
89
|
dno += ' ' + Formatter.time(oldValue!);
|
|
66
90
|
dn += ' ' + Formatter.time(value!);
|
|
@@ -68,7 +92,7 @@ function createDateChangeHandler(key: string) {
|
|
|
68
92
|
|
|
69
93
|
return [
|
|
70
94
|
AuditLogPatchItem.create({
|
|
71
|
-
key:
|
|
95
|
+
key: getAutoEncoderKey(key),
|
|
72
96
|
oldValue: dno ? AuditLogReplacement.string(dno) : undefined,
|
|
73
97
|
value: dn ? AuditLogReplacement.string(dn) : undefined,
|
|
74
98
|
}).autoType(),
|
|
@@ -92,48 +116,98 @@ function createBooleanChangeHandler(key: string) {
|
|
|
92
116
|
|
|
93
117
|
return [
|
|
94
118
|
AuditLogPatchItem.create({
|
|
95
|
-
key:
|
|
96
|
-
oldValue: oldValue === true ? AuditLogReplacement.
|
|
97
|
-
value: value === true ? AuditLogReplacement.
|
|
119
|
+
key: getAutoEncoderKey(key),
|
|
120
|
+
oldValue: oldValue === true ? AuditLogReplacement.key('on') : (oldValue === false ? AuditLogReplacement.key('off') : undefined),
|
|
121
|
+
value: value === true ? AuditLogReplacement.key('on') : (value === false ? AuditLogReplacement.key('off') : undefined),
|
|
98
122
|
}).autoType(),
|
|
99
123
|
];
|
|
100
124
|
};
|
|
101
125
|
}
|
|
102
126
|
|
|
103
|
-
function
|
|
127
|
+
function getAutoEncoderKey(autoEncoder: string): AuditLogReplacement;
|
|
128
|
+
function getAutoEncoderKey(autoEncoder: unknown): AuditLogReplacement | null;
|
|
129
|
+
function getAutoEncoderKey(autoEncoder: unknown): AuditLogReplacement | null {
|
|
104
130
|
if (typeof autoEncoder === 'string') {
|
|
105
|
-
|
|
131
|
+
if (isUuid(autoEncoder)) {
|
|
132
|
+
return AuditLogReplacement.uuid(autoEncoder);
|
|
133
|
+
}
|
|
134
|
+
return AuditLogReplacement.key(autoEncoder);
|
|
106
135
|
}
|
|
136
|
+
return null;
|
|
137
|
+
}
|
|
107
138
|
|
|
108
|
-
|
|
109
|
-
|
|
139
|
+
function getAutoEncoderName(autoEncoder: unknown): AuditLogReplacement | null {
|
|
140
|
+
if (typeof autoEncoder === 'string') {
|
|
141
|
+
if (isUuid(autoEncoder)) {
|
|
142
|
+
return AuditLogReplacement.uuid(autoEncoder);
|
|
143
|
+
}
|
|
144
|
+
return AuditLogReplacement.string(autoEncoder);
|
|
110
145
|
}
|
|
111
146
|
|
|
112
|
-
if (autoEncoder
|
|
113
|
-
|
|
147
|
+
if (typeof autoEncoder === 'object' && autoEncoder !== null && 'getPatchName' in autoEncoder && typeof autoEncoder.getPatchName === 'function') {
|
|
148
|
+
const name = autoEncoder.getPatchName();
|
|
149
|
+
if (typeof name === 'string') {
|
|
150
|
+
return name ? AuditLogReplacement.string(name) : AuditLogReplacement.key('untitled');
|
|
151
|
+
}
|
|
114
152
|
}
|
|
115
153
|
|
|
116
154
|
if (typeof autoEncoder === 'object' && autoEncoder !== null && 'name' in autoEncoder && typeof autoEncoder.name === 'string') {
|
|
117
|
-
return autoEncoder.name;
|
|
155
|
+
return autoEncoder.name ? AuditLogReplacement.string(autoEncoder.name) : AuditLogReplacement.key('untitled');
|
|
118
156
|
}
|
|
119
157
|
return null;
|
|
120
158
|
}
|
|
159
|
+
function getAutoEncoderPutValue(autoEncoder: unknown, key?: string): AuditLogReplacement | null {
|
|
160
|
+
if (typeof autoEncoder === 'object' && autoEncoder !== null && 'getPutValue' in autoEncoder && typeof autoEncoder.getPutValue === 'function') {
|
|
161
|
+
const name = autoEncoder.getPutValue();
|
|
162
|
+
if (typeof name === 'string') {
|
|
163
|
+
return AuditLogReplacement.string(name);
|
|
164
|
+
}
|
|
165
|
+
if (name instanceof AuditLogReplacement) {
|
|
166
|
+
return name;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
return getAutoEncoderValue(autoEncoder, key);
|
|
170
|
+
}
|
|
121
171
|
|
|
122
|
-
function getAutoEncoderValue(autoEncoder: unknown): AuditLogReplacement | null {
|
|
172
|
+
function getAutoEncoderValue(autoEncoder: unknown, key?: string): AuditLogReplacement | null {
|
|
123
173
|
if (typeof autoEncoder === 'string') {
|
|
174
|
+
if (isUuid(autoEncoder)) {
|
|
175
|
+
return AuditLogReplacement.uuid(autoEncoder);
|
|
176
|
+
}
|
|
177
|
+
if (key && key === 'status') {
|
|
178
|
+
// Will be an enum
|
|
179
|
+
return AuditLogReplacement.key(autoEncoder);
|
|
180
|
+
}
|
|
124
181
|
return AuditLogReplacement.string(autoEncoder);
|
|
125
182
|
}
|
|
126
183
|
|
|
127
|
-
if (autoEncoder
|
|
128
|
-
|
|
184
|
+
if (typeof autoEncoder === 'symbol') {
|
|
185
|
+
const name = Symbol.keyFor(autoEncoder);
|
|
186
|
+
if (name) {
|
|
187
|
+
return AuditLogReplacement.key(name);
|
|
188
|
+
}
|
|
189
|
+
return AuditLogReplacement.key('unknown');
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
if (typeof autoEncoder === 'number') {
|
|
193
|
+
if (key && (key.toLowerCase().includes('price') || key.toLowerCase().includes('fee'))) {
|
|
194
|
+
return AuditLogReplacement.string(Formatter.price(autoEncoder));
|
|
195
|
+
}
|
|
196
|
+
return AuditLogReplacement.string(Formatter.integer(autoEncoder));
|
|
129
197
|
}
|
|
130
198
|
|
|
131
|
-
if (autoEncoder instanceof
|
|
132
|
-
return AuditLogReplacement.string(
|
|
199
|
+
if (autoEncoder instanceof Date) {
|
|
200
|
+
return AuditLogReplacement.string(Formatter.dateTime(autoEncoder, true, true));
|
|
133
201
|
}
|
|
134
202
|
|
|
135
|
-
if (typeof autoEncoder === 'object' && autoEncoder !== null && '
|
|
136
|
-
|
|
203
|
+
if (typeof autoEncoder === 'object' && autoEncoder !== null && 'getPatchValue' in autoEncoder && typeof autoEncoder.getPatchValue === 'function') {
|
|
204
|
+
const name = autoEncoder.getPatchValue();
|
|
205
|
+
if (typeof name === 'string') {
|
|
206
|
+
return AuditLogReplacement.string(name);
|
|
207
|
+
}
|
|
208
|
+
if (name instanceof AuditLogReplacement) {
|
|
209
|
+
return name;
|
|
210
|
+
}
|
|
137
211
|
}
|
|
138
212
|
|
|
139
213
|
if (autoEncoder instanceof Image) {
|
|
@@ -147,144 +221,270 @@ function getAutoEncoderValue(autoEncoder: unknown): AuditLogReplacement | null {
|
|
|
147
221
|
if (autoEncoder instanceof RichText) {
|
|
148
222
|
return AuditLogReplacement.string(autoEncoder.text);
|
|
149
223
|
}
|
|
224
|
+
|
|
225
|
+
if (autoEncoder instanceof PropertyFilter) {
|
|
226
|
+
if (autoEncoder.isAlwaysEnabledAndRequired) {
|
|
227
|
+
return AuditLogReplacement.key('alwaysEnabledAndRequired');
|
|
228
|
+
}
|
|
229
|
+
if (autoEncoder.enabledWhen === null && autoEncoder.requiredWhen === null) {
|
|
230
|
+
return AuditLogReplacement.key('alwaysEnabledAndOptional');
|
|
231
|
+
}
|
|
232
|
+
if (autoEncoder.enabledWhen !== null && autoEncoder.requiredWhen === null) {
|
|
233
|
+
return AuditLogReplacement.key('sometimesEnabledAndOptional');
|
|
234
|
+
}
|
|
235
|
+
if (autoEncoder.enabledWhen === null && autoEncoder.requiredWhen !== null) {
|
|
236
|
+
return AuditLogReplacement.key('alwaysEnabledAndSometimesRequired');
|
|
237
|
+
}
|
|
238
|
+
if (autoEncoder.enabledWhen !== null && isEmptyFilter(autoEncoder.requiredWhen)) {
|
|
239
|
+
return AuditLogReplacement.key('sometimesEnabledAndRequired');
|
|
240
|
+
}
|
|
241
|
+
return AuditLogReplacement.key('sometimesEnabledAndSometimesRequired');
|
|
242
|
+
}
|
|
243
|
+
|
|
150
244
|
return null;
|
|
151
245
|
}
|
|
152
246
|
|
|
153
|
-
function
|
|
154
|
-
return (
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
247
|
+
function getKeySingular(key: string) {
|
|
248
|
+
return key.replace(/ies$/, 'y').replace(/s$/, '');
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
function findOriginalById(id: unknown, oldArray: unknown[]): unknown | null {
|
|
252
|
+
return id ? oldArray.find(v => getId(v) === id) : null;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
function findOriginalIndexById(id: unknown, oldArray: unknown[]): number {
|
|
256
|
+
return id ? oldArray.findIndex(v => getId(v) === id) : -1;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
function getId(object: unknown): string | number | null {
|
|
260
|
+
const id = getOptionalId(object);
|
|
261
|
+
if (typeof id !== 'string' && typeof id !== 'number') {
|
|
262
|
+
if (object instanceof AutoEncoder) {
|
|
263
|
+
const encoded = object.encode({ version: Version });
|
|
264
|
+
return JSON.stringify(encoded);
|
|
158
265
|
}
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
266
|
+
return JSON.stringify(object);
|
|
267
|
+
}
|
|
268
|
+
return id;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
function findOriginal(put: unknown, oldArray: unknown[]): unknown | null {
|
|
272
|
+
return findOriginalById(getId(put), oldArray);
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
function findIndex(put: unknown, oldArray: unknown[]): number {
|
|
276
|
+
return findOriginalIndexById(getId(put), oldArray);
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
function processPut(key: string, put: unknown, original: unknown | null, createdIdSet?: Set<string>): AuditLogPatchItem[] {
|
|
280
|
+
const items: AuditLogPatchItem[] = [];
|
|
281
|
+
const keySingular = getKeySingular(key);
|
|
282
|
+
const v = getAutoEncoderPutValue(put);
|
|
283
|
+
|
|
284
|
+
// Added a new parent
|
|
285
|
+
if (!original) {
|
|
286
|
+
const n = getAutoEncoderName(put);
|
|
287
|
+
items.push(
|
|
288
|
+
AuditLogPatchItem.create({
|
|
289
|
+
key: AuditLogReplacement.key(keySingular).append(n),
|
|
290
|
+
value: (n?.toString() !== v?.toString()) ? (v || undefined) : undefined,
|
|
291
|
+
type: AuditLogPatchItemType.Added,
|
|
292
|
+
}),
|
|
293
|
+
);
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
// Little hack: detect PUT/DELETE behaviour:
|
|
297
|
+
if (createdIdSet) {
|
|
298
|
+
const id = getId(put);
|
|
299
|
+
if (id && typeof id === 'string') {
|
|
300
|
+
createdIdSet.add(id);
|
|
162
301
|
}
|
|
302
|
+
}
|
|
163
303
|
|
|
164
|
-
|
|
165
|
-
|
|
304
|
+
if (!original && (v || getAutoEncoderName(put))) {
|
|
305
|
+
// Simplify addition: don't show all added properties
|
|
306
|
+
return items;
|
|
307
|
+
}
|
|
166
308
|
|
|
167
|
-
|
|
309
|
+
items.push(
|
|
310
|
+
...explainPatch(
|
|
311
|
+
original ?? null,
|
|
312
|
+
put,
|
|
313
|
+
).map((i) => {
|
|
314
|
+
i.key = i.key.prepend(getAutoEncoderName(original) || getAutoEncoderName(put) || AuditLogReplacement.key('item'));
|
|
315
|
+
i.key = i.key.prepend(getAutoEncoderKey(key));
|
|
316
|
+
return i;
|
|
317
|
+
}),
|
|
318
|
+
);
|
|
319
|
+
return items;
|
|
320
|
+
}
|
|
168
321
|
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
322
|
+
function processPatch(key: string, patch: unknown, original: unknown | null): AuditLogPatchItem[] {
|
|
323
|
+
if (!original) {
|
|
324
|
+
// Not supported
|
|
325
|
+
return [];
|
|
326
|
+
}
|
|
174
327
|
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
// Not supported
|
|
179
|
-
original = null;
|
|
180
|
-
}
|
|
328
|
+
if (patch === original) {
|
|
329
|
+
return [];
|
|
330
|
+
}
|
|
181
331
|
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
332
|
+
const items: AuditLogPatchItem[] = [];
|
|
333
|
+
const keySingular = getKeySingular(key);
|
|
334
|
+
|
|
335
|
+
const l = explainPatch(
|
|
336
|
+
original,
|
|
337
|
+
patch,
|
|
338
|
+
).map((i) => {
|
|
339
|
+
i.key = i.key.prepend(getAutoEncoderName(original) || getAutoEncoderName(patch) || AuditLogReplacement.key('item'));
|
|
340
|
+
i.key = i.key.prepend(getAutoEncoderKey(key));
|
|
341
|
+
return i;
|
|
342
|
+
});
|
|
343
|
+
let ov = getAutoEncoderValue(original);
|
|
344
|
+
let v = getAutoEncoderValue(patch);
|
|
345
|
+
|
|
346
|
+
if (l.length === 0 && patch instanceof AutoEncoder && patch.isPatch()) {
|
|
347
|
+
items.push(
|
|
348
|
+
AuditLogPatchItem.create({
|
|
349
|
+
key: getAutoEncoderKey(keySingular).append(getAutoEncoderName(original) || getAutoEncoderName(patch) || AuditLogReplacement.key('item')),
|
|
350
|
+
oldValue: ov || undefined,
|
|
351
|
+
value: v || undefined,
|
|
352
|
+
type: AuditLogPatchItemType.Changed,
|
|
353
|
+
}),
|
|
354
|
+
);
|
|
355
|
+
return items;
|
|
356
|
+
}
|
|
192
357
|
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
358
|
+
if (ov && v) {
|
|
359
|
+
if (ov.toString() === v.toString()) {
|
|
360
|
+
ov = null;
|
|
361
|
+
v = null;
|
|
196
362
|
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
).map((i) => {
|
|
202
|
-
const name = getAutoEncoderName(put);
|
|
203
|
-
if (name) {
|
|
204
|
-
i.key = i.key.prepend(AuditLogReplacement.string(name));
|
|
205
|
-
}
|
|
206
|
-
i.key = i.key.prepend(AuditLogReplacement.key(key));
|
|
207
|
-
return i;
|
|
208
|
-
}),
|
|
209
|
-
);
|
|
363
|
+
// if (l.length === 0) {
|
|
364
|
+
// Probably no change
|
|
365
|
+
return [];
|
|
366
|
+
// }
|
|
210
367
|
}
|
|
211
368
|
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
369
|
+
// Simplify changes by providing one change instead of for all keys
|
|
370
|
+
items.push(
|
|
371
|
+
AuditLogPatchItem.create({
|
|
372
|
+
key: getAutoEncoderKey(keySingular).append(getAutoEncoderName(original) || getAutoEncoderName(v) || AuditLogReplacement.key('item')),
|
|
373
|
+
oldValue: ov || undefined,
|
|
374
|
+
value: v || undefined,
|
|
375
|
+
type: AuditLogPatchItemType.Changed,
|
|
376
|
+
}),
|
|
377
|
+
);
|
|
378
|
+
return items;
|
|
379
|
+
}
|
|
222
380
|
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
).map((i) => {
|
|
227
|
-
const name = getAutoEncoderName(original);
|
|
228
|
-
if (name) {
|
|
229
|
-
i.key = i.key.prepend(AuditLogReplacement.string(name));
|
|
230
|
-
}
|
|
231
|
-
i.key = i.key.prepend(AuditLogReplacement.key(key));
|
|
232
|
-
return i;
|
|
233
|
-
});
|
|
381
|
+
items.push(
|
|
382
|
+
...l,
|
|
383
|
+
);
|
|
234
384
|
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
AuditLogPatchItem.create({
|
|
238
|
-
key: AuditLogReplacement.key(keySingular),
|
|
239
|
-
value: getAutoEncoderValue(original) || undefined,
|
|
240
|
-
type: AuditLogPatchItemType.Changed,
|
|
241
|
-
}),
|
|
242
|
-
);
|
|
243
|
-
}
|
|
385
|
+
return items;
|
|
386
|
+
}
|
|
244
387
|
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
388
|
+
function processDelete(key: string, deletedItem: unknown, createdIdSet?: Set<string>): AuditLogPatchItem[] {
|
|
389
|
+
if (createdIdSet) {
|
|
390
|
+
const id = getId(deletedItem);
|
|
391
|
+
if (id && typeof id === 'string' && createdIdSet.has(id)) {
|
|
392
|
+
// DELETE + PUT happened
|
|
393
|
+
return [];
|
|
248
394
|
}
|
|
395
|
+
}
|
|
249
396
|
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
continue;
|
|
253
|
-
}
|
|
254
|
-
const original = oldValue.find(v => v.id === id);
|
|
255
|
-
if (!original) {
|
|
256
|
-
// Not supported
|
|
257
|
-
continue;
|
|
258
|
-
}
|
|
259
|
-
if (!(original instanceof AutoEncoder)) {
|
|
260
|
-
// Not supported
|
|
261
|
-
continue;
|
|
262
|
-
}
|
|
397
|
+
const v = getAutoEncoderPutValue(deletedItem);
|
|
398
|
+
const n = getAutoEncoderName(deletedItem);
|
|
263
399
|
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
continue;
|
|
267
|
-
}
|
|
400
|
+
const keySingular = getKeySingular(key);
|
|
401
|
+
const k = AuditLogReplacement.key(keySingular).append(n);
|
|
268
402
|
|
|
269
|
-
|
|
403
|
+
return [
|
|
404
|
+
AuditLogPatchItem.create({
|
|
405
|
+
key: k,
|
|
406
|
+
type: AuditLogPatchItemType.Removed,
|
|
407
|
+
oldValue: (n?.toString() !== v?.toString()) ? (v || undefined) : undefined,
|
|
408
|
+
}),
|
|
409
|
+
];
|
|
410
|
+
}
|
|
270
411
|
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
412
|
+
function createArrayChangeHandler(key: string) {
|
|
413
|
+
return (oldValue: unknown, value: unknown) => {
|
|
414
|
+
if (!Array.isArray(oldValue)) {
|
|
415
|
+
// Not supported
|
|
416
|
+
return [];
|
|
417
|
+
}
|
|
418
|
+
const items: AuditLogPatchItem[] = [];
|
|
419
|
+
|
|
420
|
+
if (!isPatchableArray(value)) {
|
|
421
|
+
if (Array.isArray(value)) {
|
|
422
|
+
// Search for puts
|
|
423
|
+
let orderChanged = false;
|
|
424
|
+
let added = 0;
|
|
425
|
+
for (const [index, newItem] of value.entries()) {
|
|
426
|
+
const originalIndex = findIndex(newItem, oldValue);
|
|
427
|
+
|
|
428
|
+
if (originalIndex === -1) {
|
|
429
|
+
// Has been added
|
|
430
|
+
items.push(...processPut(key, newItem, null));
|
|
431
|
+
added++;
|
|
432
|
+
}
|
|
433
|
+
else {
|
|
434
|
+
// Has been overwritten
|
|
435
|
+
const original = oldValue[originalIndex];
|
|
436
|
+
items.push(...processPatch(key, newItem, original));
|
|
437
|
+
|
|
438
|
+
if ((index - added) !== originalIndex) {
|
|
439
|
+
// Order has changed
|
|
440
|
+
orderChanged = true;
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
// Search for deletes
|
|
446
|
+
for (const original of oldValue) {
|
|
447
|
+
const newItem = findOriginal(original, value);
|
|
448
|
+
if (!newItem) {
|
|
449
|
+
// Has been deleted
|
|
450
|
+
items.push(...processDelete(key, original));
|
|
451
|
+
|
|
452
|
+
orderChanged = false; // ignore order changed as delete will have set it to true
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
if (orderChanged) {
|
|
457
|
+
// Check if order has changed
|
|
458
|
+
items.push(
|
|
459
|
+
AuditLogPatchItem.create({
|
|
460
|
+
key: getAutoEncoderKey(key),
|
|
461
|
+
type: AuditLogPatchItemType.Reordered,
|
|
462
|
+
}),
|
|
463
|
+
);
|
|
464
|
+
}
|
|
274
465
|
}
|
|
466
|
+
// Not supported
|
|
467
|
+
return items;
|
|
468
|
+
}
|
|
275
469
|
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
470
|
+
const createdIdSet = new Set<string>();
|
|
471
|
+
|
|
472
|
+
for (const { put } of value.getPuts()) {
|
|
473
|
+
items.push(...processPut(key, put, findOriginal(put, oldValue), createdIdSet));
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
for (const patch of value.getPatches()) {
|
|
477
|
+
items.push(...processPatch(key, patch, findOriginal(patch, oldValue)));
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
for (const id of value.getDeletes()) {
|
|
481
|
+
items.push(...processDelete(key, findOriginalById(id, oldValue), createdIdSet));
|
|
282
482
|
}
|
|
283
483
|
|
|
284
484
|
if (value.getMoves().length > 0) {
|
|
285
485
|
items.push(
|
|
286
486
|
AuditLogPatchItem.create({
|
|
287
|
-
key:
|
|
487
|
+
key: getAutoEncoderKey(key),
|
|
288
488
|
type: AuditLogPatchItemType.Reordered,
|
|
289
489
|
}),
|
|
290
490
|
);
|
|
@@ -293,9 +493,9 @@ function createArrayChangeHandler(key: string) {
|
|
|
293
493
|
};
|
|
294
494
|
}
|
|
295
495
|
|
|
296
|
-
function createMapChangeHandler(key
|
|
496
|
+
function createMapChangeHandler(key?: string) {
|
|
297
497
|
return (oldValue: unknown, value: unknown) => {
|
|
298
|
-
if (!
|
|
498
|
+
if (!(value instanceof Map)) {
|
|
299
499
|
// Not supported
|
|
300
500
|
return [];
|
|
301
501
|
}
|
|
@@ -305,22 +505,27 @@ function createMapChangeHandler(key: string) {
|
|
|
305
505
|
}
|
|
306
506
|
|
|
307
507
|
const items: AuditLogPatchItem[] = [];
|
|
308
|
-
const keySingular = key.replace(/ies$/, 'y').replace(/s$/, '');
|
|
508
|
+
const keySingular = key ? key.replace(/ies$/, 'y').replace(/s$/, '') : key;
|
|
509
|
+
const isPatch = isPatchMap(value);
|
|
309
510
|
|
|
310
511
|
for (const [k, v] of value.entries()) {
|
|
311
512
|
if (typeof k !== 'string') {
|
|
312
513
|
// Not supported
|
|
313
514
|
continue;
|
|
314
515
|
}
|
|
315
|
-
|
|
516
|
+
let original = oldValue.get(k);
|
|
316
517
|
|
|
317
|
-
if (v
|
|
518
|
+
if (v instanceof Map && !original) {
|
|
519
|
+
original = new Map();
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
if (v === null && isPatch) {
|
|
318
523
|
// Delete
|
|
319
524
|
if (original) {
|
|
320
525
|
items.push(
|
|
321
526
|
AuditLogPatchItem.create({
|
|
322
|
-
key: AuditLogReplacement.key(keySingular),
|
|
323
|
-
oldValue:
|
|
527
|
+
key: AuditLogReplacement.key(keySingular).append(getAutoEncoderKey(k)).append(getAutoEncoderName(original)),
|
|
528
|
+
oldValue: getAutoEncoderPutValue(original) || undefined,
|
|
324
529
|
type: AuditLogPatchItemType.Removed,
|
|
325
530
|
}),
|
|
326
531
|
);
|
|
@@ -332,30 +537,55 @@ function createMapChangeHandler(key: string) {
|
|
|
332
537
|
// added
|
|
333
538
|
items.push(
|
|
334
539
|
AuditLogPatchItem.create({
|
|
335
|
-
key: AuditLogReplacement.key(keySingular),
|
|
336
|
-
value:
|
|
540
|
+
key: AuditLogReplacement.key(keySingular).append(getAutoEncoderKey(k)).append(getAutoEncoderName(v)),
|
|
541
|
+
value: getAutoEncoderPutValue(v) || undefined,
|
|
337
542
|
type: AuditLogPatchItemType.Added,
|
|
338
543
|
}),
|
|
339
544
|
);
|
|
340
545
|
}
|
|
341
546
|
else {
|
|
547
|
+
let ov = getAutoEncoderValue(original);
|
|
548
|
+
let nv = getAutoEncoderValue(v);
|
|
549
|
+
|
|
342
550
|
const c = explainPatch(
|
|
343
551
|
original,
|
|
344
|
-
v
|
|
552
|
+
v,
|
|
345
553
|
).map((i) => {
|
|
346
|
-
|
|
347
|
-
if (name) {
|
|
348
|
-
i.key = i.key.prepend(name);
|
|
349
|
-
}
|
|
554
|
+
i.key = i.key.prepend(getAutoEncoderName(original) || getAutoEncoderName(v) || getAutoEncoderKey(k));
|
|
350
555
|
i.key = i.key.prepend(AuditLogReplacement.key(keySingular));
|
|
351
556
|
return i;
|
|
352
557
|
});
|
|
353
558
|
|
|
354
|
-
if (
|
|
559
|
+
if (ov && nv) {
|
|
560
|
+
if (ov.toString() === nv.toString()) {
|
|
561
|
+
ov = null;
|
|
562
|
+
nv = null;
|
|
563
|
+
|
|
564
|
+
// if (c.length === 0) {
|
|
565
|
+
// Probably no change
|
|
566
|
+
continue;
|
|
567
|
+
// }
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
// Simplify change
|
|
571
|
+
items.push(
|
|
572
|
+
AuditLogPatchItem.create({
|
|
573
|
+
key: AuditLogReplacement.key(keySingular).append(getAutoEncoderKey(k)).append(getAutoEncoderName(original) || getAutoEncoderName(v)),
|
|
574
|
+
oldValue: ov || undefined,
|
|
575
|
+
value: nv || undefined,
|
|
576
|
+
type: AuditLogPatchItemType.Changed,
|
|
577
|
+
}),
|
|
578
|
+
);
|
|
579
|
+
continue;
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
if (c.length === 0 && v instanceof AutoEncoder && v.isPatch()) {
|
|
355
583
|
// Manual log
|
|
356
584
|
items.push(
|
|
357
585
|
AuditLogPatchItem.create({
|
|
358
|
-
key: AuditLogReplacement.key(keySingular).append(
|
|
586
|
+
key: AuditLogReplacement.key(keySingular).append(getAutoEncoderKey(k)).append(getAutoEncoderName(original) || getAutoEncoderName(v)),
|
|
587
|
+
oldValue: getAutoEncoderValue(original) || undefined,
|
|
588
|
+
value: getAutoEncoderValue(v) || undefined,
|
|
359
589
|
type: AuditLogPatchItemType.Changed,
|
|
360
590
|
}),
|
|
361
591
|
);
|
|
@@ -368,121 +598,124 @@ function createMapChangeHandler(key: string) {
|
|
|
368
598
|
}
|
|
369
599
|
}
|
|
370
600
|
|
|
601
|
+
if (!isPatch) {
|
|
602
|
+
// Loop old values
|
|
603
|
+
for (const [k, v] of oldValue.entries()) {
|
|
604
|
+
if (typeof k !== 'string') {
|
|
605
|
+
// Not supported
|
|
606
|
+
continue;
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
if (value.has(k)) {
|
|
610
|
+
continue;
|
|
611
|
+
}
|
|
612
|
+
|
|
613
|
+
items.push(
|
|
614
|
+
AuditLogPatchItem.create({
|
|
615
|
+
key: AuditLogReplacement.key(keySingular).append(getAutoEncoderKey(k)).append(getAutoEncoderName(v)),
|
|
616
|
+
oldValue: getAutoEncoderPutValue(v) || undefined,
|
|
617
|
+
type: AuditLogPatchItemType.Removed,
|
|
618
|
+
}),
|
|
619
|
+
);
|
|
620
|
+
}
|
|
621
|
+
}
|
|
622
|
+
|
|
371
623
|
return items;
|
|
372
624
|
};
|
|
373
625
|
}
|
|
374
626
|
|
|
375
|
-
function
|
|
627
|
+
export function createUnknownChangeHandler(key: string) {
|
|
376
628
|
return (oldValue: unknown, value: unknown) => {
|
|
377
|
-
if (
|
|
378
|
-
// Not supported
|
|
629
|
+
if (oldValue === value) {
|
|
379
630
|
return [];
|
|
380
631
|
}
|
|
381
|
-
const keySingular = key.replace(/ies$/, 'y').replace(/s$/, '');
|
|
382
632
|
|
|
383
|
-
if (Array.isArray(value)) {
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
return [];
|
|
387
|
-
}
|
|
388
|
-
if (!oldValue.every(v => typeof v === 'string')) {
|
|
389
|
-
// Not supported
|
|
390
|
-
return [];
|
|
391
|
-
}
|
|
392
|
-
|
|
393
|
-
// Simple change
|
|
394
|
-
const valueStr = (value as string[]).join(', ');
|
|
395
|
-
const oldValueStr = (oldValue as string[]).join(', ');
|
|
396
|
-
|
|
397
|
-
if (valueStr === oldValueStr) {
|
|
398
|
-
return [];
|
|
399
|
-
}
|
|
633
|
+
if ((Array.isArray(oldValue) || Array.isArray(value)) && (!oldValue || Array.isArray(oldValue)) && (Array.isArray(value) || !value)) {
|
|
634
|
+
return createArrayChangeHandler(key)(oldValue, value);
|
|
635
|
+
}
|
|
400
636
|
|
|
637
|
+
if (!oldValue && oldValue !== 0 && getAutoEncoderValue(value, key)) {
|
|
638
|
+
// Simplify addition
|
|
401
639
|
return [
|
|
402
640
|
AuditLogPatchItem.create({
|
|
403
|
-
key:
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
})
|
|
641
|
+
key: getAutoEncoderKey(key),
|
|
642
|
+
value: getAutoEncoderPutValue(value, key) || undefined,
|
|
643
|
+
type: AuditLogPatchItemType.Added,
|
|
644
|
+
}),
|
|
407
645
|
];
|
|
408
646
|
}
|
|
409
647
|
|
|
410
|
-
if (
|
|
411
|
-
|
|
412
|
-
|
|
648
|
+
if ((oldValue || oldValue === 0) && (value === null || value === undefined)) {
|
|
649
|
+
return [
|
|
650
|
+
AuditLogPatchItem.create({
|
|
651
|
+
key: getAutoEncoderKey(key),
|
|
652
|
+
oldValue: getAutoEncoderPutValue(oldValue, key) || undefined,
|
|
653
|
+
type: AuditLogPatchItemType.Removed,
|
|
654
|
+
}),
|
|
655
|
+
];
|
|
413
656
|
}
|
|
414
657
|
|
|
415
|
-
const items
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
if (typeof put !== 'string') {
|
|
420
|
-
// Not supported
|
|
421
|
-
continue;
|
|
422
|
-
}
|
|
658
|
+
const items = explainPatch(oldValue, value).map((i) => {
|
|
659
|
+
i.key = i.key.prepend(getAutoEncoderKey(key));
|
|
660
|
+
return i;
|
|
661
|
+
});
|
|
423
662
|
|
|
424
|
-
|
|
425
|
-
|
|
663
|
+
let v = getAutoEncoderValue(value, key);
|
|
664
|
+
let ov = getAutoEncoderValue(oldValue, key);
|
|
426
665
|
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
}
|
|
437
|
-
createdIdSet.add(put);
|
|
666
|
+
if (oldValue !== undefined && oldValue !== null && value !== undefined && value !== null && getAutoEncoderValue(value, key) && items.length === 0 && value instanceof AutoEncoder && value.isPatch()) {
|
|
667
|
+
return [
|
|
668
|
+
AuditLogPatchItem.create({
|
|
669
|
+
key: getAutoEncoderKey(key),
|
|
670
|
+
value: v || undefined,
|
|
671
|
+
oldValue: ov || undefined,
|
|
672
|
+
type: AuditLogPatchItemType.Changed,
|
|
673
|
+
}),
|
|
674
|
+
];
|
|
438
675
|
}
|
|
439
676
|
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
if (createdIdSet.has(id)) {
|
|
446
|
-
// DELETE + PUT happened
|
|
447
|
-
continue;
|
|
448
|
-
}
|
|
677
|
+
if (v && ov) {
|
|
678
|
+
// Simplify change
|
|
679
|
+
if (v.toString() === ov.toString()) {
|
|
680
|
+
v = null;
|
|
681
|
+
ov = null;
|
|
449
682
|
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
683
|
+
// if (items.length === 0) {
|
|
684
|
+
// Probably no change
|
|
685
|
+
return [];
|
|
686
|
+
// }
|
|
454
687
|
}
|
|
455
688
|
|
|
456
|
-
|
|
457
|
-
AuditLogPatchItem.create({
|
|
458
|
-
key: AuditLogReplacement.key(keySingular),
|
|
459
|
-
oldValue: AuditLogReplacement.string(original),
|
|
460
|
-
type: AuditLogPatchItemType.Removed,
|
|
461
|
-
}),
|
|
462
|
-
);
|
|
463
|
-
}
|
|
464
|
-
|
|
465
|
-
if (value.getMoves().length > 0) {
|
|
466
|
-
items.push(
|
|
689
|
+
return [
|
|
467
690
|
AuditLogPatchItem.create({
|
|
468
|
-
key:
|
|
469
|
-
|
|
691
|
+
key: getAutoEncoderKey(key),
|
|
692
|
+
value: v || undefined,
|
|
693
|
+
oldValue: ov || undefined,
|
|
694
|
+
type: AuditLogPatchItemType.Changed,
|
|
470
695
|
}),
|
|
471
|
-
|
|
696
|
+
];
|
|
472
697
|
}
|
|
473
698
|
return items;
|
|
474
699
|
};
|
|
475
700
|
}
|
|
476
701
|
|
|
477
702
|
function getExplainerForField(field: Field<any>) {
|
|
478
|
-
if (field.decoder === StringDecoder
|
|
703
|
+
if (field.decoder === StringDecoder) {
|
|
479
704
|
return createStringChangeHandler(field.property);
|
|
480
705
|
}
|
|
481
706
|
|
|
707
|
+
if (field.decoder instanceof EnumDecoder) {
|
|
708
|
+
return createEnumChangeHandler(field.property);
|
|
709
|
+
}
|
|
710
|
+
|
|
482
711
|
if (field.decoder instanceof SymbolDecoder) {
|
|
483
|
-
if (field.decoder.decoder === StringDecoder
|
|
712
|
+
if (field.decoder.decoder === StringDecoder) {
|
|
484
713
|
return createStringChangeHandler(field.property);
|
|
485
714
|
}
|
|
715
|
+
|
|
716
|
+
if (field.decoder.decoder instanceof EnumDecoder) {
|
|
717
|
+
return createEnumChangeHandler(field.property);
|
|
718
|
+
}
|
|
486
719
|
}
|
|
487
720
|
|
|
488
721
|
if (field.decoder === DateDecoder) {
|
|
@@ -497,12 +730,40 @@ function getExplainerForField(field: Field<any>) {
|
|
|
497
730
|
return createIntegerChangeHandler(field.property);
|
|
498
731
|
}
|
|
499
732
|
|
|
500
|
-
if (field.decoder instanceof ArrayDecoder && field.decoder.decoder === StringDecoder) {
|
|
501
|
-
return createSimpleArrayChangeHandler(field.property);
|
|
502
|
-
}
|
|
503
|
-
|
|
504
733
|
if (field.decoder instanceof ArrayDecoder) {
|
|
505
|
-
|
|
734
|
+
const handler = createArrayChangeHandler(field.property);
|
|
735
|
+
|
|
736
|
+
if (field.decoder.decoder instanceof EnumDecoder) {
|
|
737
|
+
// Map values to keys
|
|
738
|
+
return (oldValue: unknown, value: unknown) => {
|
|
739
|
+
const items = handler(oldValue, value);
|
|
740
|
+
|
|
741
|
+
for (const item of items) {
|
|
742
|
+
if (item.oldValue && !item.oldValue.type) {
|
|
743
|
+
item.oldValue.type = AuditLogReplacementType.Key;
|
|
744
|
+
}
|
|
745
|
+
if (item.value && !item.value.type) {
|
|
746
|
+
item.value.type = AuditLogReplacementType.Key;
|
|
747
|
+
}
|
|
748
|
+
|
|
749
|
+
// If item.key is an array that ends with a 'value', also change it
|
|
750
|
+
if (item.key.type === AuditLogReplacementType.Array) {
|
|
751
|
+
const lastKeyItem = item.key.values[item.key.values.length - 1];
|
|
752
|
+
if (!lastKeyItem.type) {
|
|
753
|
+
lastKeyItem.type = AuditLogReplacementType.Key;
|
|
754
|
+
}
|
|
755
|
+
}
|
|
756
|
+
else {
|
|
757
|
+
if (!item.key.type) {
|
|
758
|
+
item.key.type = AuditLogReplacementType.Key;
|
|
759
|
+
}
|
|
760
|
+
}
|
|
761
|
+
}
|
|
762
|
+
return items;
|
|
763
|
+
};
|
|
764
|
+
}
|
|
765
|
+
|
|
766
|
+
return handler;
|
|
506
767
|
}
|
|
507
768
|
|
|
508
769
|
if (field.decoder instanceof MapDecoder) {
|
|
@@ -524,106 +785,57 @@ function getExplainerForField(field: Field<any>) {
|
|
|
524
785
|
|
|
525
786
|
return [
|
|
526
787
|
AuditLogPatchItem.create({
|
|
527
|
-
key:
|
|
528
|
-
oldValue: wasTrueOld === true ? AuditLogReplacement.
|
|
529
|
-
value: isTrue === true ? AuditLogReplacement.
|
|
530
|
-
}),
|
|
788
|
+
key: getAutoEncoderKey(field.property),
|
|
789
|
+
oldValue: wasTrueOld === true ? AuditLogReplacement.key('checked') : (wasTrueOld === false ? AuditLogReplacement.key('unchecked') : undefined),
|
|
790
|
+
value: isTrue === true ? AuditLogReplacement.key('checked') : (isTrue === false ? AuditLogReplacement.key('unchecked') : undefined),
|
|
791
|
+
}).autoType(),
|
|
531
792
|
];
|
|
532
793
|
};
|
|
533
794
|
}
|
|
534
795
|
|
|
535
|
-
|
|
536
|
-
return (oldValue: unknown, value: unknown) => {
|
|
537
|
-
if (!(value instanceof AutoEncoder) && value !== null) {
|
|
538
|
-
return [];
|
|
539
|
-
}
|
|
540
|
-
|
|
541
|
-
if (oldValue === value) {
|
|
542
|
-
return [];
|
|
543
|
-
}
|
|
544
|
-
|
|
545
|
-
if (oldValue && value && getAutoEncoderValue(value as AutoEncoder)) {
|
|
546
|
-
// Simplify addition
|
|
547
|
-
return [
|
|
548
|
-
AuditLogPatchItem.create({
|
|
549
|
-
key: AuditLogReplacement.key(field.property),
|
|
550
|
-
value: getAutoEncoderValue(value as AutoEncoder) || AuditLogReplacement.key(field.property),
|
|
551
|
-
oldValue: getAutoEncoderValue(oldValue as AutoEncoder) || AuditLogReplacement.key(field.property),
|
|
552
|
-
type: AuditLogPatchItemType.Changed,
|
|
553
|
-
}),
|
|
554
|
-
];
|
|
555
|
-
}
|
|
556
|
-
|
|
557
|
-
if (!oldValue && getAutoEncoderValue(value as AutoEncoder)) {
|
|
558
|
-
// Simplify addition
|
|
559
|
-
return [
|
|
560
|
-
AuditLogPatchItem.create({
|
|
561
|
-
key: AuditLogReplacement.key(field.property),
|
|
562
|
-
value: getAutoEncoderValue(value as AutoEncoder) || AuditLogReplacement.key(field.property),
|
|
563
|
-
type: AuditLogPatchItemType.Added,
|
|
564
|
-
}),
|
|
565
|
-
];
|
|
566
|
-
}
|
|
567
|
-
|
|
568
|
-
if (value === null) {
|
|
569
|
-
return [
|
|
570
|
-
AuditLogPatchItem.create({
|
|
571
|
-
key: AuditLogReplacement.key(field.property),
|
|
572
|
-
oldValue: getAutoEncoderValue(oldValue as AutoEncoder) || AuditLogReplacement.key(field.property),
|
|
573
|
-
type: AuditLogPatchItemType.Removed,
|
|
574
|
-
}),
|
|
575
|
-
];
|
|
576
|
-
}
|
|
577
|
-
|
|
578
|
-
return explainPatch(oldValue as AutoEncoder | null, value).map((i) => {
|
|
579
|
-
i.key = i.key.prepend(AuditLogReplacement.key(field.property));
|
|
580
|
-
return i;
|
|
581
|
-
});
|
|
582
|
-
};
|
|
583
|
-
}
|
|
584
|
-
|
|
585
|
-
// Simple addition/delete/change detection
|
|
586
|
-
return (oldValue: unknown, value: unknown) => {
|
|
587
|
-
if (value === undefined) {
|
|
588
|
-
return [];
|
|
589
|
-
}
|
|
590
|
-
|
|
591
|
-
if (oldValue === value) {
|
|
592
|
-
return [];
|
|
593
|
-
}
|
|
594
|
-
|
|
595
|
-
return [
|
|
596
|
-
AuditLogPatchItem.create({
|
|
597
|
-
key: AuditLogReplacement.key(field.property),
|
|
598
|
-
type: AuditLogPatchItemType.Changed,
|
|
599
|
-
}),
|
|
600
|
-
];
|
|
601
|
-
};
|
|
796
|
+
return createUnknownChangeHandler(field.property);
|
|
602
797
|
}
|
|
603
798
|
|
|
604
|
-
export function explainPatch
|
|
799
|
+
export function explainPatch(original: unknown | null, patch: unknown): AuditLogPatchItem[] {
|
|
605
800
|
if (isPatchableArray(patch)) {
|
|
606
801
|
const b = createArrayChangeHandler('items');
|
|
607
802
|
return b(original, patch);
|
|
608
803
|
}
|
|
609
|
-
|
|
804
|
+
|
|
805
|
+
if (original instanceof Map) {
|
|
806
|
+
const b = createMapChangeHandler();
|
|
807
|
+
return b(original, patch);
|
|
808
|
+
}
|
|
809
|
+
|
|
810
|
+
if (typeof patch !== 'object' || patch === null) {
|
|
811
|
+
if (patch === null) {
|
|
812
|
+
// todo
|
|
813
|
+
}
|
|
610
814
|
return [];
|
|
611
815
|
}
|
|
612
|
-
if (original &&
|
|
816
|
+
if (original && typeof original !== 'object') {
|
|
613
817
|
return [];
|
|
614
818
|
}
|
|
615
819
|
|
|
616
820
|
const items: AuditLogPatchItem[] = [];
|
|
617
821
|
|
|
618
822
|
for (const key in patch) {
|
|
619
|
-
const field = original
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
823
|
+
const field = original instanceof AutoEncoder
|
|
824
|
+
? original.static.latestFields.find(f => f.property === key)
|
|
825
|
+
: (
|
|
826
|
+
patch instanceof AutoEncoder
|
|
827
|
+
? patch.static.latestFields.find(f => f.property === key)
|
|
828
|
+
: null
|
|
829
|
+
);
|
|
624
830
|
const oldValue = original?.[key] ?? null;
|
|
625
831
|
const value = patch[key];
|
|
626
832
|
|
|
833
|
+
if (!(patch instanceof AutoEncoder) || !field) {
|
|
834
|
+
// try manual without type information
|
|
835
|
+
items.push(...createUnknownChangeHandler(key)(oldValue, value));
|
|
836
|
+
continue;
|
|
837
|
+
}
|
|
838
|
+
|
|
627
839
|
if (patch.isPut() && key === 'id') {
|
|
628
840
|
continue;
|
|
629
841
|
}
|