@flusys/nestjs-form-builder 9.1.0 → 9.1.2
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/README.md +28 -0
- package/config/message-keys.d.ts +1 -0
- package/dtos/form.dto.d.ts +5 -4
- package/entities/form.entity.d.ts +2 -1
- package/fesm/432.js +270 -302
- package/fesm/720.js +39 -17
- package/fesm/config/index.js +2 -1
- package/fesm/docs/index.js +1 -1
- package/fesm/dtos/index.js +47 -18
- package/fesm/entities/index.js +3 -3
- package/fesm/index.js +10 -6
- package/interfaces/form.interface.d.ts +2 -2
- package/package.json +5 -5
- package/services/form-result.service.d.ts +5 -3
- package/services/form.service.d.ts +7 -4
- package/utils/computed-field.utils.d.ts +13 -37
- package/utils/permission.utils.d.ts +3 -3
package/fesm/432.js
CHANGED
|
@@ -3,6 +3,7 @@ import { Identity as entities_Identity } from "@flusys/nestjs-shared/entities";
|
|
|
3
3
|
import * as __rspack_external__flusys_nestjs_shared_classes_6076a329 from "@flusys/nestjs-shared/classes";
|
|
4
4
|
import * as __rspack_external__flusys_nestjs_shared_decorators_c129b601 from "@flusys/nestjs-shared/decorators";
|
|
5
5
|
import * as __rspack_external__flusys_nestjs_shared_dtos_c4585026 from "@flusys/nestjs-shared/dtos";
|
|
6
|
+
import * as __rspack_external__flusys_nestjs_shared_interfaces_413f2706 from "@flusys/nestjs-shared/interfaces";
|
|
6
7
|
import * as __rspack_external__flusys_nestjs_shared_modules_24702bee from "@flusys/nestjs-shared/modules";
|
|
7
8
|
import * as __rspack_external__flusys_nestjs_shared_utils_9125c1f1 from "@flusys/nestjs-shared/utils";
|
|
8
9
|
import * as __rspack_external__nestjs_common_a04939da from "@nestjs/common";
|
|
@@ -67,7 +68,8 @@ const FORM_MESSAGES = {
|
|
|
67
68
|
OTP_INVALID: 'form.email.otp.invalid',
|
|
68
69
|
OTP_EXPIRED: 'form.email.otp.expired',
|
|
69
70
|
OTP_TOO_MANY_ATTEMPTS: 'form.email.otp.too.many.attempts',
|
|
70
|
-
OTP_VERIFIED: 'form.email.otp.verified'
|
|
71
|
+
OTP_VERIFIED: 'form.email.otp.verified',
|
|
72
|
+
INVALID_COMPUTED_FIELD: 'form.invalid.computed.field'
|
|
71
73
|
};
|
|
72
74
|
const FORM_RESULT_MESSAGES = {
|
|
73
75
|
GET_ALL_SUCCESS: 'form.result.get.all.success',
|
|
@@ -379,7 +381,7 @@ class Form extends entities_Identity {
|
|
|
379
381
|
schema;
|
|
380
382
|
schemaVersion;
|
|
381
383
|
accessType;
|
|
382
|
-
|
|
384
|
+
permissionLogic;
|
|
383
385
|
tags;
|
|
384
386
|
isActive;
|
|
385
387
|
}
|
|
@@ -436,10 +438,10 @@ _ts_decorate([
|
|
|
436
438
|
(0,external_typeorm_.Column)({
|
|
437
439
|
type: getJsonColumnType(),
|
|
438
440
|
nullable: true,
|
|
439
|
-
name: '
|
|
441
|
+
name: 'permission_logic'
|
|
440
442
|
}),
|
|
441
443
|
_ts_metadata("design:type", Object)
|
|
442
|
-
], Form.prototype, "
|
|
444
|
+
], Form.prototype, "permissionLogic", void 0);
|
|
443
445
|
_ts_decorate([
|
|
444
446
|
(0,external_typeorm_.Column)({
|
|
445
447
|
type: getJsonColumnType(),
|
|
@@ -1168,19 +1170,20 @@ FormEmailAuthService = _ts_decorate([
|
|
|
1168
1170
|
160(__unused_rspack_module, __webpack_exports__, __webpack_require__) {
|
|
1169
1171
|
/* import */ var _flusys_nestjs_shared_classes__rspack_import_0 = __webpack_require__(937);
|
|
1170
1172
|
/* import */ var _flusys_nestjs_shared_decorators__rspack_import_1 = __webpack_require__(265);
|
|
1171
|
-
/* import */ var
|
|
1172
|
-
/* import */ var
|
|
1173
|
-
/* import */ var
|
|
1174
|
-
/* import */ var
|
|
1175
|
-
/* import */ var
|
|
1176
|
-
/* import */ var
|
|
1177
|
-
/* import */ var
|
|
1178
|
-
/* import */ var
|
|
1179
|
-
/* import */ var
|
|
1180
|
-
/* import */ var
|
|
1181
|
-
/* import */ var
|
|
1182
|
-
/* import */ var
|
|
1183
|
-
/* import */ var
|
|
1173
|
+
/* import */ var _flusys_nestjs_shared_interfaces__rspack_import_2 = __webpack_require__(103);
|
|
1174
|
+
/* import */ var _flusys_nestjs_shared_modules__rspack_import_3 = __webpack_require__(236);
|
|
1175
|
+
/* import */ var _nestjs_common__rspack_import_4 = __webpack_require__(157);
|
|
1176
|
+
/* import */ var typeorm__rspack_import_5 = __webpack_require__(158);
|
|
1177
|
+
/* import */ var _config_index_js__rspack_import_13 = __webpack_require__(769);
|
|
1178
|
+
/* import */ var _config_index_js__rspack_import_14 = __webpack_require__(137);
|
|
1179
|
+
/* import */ var _dtos_form_result_dto_js__rspack_import_6 = __webpack_require__(788);
|
|
1180
|
+
/* import */ var _entities_index_js__rspack_import_7 = __webpack_require__(814);
|
|
1181
|
+
/* import */ var _enums_form_access_type_enum_js__rspack_import_15 = __webpack_require__(376);
|
|
1182
|
+
/* import */ var _utils_computed_field_utils_js__rspack_import_8 = __webpack_require__(801);
|
|
1183
|
+
/* import */ var _utils_permission_utils_js__rspack_import_9 = __webpack_require__(988);
|
|
1184
|
+
/* import */ var _form_builder_config_service_js__rspack_import_10 = __webpack_require__(781);
|
|
1185
|
+
/* import */ var _form_builder_datasource_provider_js__rspack_import_11 = __webpack_require__(593);
|
|
1186
|
+
/* import */ var _form_email_auth_service_js__rspack_import_12 = __webpack_require__(474);
|
|
1184
1187
|
function _ts_decorate(decorators, target, key, desc) {
|
|
1185
1188
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
1186
1189
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") {
|
|
@@ -1218,12 +1221,15 @@ function _ts_param(paramIndex, decorator) {
|
|
|
1218
1221
|
|
|
1219
1222
|
|
|
1220
1223
|
|
|
1224
|
+
|
|
1221
1225
|
class FormResultService extends _flusys_nestjs_shared_classes__rspack_import_0.ApiService {
|
|
1222
1226
|
cacheManager;
|
|
1223
1227
|
utilsService;
|
|
1224
1228
|
formBuilderConfig;
|
|
1225
1229
|
dataSourceProvider;
|
|
1226
1230
|
formEmailAuthService;
|
|
1231
|
+
permissionResolver;
|
|
1232
|
+
permissionCache;
|
|
1227
1233
|
formRepository = null;
|
|
1228
1234
|
// Serializes the single-response check-then-insert per (formId, email) within
|
|
1229
1235
|
// this process, so a double-click/two-tab submission can't both pass the check
|
|
@@ -1231,13 +1237,13 @@ class FormResultService extends _flusys_nestjs_shared_classes__rspack_import_0.A
|
|
|
1231
1237
|
// per-instance lock would never be shared between the two racing requests.
|
|
1232
1238
|
// Does not span multiple app instances; see withSubmissionLock().
|
|
1233
1239
|
static submissionLocks = new Map();
|
|
1234
|
-
constructor(cacheManager, utilsService, formBuilderConfig, dataSourceProvider, formEmailAuthService){
|
|
1235
|
-
super(
|
|
1240
|
+
constructor(cacheManager, utilsService, formBuilderConfig, dataSourceProvider, formEmailAuthService, permissionResolver, permissionCache){
|
|
1241
|
+
super(_config_index_js__rspack_import_13/* .FORM_BUILDER_EVENT_ENTITIES.FORM_RESULT */.eF.FORM_RESULT, cacheManager, utilsService, FormResultService.name, true, _config_index_js__rspack_import_13/* .FORM_BUILDER_EVENT_MODULE */.T$, dataSourceProvider, _entities_index_js__rspack_import_7/* .FormResult */.ez), this.cacheManager = cacheManager, this.utilsService = utilsService, this.formBuilderConfig = formBuilderConfig, this.dataSourceProvider = dataSourceProvider, this.formEmailAuthService = formEmailAuthService, this.permissionResolver = permissionResolver, this.permissionCache = permissionCache;
|
|
1236
1242
|
}
|
|
1237
1243
|
async ensureFormRepositoryInitialized() {
|
|
1238
1244
|
if (!this.formRepository) {
|
|
1239
1245
|
const enableCompanyFeature = this.formBuilderConfig.isCompanyFeatureEnabled();
|
|
1240
|
-
const formEntity = enableCompanyFeature ?
|
|
1246
|
+
const formEntity = enableCompanyFeature ? _entities_index_js__rspack_import_7/* .FormWithCompany */.Wl : _entities_index_js__rspack_import_7/* .Form */.lV;
|
|
1241
1247
|
this.formRepository = await this.dataSourceProvider.getRepository(formEntity);
|
|
1242
1248
|
}
|
|
1243
1249
|
}
|
|
@@ -1264,13 +1270,13 @@ class FormResultService extends _flusys_nestjs_shared_classes__rspack_import_0.A
|
|
|
1264
1270
|
where: {
|
|
1265
1271
|
id: formId,
|
|
1266
1272
|
isActive: true,
|
|
1267
|
-
deletedAt: (0,
|
|
1273
|
+
deletedAt: (0,typeorm__rspack_import_5.IsNull)()
|
|
1268
1274
|
}
|
|
1269
1275
|
});
|
|
1270
1276
|
if (!form) {
|
|
1271
|
-
throw new
|
|
1277
|
+
throw new _nestjs_common__rspack_import_4.NotFoundException({
|
|
1272
1278
|
message: 'Form not found or inactive',
|
|
1273
|
-
messageKey:
|
|
1279
|
+
messageKey: _config_index_js__rspack_import_14/* .FORM_MESSAGES.NOT_FOUND */.Q.NOT_FOUND
|
|
1274
1280
|
});
|
|
1275
1281
|
}
|
|
1276
1282
|
return form;
|
|
@@ -1283,64 +1289,67 @@ class FormResultService extends _flusys_nestjs_shared_classes__rspack_import_0.A
|
|
|
1283
1289
|
}
|
|
1284
1290
|
}
|
|
1285
1291
|
static PUBLICLY_SUBMITTABLE_ACCESS_TYPES = new Set([
|
|
1286
|
-
|
|
1287
|
-
|
|
1292
|
+
_enums_form_access_type_enum_js__rspack_import_15/* .FormAccessType.PUBLIC */.h.PUBLIC,
|
|
1293
|
+
_enums_form_access_type_enum_js__rspack_import_15/* .FormAccessType.EMAIL_VERIFIED */.h.EMAIL_VERIFIED
|
|
1288
1294
|
]);
|
|
1289
1295
|
async validateSubmissionAccess(form, user, isPublic) {
|
|
1290
1296
|
if (isPublic) {
|
|
1291
1297
|
if (!FormResultService.PUBLICLY_SUBMITTABLE_ACCESS_TYPES.has(form.accessType)) {
|
|
1292
|
-
throw new
|
|
1298
|
+
throw new _nestjs_common__rspack_import_4.UnauthorizedException({
|
|
1293
1299
|
message: 'This form is not available for public submission',
|
|
1294
|
-
messageKey:
|
|
1300
|
+
messageKey: _config_index_js__rspack_import_14/* .FORM_MESSAGES.NOT_PUBLIC */.Q.NOT_PUBLIC
|
|
1295
1301
|
});
|
|
1296
1302
|
}
|
|
1297
1303
|
return;
|
|
1298
1304
|
}
|
|
1299
1305
|
switch(form.accessType){
|
|
1300
|
-
case
|
|
1306
|
+
case _enums_form_access_type_enum_js__rspack_import_15/* .FormAccessType.PUBLIC */.h.PUBLIC:
|
|
1301
1307
|
return;
|
|
1302
|
-
case
|
|
1303
|
-
throw new
|
|
1308
|
+
case _enums_form_access_type_enum_js__rspack_import_15/* .FormAccessType.EMAIL_VERIFIED */.h.EMAIL_VERIFIED:
|
|
1309
|
+
throw new _nestjs_common__rspack_import_4.BadRequestException({
|
|
1304
1310
|
message: 'Email-verified forms must be submitted through the public endpoint',
|
|
1305
|
-
messageKey:
|
|
1311
|
+
messageKey: _config_index_js__rspack_import_14/* .FORM_MESSAGES.INVALID_ACCESS_TYPE */.Q.INVALID_ACCESS_TYPE
|
|
1306
1312
|
});
|
|
1307
|
-
case
|
|
1308
|
-
case
|
|
1313
|
+
case _enums_form_access_type_enum_js__rspack_import_15/* .FormAccessType.ACTION_GROUP */.h.ACTION_GROUP:
|
|
1314
|
+
case _enums_form_access_type_enum_js__rspack_import_15/* .FormAccessType.AUTHENTICATED */.h.AUTHENTICATED:
|
|
1309
1315
|
break;
|
|
1310
1316
|
default:
|
|
1311
|
-
throw new
|
|
1317
|
+
throw new _nestjs_common__rspack_import_4.BadRequestException({
|
|
1312
1318
|
message: 'Invalid form access type',
|
|
1313
|
-
messageKey:
|
|
1319
|
+
messageKey: _config_index_js__rspack_import_14/* .FORM_MESSAGES.INVALID_ACCESS_TYPE */.Q.INVALID_ACCESS_TYPE
|
|
1314
1320
|
});
|
|
1315
1321
|
}
|
|
1316
1322
|
if (!user) {
|
|
1317
|
-
throw new
|
|
1323
|
+
throw new _nestjs_common__rspack_import_4.UnauthorizedException({
|
|
1318
1324
|
message: 'Authentication required to submit this form',
|
|
1319
|
-
messageKey:
|
|
1325
|
+
messageKey: _config_index_js__rspack_import_14/* .FORM_MESSAGES.AUTH_REQUIRED */.Q.AUTH_REQUIRED
|
|
1320
1326
|
});
|
|
1321
1327
|
}
|
|
1322
|
-
if (form.accessType ===
|
|
1323
|
-
const
|
|
1324
|
-
|
|
1325
|
-
|
|
1328
|
+
if (form.accessType === _enums_form_access_type_enum_js__rspack_import_15/* .FormAccessType.ACTION_GROUP */.h.ACTION_GROUP && form.permissionLogic) {
|
|
1329
|
+
const permitted = await (0,_utils_permission_utils_js__rspack_import_9/* .hasFormPermission */.E)(user, form.permissionLogic, {
|
|
1330
|
+
resolver: this.permissionResolver,
|
|
1331
|
+
cache: this.permissionCache
|
|
1332
|
+
});
|
|
1333
|
+
if (!permitted) {
|
|
1334
|
+
throw new _nestjs_common__rspack_import_4.ForbiddenException({
|
|
1326
1335
|
message: 'You do not have permission to submit this form',
|
|
1327
|
-
messageKey:
|
|
1336
|
+
messageKey: _config_index_js__rspack_import_14/* .FORM_MESSAGES.ACCESS_DENIED */.Q.ACCESS_DENIED
|
|
1328
1337
|
});
|
|
1329
1338
|
}
|
|
1330
|
-
} else if (form.accessType !==
|
|
1331
|
-
throw new
|
|
1339
|
+
} else if (form.accessType !== _enums_form_access_type_enum_js__rspack_import_15/* .FormAccessType.AUTHENTICATED */.h.AUTHENTICATED) {
|
|
1340
|
+
throw new _nestjs_common__rspack_import_4.BadRequestException({
|
|
1332
1341
|
message: 'Invalid form access type',
|
|
1333
|
-
messageKey:
|
|
1342
|
+
messageKey: _config_index_js__rspack_import_14/* .FORM_MESSAGES.INVALID_ACCESS_TYPE */.Q.INVALID_ACCESS_TYPE
|
|
1334
1343
|
});
|
|
1335
1344
|
}
|
|
1336
1345
|
}
|
|
1337
1346
|
async resolveEmailVerifiedSubmitter(form, user, accessToken) {
|
|
1338
|
-
if (form.accessType !==
|
|
1347
|
+
if (form.accessType !== _enums_form_access_type_enum_js__rspack_import_15/* .FormAccessType.EMAIL_VERIFIED */.h.EMAIL_VERIFIED) return null;
|
|
1339
1348
|
const email = await this.formEmailAuthService.resolveSubmitterEmail(form.id, user ?? undefined, accessToken);
|
|
1340
1349
|
if (!email) {
|
|
1341
|
-
throw new
|
|
1350
|
+
throw new _nestjs_common__rspack_import_4.UnauthorizedException({
|
|
1342
1351
|
message: 'Email verification required to submit this form',
|
|
1343
|
-
messageKey:
|
|
1352
|
+
messageKey: _config_index_js__rspack_import_14/* .FORM_MESSAGES.EMAIL_VERIFICATION_REQUIRED */.Q.EMAIL_VERIFICATION_REQUIRED
|
|
1344
1353
|
});
|
|
1345
1354
|
}
|
|
1346
1355
|
return email;
|
|
@@ -1354,13 +1363,13 @@ class FormResultService extends _flusys_nestjs_shared_classes__rspack_import_0.A
|
|
|
1354
1363
|
formId: form.id,
|
|
1355
1364
|
submitterEmail,
|
|
1356
1365
|
isDraft: false,
|
|
1357
|
-
deletedAt: (0,
|
|
1366
|
+
deletedAt: (0,typeorm__rspack_import_5.IsNull)()
|
|
1358
1367
|
}
|
|
1359
1368
|
});
|
|
1360
1369
|
if (count > 0) {
|
|
1361
|
-
throw new
|
|
1370
|
+
throw new _nestjs_common__rspack_import_4.ConflictException({
|
|
1362
1371
|
message: 'You have already submitted a response to this form',
|
|
1363
|
-
messageKey:
|
|
1372
|
+
messageKey: _config_index_js__rspack_import_14/* .FORM_RESULT_MESSAGES.ALREADY_SUBMITTED */.y.ALREADY_SUBMITTED
|
|
1364
1373
|
});
|
|
1365
1374
|
}
|
|
1366
1375
|
}
|
|
@@ -1369,7 +1378,7 @@ class FormResultService extends _flusys_nestjs_shared_classes__rspack_import_0.A
|
|
|
1369
1378
|
formId,
|
|
1370
1379
|
submittedById: userId,
|
|
1371
1380
|
isDraft: true,
|
|
1372
|
-
deletedAt: (0,
|
|
1381
|
+
deletedAt: (0,typeorm__rspack_import_5.IsNull)()
|
|
1373
1382
|
};
|
|
1374
1383
|
}
|
|
1375
1384
|
// Query Customization
|
|
@@ -1405,13 +1414,10 @@ class FormResultService extends _flusys_nestjs_shared_classes__rspack_import_0.A
|
|
|
1405
1414
|
if (isDraft) {
|
|
1406
1415
|
return data;
|
|
1407
1416
|
}
|
|
1408
|
-
const
|
|
1409
|
-
|
|
1410
|
-
const computedFields = settings?.computedFields;
|
|
1411
|
-
if (!computedFields || computedFields.length === 0) {
|
|
1417
|
+
const computedValues = (0,_utils_computed_field_utils_js__rspack_import_8/* .calculateComputedFields */.XZ)(data, form.schema);
|
|
1418
|
+
if (Object.keys(computedValues).length === 0) {
|
|
1412
1419
|
return data;
|
|
1413
1420
|
}
|
|
1414
|
-
const computedValues = (0,_utils_computed_field_utils_js__rspack_import_14/* .calculateComputedFields */.X)(data, computedFields);
|
|
1415
1421
|
return {
|
|
1416
1422
|
...data,
|
|
1417
1423
|
_computed: computedValues
|
|
@@ -1514,13 +1520,13 @@ class FormResultService extends _flusys_nestjs_shared_classes__rspack_import_0.A
|
|
|
1514
1520
|
where: {
|
|
1515
1521
|
id: draftId,
|
|
1516
1522
|
submittedById: user.id,
|
|
1517
|
-
deletedAt: (0,
|
|
1523
|
+
deletedAt: (0,typeorm__rspack_import_5.IsNull)()
|
|
1518
1524
|
}
|
|
1519
1525
|
});
|
|
1520
1526
|
if (!draft) {
|
|
1521
|
-
throw new
|
|
1527
|
+
throw new _nestjs_common__rspack_import_4.NotFoundException({
|
|
1522
1528
|
message: 'Draft not found',
|
|
1523
|
-
messageKey:
|
|
1529
|
+
messageKey: _config_index_js__rspack_import_14/* .FORM_RESULT_MESSAGES.NOT_FOUND */.y.NOT_FOUND
|
|
1524
1530
|
});
|
|
1525
1531
|
}
|
|
1526
1532
|
const form = await this.getActiveForm(dto.formId);
|
|
@@ -1540,7 +1546,7 @@ class FormResultService extends _flusys_nestjs_shared_classes__rspack_import_0.A
|
|
|
1540
1546
|
return this.convertEntityToResponseDto(saved, false);
|
|
1541
1547
|
}
|
|
1542
1548
|
async publishSubmissionEvent(result, formId, isDraft, user) {
|
|
1543
|
-
await this.publishDomainAction(isDraft ?
|
|
1549
|
+
await this.publishDomainAction(isDraft ? _config_index_js__rspack_import_13/* .FORM_BUILDER_EVENT_ACTIONS.DRAFT_SAVED */.ov.DRAFT_SAVED : _config_index_js__rspack_import_13/* .FORM_BUILDER_EVENT_ACTIONS.SUBMITTED */.ov.SUBMITTED, {
|
|
1544
1550
|
ids: [
|
|
1545
1551
|
result.id
|
|
1546
1552
|
],
|
|
@@ -1581,7 +1587,7 @@ class FormResultService extends _flusys_nestjs_shared_classes__rspack_import_0.A
|
|
|
1581
1587
|
formId,
|
|
1582
1588
|
submittedById: user.id,
|
|
1583
1589
|
isDraft: false,
|
|
1584
|
-
deletedAt: (0,
|
|
1590
|
+
deletedAt: (0,typeorm__rspack_import_5.IsNull)()
|
|
1585
1591
|
}
|
|
1586
1592
|
});
|
|
1587
1593
|
return count > 0;
|
|
@@ -1595,7 +1601,7 @@ class FormResultService extends _flusys_nestjs_shared_classes__rspack_import_0.A
|
|
|
1595
1601
|
formId,
|
|
1596
1602
|
submitterEmail: email,
|
|
1597
1603
|
isDraft: false,
|
|
1598
|
-
deletedAt: (0,
|
|
1604
|
+
deletedAt: (0,typeorm__rspack_import_5.IsNull)()
|
|
1599
1605
|
}
|
|
1600
1606
|
});
|
|
1601
1607
|
return count > 0;
|
|
@@ -1608,7 +1614,7 @@ _ts_decorate([
|
|
|
1608
1614
|
}),
|
|
1609
1615
|
_ts_metadata("design:type", Function),
|
|
1610
1616
|
_ts_metadata("design:paramtypes", [
|
|
1611
|
-
typeof
|
|
1617
|
+
typeof _dtos_form_result_dto_js__rspack_import_6/* .SubmitFormDto */.sH === "undefined" ? Object : _dtos_form_result_dto_js__rspack_import_6/* .SubmitFormDto */.sH,
|
|
1612
1618
|
Object,
|
|
1613
1619
|
void 0
|
|
1614
1620
|
]),
|
|
@@ -1622,27 +1628,33 @@ _ts_decorate([
|
|
|
1622
1628
|
_ts_metadata("design:type", Function),
|
|
1623
1629
|
_ts_metadata("design:paramtypes", [
|
|
1624
1630
|
String,
|
|
1625
|
-
typeof
|
|
1631
|
+
typeof _dtos_form_result_dto_js__rspack_import_6/* .SubmitFormDto */.sH === "undefined" ? Object : _dtos_form_result_dto_js__rspack_import_6/* .SubmitFormDto */.sH,
|
|
1626
1632
|
typeof ILoggedUserInfo === "undefined" ? Object : ILoggedUserInfo
|
|
1627
1633
|
]),
|
|
1628
1634
|
_ts_metadata("design:returntype", Promise)
|
|
1629
1635
|
], FormResultService.prototype, "updateDraft", null);
|
|
1630
1636
|
FormResultService = _ts_decorate([
|
|
1631
|
-
(0,
|
|
1632
|
-
scope:
|
|
1637
|
+
(0,_nestjs_common__rspack_import_4.Injectable)({
|
|
1638
|
+
scope: _nestjs_common__rspack_import_4.Scope.REQUEST
|
|
1633
1639
|
}),
|
|
1634
|
-
_ts_param(0, (0,
|
|
1635
|
-
_ts_param(1, (0,
|
|
1636
|
-
_ts_param(2, (0,
|
|
1637
|
-
_ts_param(3, (0,
|
|
1638
|
-
_ts_param(4, (0,
|
|
1640
|
+
_ts_param(0, (0,_nestjs_common__rspack_import_4.Inject)('CACHE_INSTANCE')),
|
|
1641
|
+
_ts_param(1, (0,_nestjs_common__rspack_import_4.Inject)(_flusys_nestjs_shared_modules__rspack_import_3.UtilsService)),
|
|
1642
|
+
_ts_param(2, (0,_nestjs_common__rspack_import_4.Inject)(_form_builder_config_service_js__rspack_import_10/* .FormBuilderConfigService */.j)),
|
|
1643
|
+
_ts_param(3, (0,_nestjs_common__rspack_import_4.Inject)(_form_builder_datasource_provider_js__rspack_import_11/* .FormBuilderDataSourceProvider */._)),
|
|
1644
|
+
_ts_param(4, (0,_nestjs_common__rspack_import_4.Inject)(_form_email_auth_service_js__rspack_import_12/* .FormEmailAuthService */.w)),
|
|
1645
|
+
_ts_param(5, (0,_nestjs_common__rspack_import_4.Optional)()),
|
|
1646
|
+
_ts_param(5, (0,_nestjs_common__rspack_import_4.Inject)(_flusys_nestjs_shared_interfaces__rspack_import_2.PERMISSION_RESOLVER)),
|
|
1647
|
+
_ts_param(6, (0,_nestjs_common__rspack_import_4.Optional)()),
|
|
1648
|
+
_ts_param(6, (0,_nestjs_common__rspack_import_4.Inject)(_flusys_nestjs_shared_modules__rspack_import_3.SharedPermissionCacheService)),
|
|
1639
1649
|
_ts_metadata("design:type", Function),
|
|
1640
1650
|
_ts_metadata("design:paramtypes", [
|
|
1641
1651
|
typeof _flusys_nestjs_shared_classes__rspack_import_0.HybridCache === "undefined" ? Object : _flusys_nestjs_shared_classes__rspack_import_0.HybridCache,
|
|
1642
|
-
typeof
|
|
1643
|
-
typeof
|
|
1644
|
-
typeof
|
|
1645
|
-
typeof
|
|
1652
|
+
typeof _flusys_nestjs_shared_modules__rspack_import_3.UtilsService === "undefined" ? Object : _flusys_nestjs_shared_modules__rspack_import_3.UtilsService,
|
|
1653
|
+
typeof _form_builder_config_service_js__rspack_import_10/* .FormBuilderConfigService */.j === "undefined" ? Object : _form_builder_config_service_js__rspack_import_10/* .FormBuilderConfigService */.j,
|
|
1654
|
+
typeof _form_builder_datasource_provider_js__rspack_import_11/* .FormBuilderDataSourceProvider */._ === "undefined" ? Object : _form_builder_datasource_provider_js__rspack_import_11/* .FormBuilderDataSourceProvider */._,
|
|
1655
|
+
typeof _form_email_auth_service_js__rspack_import_12/* .FormEmailAuthService */.w === "undefined" ? Object : _form_email_auth_service_js__rspack_import_12/* .FormEmailAuthService */.w,
|
|
1656
|
+
typeof IPermissionResolver === "undefined" ? Object : IPermissionResolver,
|
|
1657
|
+
typeof _flusys_nestjs_shared_modules__rspack_import_3.SharedPermissionCacheService === "undefined" ? Object : _flusys_nestjs_shared_modules__rspack_import_3.SharedPermissionCacheService
|
|
1646
1658
|
])
|
|
1647
1659
|
], FormResultService);
|
|
1648
1660
|
|
|
@@ -1663,6 +1675,8 @@ __webpack_require__.d(__webpack_exports__, {
|
|
|
1663
1675
|
|
|
1664
1676
|
// EXTERNAL MODULE: external "@flusys/nestjs-shared/classes"
|
|
1665
1677
|
var classes_ = __webpack_require__(937);
|
|
1678
|
+
// EXTERNAL MODULE: external "@flusys/nestjs-shared/interfaces"
|
|
1679
|
+
var interfaces_ = __webpack_require__(103);
|
|
1666
1680
|
// EXTERNAL MODULE: external "@flusys/nestjs-shared/modules"
|
|
1667
1681
|
var modules_ = __webpack_require__(236);
|
|
1668
1682
|
// EXTERNAL MODULE: external "@flusys/nestjs-shared/utils"
|
|
@@ -1679,6 +1693,8 @@ var message_keys = __webpack_require__(137);
|
|
|
1679
1693
|
var entities = __webpack_require__(814);
|
|
1680
1694
|
// EXTERNAL MODULE: ./projects/nestjs-form-builder/src/enums/form-access-type.enum.ts
|
|
1681
1695
|
var form_access_type_enum = __webpack_require__(376);
|
|
1696
|
+
// EXTERNAL MODULE: ./projects/nestjs-form-builder/src/utils/computed-field.utils.ts
|
|
1697
|
+
var computed_field_utils = __webpack_require__(801);
|
|
1682
1698
|
// EXTERNAL MODULE: ./projects/nestjs-form-builder/src/utils/permission.utils.ts
|
|
1683
1699
|
var permission_utils = __webpack_require__(988);
|
|
1684
1700
|
// EXTERNAL MODULE: ./projects/nestjs-form-builder/src/services/form-builder-config.service.ts
|
|
@@ -1721,17 +1737,24 @@ function _ts_param(paramIndex, decorator) {
|
|
|
1721
1737
|
|
|
1722
1738
|
|
|
1723
1739
|
|
|
1740
|
+
|
|
1741
|
+
|
|
1724
1742
|
class FormService extends classes_.ApiService {
|
|
1725
1743
|
cacheManager;
|
|
1726
1744
|
utilsService;
|
|
1727
1745
|
formBuilderConfig;
|
|
1728
|
-
|
|
1729
|
-
|
|
1746
|
+
permissionResolver;
|
|
1747
|
+
permissionCache;
|
|
1748
|
+
constructor(cacheManager, utilsService, formBuilderConfig, dataSourceProvider, permissionResolver, permissionCache){
|
|
1749
|
+
super(event_actions/* .FORM_BUILDER_EVENT_ENTITIES.FORM */.eF.FORM, cacheManager, utilsService, FormService.name, true, event_actions/* .FORM_BUILDER_EVENT_MODULE */.T$, dataSourceProvider, formBuilderConfig.isCompanyFeatureEnabled() ? entities/* .FormWithCompany */.Wl : entities/* .Form */.lV), this.cacheManager = cacheManager, this.utilsService = utilsService, this.formBuilderConfig = formBuilderConfig, this.permissionResolver = permissionResolver, this.permissionCache = permissionCache;
|
|
1730
1750
|
}
|
|
1731
1751
|
// Entity Conversion
|
|
1732
1752
|
async convertSingleDtoToEntity(dto, user) {
|
|
1733
1753
|
let form = {};
|
|
1734
1754
|
let isUpdate = false;
|
|
1755
|
+
if (dto.schema) {
|
|
1756
|
+
this.assertValidComputedFields(dto.schema);
|
|
1757
|
+
}
|
|
1735
1758
|
// NOTE: Using 'id' in dto check instead of instanceof - instanceof may not work after esbuild bundling
|
|
1736
1759
|
if ('id' in dto && dto.id && typeof dto.id === 'string') {
|
|
1737
1760
|
const dbData = await this.repository.findOne({
|
|
@@ -1776,6 +1799,19 @@ class FormService extends classes_.ApiService {
|
|
|
1776
1799
|
}
|
|
1777
1800
|
return form;
|
|
1778
1801
|
}
|
|
1802
|
+
assertValidComputedFields(schema) {
|
|
1803
|
+
const issue = (0,computed_field_utils/* .findComputedFieldIssue */.Qc)(schema);
|
|
1804
|
+
if (!issue) return;
|
|
1805
|
+
throw new common_.BadRequestException({
|
|
1806
|
+
message: `Computed field "${issue.field}" is invalid (${issue.code}).`,
|
|
1807
|
+
messageKey: message_keys/* .FORM_MESSAGES.INVALID_COMPUTED_FIELD */.Q.INVALID_COMPUTED_FIELD,
|
|
1808
|
+
messageVariables: {
|
|
1809
|
+
field: issue.field,
|
|
1810
|
+
code: issue.code,
|
|
1811
|
+
...issue.variables
|
|
1812
|
+
}
|
|
1813
|
+
});
|
|
1814
|
+
}
|
|
1779
1815
|
async getSelectQuery(query, _user, select) {
|
|
1780
1816
|
if (!select || !select.length) {
|
|
1781
1817
|
select = [
|
|
@@ -1786,7 +1822,7 @@ class FormService extends classes_.ApiService {
|
|
|
1786
1822
|
'schema',
|
|
1787
1823
|
'schemaVersion',
|
|
1788
1824
|
'accessType',
|
|
1789
|
-
'
|
|
1825
|
+
'permissionLogic',
|
|
1790
1826
|
'tags',
|
|
1791
1827
|
'isActive',
|
|
1792
1828
|
'createdAt',
|
|
@@ -1856,7 +1892,7 @@ class FormService extends classes_.ApiService {
|
|
|
1856
1892
|
schema: entity.schema,
|
|
1857
1893
|
schemaVersion: entity.schemaVersion,
|
|
1858
1894
|
accessType: entity.accessType,
|
|
1859
|
-
|
|
1895
|
+
permissionLogic: entity.permissionLogic,
|
|
1860
1896
|
tags: entity.tags,
|
|
1861
1897
|
isActive: entity.isActive,
|
|
1862
1898
|
companyId: entityWithCompany.companyId ?? null,
|
|
@@ -1966,7 +2002,7 @@ class FormService extends classes_.ApiService {
|
|
|
1966
2002
|
'name',
|
|
1967
2003
|
'description',
|
|
1968
2004
|
'accessType',
|
|
1969
|
-
'
|
|
2005
|
+
'permissionLogic',
|
|
1970
2006
|
'isActive'
|
|
1971
2007
|
]
|
|
1972
2008
|
});
|
|
@@ -1981,7 +2017,7 @@ class FormService extends classes_.ApiService {
|
|
|
1981
2017
|
name: form.name,
|
|
1982
2018
|
description: form.description,
|
|
1983
2019
|
accessType: form.accessType,
|
|
1984
|
-
|
|
2020
|
+
permissionLogic: form.permissionLogic,
|
|
1985
2021
|
isActive: form.isActive
|
|
1986
2022
|
};
|
|
1987
2023
|
}
|
|
@@ -2014,10 +2050,12 @@ class FormService extends classes_.ApiService {
|
|
|
2014
2050
|
}
|
|
2015
2051
|
async getAuthenticatedForm(formId, user) {
|
|
2016
2052
|
const form = await this.getFormForSubmission(formId, user);
|
|
2017
|
-
|
|
2018
|
-
|
|
2019
|
-
|
|
2020
|
-
|
|
2053
|
+
if (form.accessType === form_access_type_enum/* .FormAccessType.ACTION_GROUP */.h.ACTION_GROUP && form.permissionLogic) {
|
|
2054
|
+
const permitted = await (0,permission_utils/* .hasFormPermission */.E)(user, form.permissionLogic, {
|
|
2055
|
+
resolver: this.permissionResolver,
|
|
2056
|
+
cache: this.permissionCache
|
|
2057
|
+
});
|
|
2058
|
+
if (!permitted) {
|
|
2021
2059
|
throw new common_.ForbiddenException({
|
|
2022
2060
|
message: 'You do not have permission to access this form',
|
|
2023
2061
|
messageKey: message_keys/* .FORM_MESSAGES.ACCESS_DENIED */.Q.ACCESS_DENIED
|
|
@@ -2035,268 +2073,192 @@ FormService = _ts_decorate([
|
|
|
2035
2073
|
_ts_param(1, (0,common_.Inject)(modules_.UtilsService)),
|
|
2036
2074
|
_ts_param(2, (0,common_.Inject)(form_builder_config_service/* .FormBuilderConfigService */.j)),
|
|
2037
2075
|
_ts_param(3, (0,common_.Inject)(form_builder_datasource_provider/* .FormBuilderDataSourceProvider */._)),
|
|
2076
|
+
_ts_param(4, (0,common_.Optional)()),
|
|
2077
|
+
_ts_param(4, (0,common_.Inject)(interfaces_.PERMISSION_RESOLVER)),
|
|
2078
|
+
_ts_param(5, (0,common_.Optional)()),
|
|
2079
|
+
_ts_param(5, (0,common_.Inject)(modules_.SharedPermissionCacheService)),
|
|
2038
2080
|
_ts_metadata("design:type", Function),
|
|
2039
2081
|
_ts_metadata("design:paramtypes", [
|
|
2040
2082
|
typeof classes_.HybridCache === "undefined" ? Object : classes_.HybridCache,
|
|
2041
2083
|
typeof modules_.UtilsService === "undefined" ? Object : modules_.UtilsService,
|
|
2042
2084
|
typeof form_builder_config_service/* .FormBuilderConfigService */.j === "undefined" ? Object : form_builder_config_service/* .FormBuilderConfigService */.j,
|
|
2043
|
-
typeof form_builder_datasource_provider/* .FormBuilderDataSourceProvider */._ === "undefined" ? Object : form_builder_datasource_provider/* .FormBuilderDataSourceProvider */._
|
|
2085
|
+
typeof form_builder_datasource_provider/* .FormBuilderDataSourceProvider */._ === "undefined" ? Object : form_builder_datasource_provider/* .FormBuilderDataSourceProvider */._,
|
|
2086
|
+
typeof IPermissionResolver === "undefined" ? Object : IPermissionResolver,
|
|
2087
|
+
typeof modules_.SharedPermissionCacheService === "undefined" ? Object : modules_.SharedPermissionCacheService
|
|
2044
2088
|
])
|
|
2045
2089
|
], FormService);
|
|
2046
2090
|
|
|
2047
2091
|
|
|
2048
2092
|
},
|
|
2049
2093
|
801(__unused_rspack_module, __webpack_exports__, __webpack_require__) {
|
|
2050
|
-
|
|
2051
|
-
|
|
2052
|
-
|
|
2053
|
-
|
|
2054
|
-
|
|
2055
|
-
|
|
2056
|
-
* NOTE: Interface definitions here mirror @flusys/ng-form-builder interfaces
|
|
2057
|
-
* but are defined separately to avoid cross-package dependencies.
|
|
2058
|
-
* Both use compatible JSON structures for form schema serialization.
|
|
2059
|
-
*
|
|
2060
|
-
* @see FLUSYS_NG/projects/ng-form-builder/interfaces/computed-field.interface.ts
|
|
2061
|
-
*/ // ============================================================================
|
|
2062
|
-
// Type Definitions
|
|
2063
|
-
// ============================================================================
|
|
2064
|
-
// ============================================================================
|
|
2065
|
-
// Type Guards & Helpers
|
|
2066
|
-
// ============================================================================
|
|
2067
|
-
function isObject(value) {
|
|
2068
|
-
return typeof value === 'object' && value !== null;
|
|
2069
|
-
}
|
|
2070
|
-
function isDirectValueConfig(config) {
|
|
2071
|
-
return isObject(config) && config.type === 'direct' && 'value' in config;
|
|
2094
|
+
/* import */ var _flusys_nestjs_shared_utils__rspack_import_0 = __webpack_require__(216);
|
|
2095
|
+
|
|
2096
|
+
/** A field reference to an earlier computed field: `computed.<key>`. */ const COMPUTED_REF_PREFIX = 'computed.';
|
|
2097
|
+
const COMPUTED_KEY_PATTERN = /^[A-Za-z_]\w*$/;
|
|
2098
|
+
function asSchema(schema) {
|
|
2099
|
+
return typeof schema === 'object' && schema !== null ? schema : {};
|
|
2072
2100
|
}
|
|
2073
|
-
function
|
|
2074
|
-
return
|
|
2101
|
+
function formFields(schema) {
|
|
2102
|
+
return (schema.sections ?? []).flatMap((section)=>section.fields ?? []).filter((field)=>typeof field?.id === 'string');
|
|
2075
2103
|
}
|
|
2076
|
-
function
|
|
2077
|
-
|
|
2104
|
+
/** References resolve by field id, by field name (what templates use), or `computed.<key>`. */ function createResolver(data, fields, computed) {
|
|
2105
|
+
const idByName = new Map(fields.filter((f)=>f.name).map((f)=>[
|
|
2106
|
+
f.name,
|
|
2107
|
+
f.id
|
|
2108
|
+
]));
|
|
2109
|
+
return (ref)=>{
|
|
2110
|
+
if (ref.startsWith(COMPUTED_REF_PREFIX)) {
|
|
2111
|
+
const key = ref.slice(COMPUTED_REF_PREFIX.length);
|
|
2112
|
+
return Object.hasOwn(computed, key) ? computed[key] : undefined;
|
|
2113
|
+
}
|
|
2114
|
+
if (Object.hasOwn(data, ref)) return data[ref];
|
|
2115
|
+
const id = idByName.get(ref);
|
|
2116
|
+
return id !== undefined && Object.hasOwn(data, id) ? data[id] : undefined;
|
|
2117
|
+
};
|
|
2078
2118
|
}
|
|
2079
|
-
function
|
|
2080
|
-
|
|
2119
|
+
function castValue(value, valueType) {
|
|
2120
|
+
if (value === null || value === undefined) return null;
|
|
2121
|
+
switch(valueType){
|
|
2122
|
+
case 'number':
|
|
2123
|
+
try {
|
|
2124
|
+
return (0,_flusys_nestjs_shared_utils__rspack_import_0.expressionToNumber)(value);
|
|
2125
|
+
} catch {
|
|
2126
|
+
return null;
|
|
2127
|
+
}
|
|
2128
|
+
case 'boolean':
|
|
2129
|
+
if (typeof value === 'boolean') return value;
|
|
2130
|
+
return [
|
|
2131
|
+
'true',
|
|
2132
|
+
'1',
|
|
2133
|
+
'yes'
|
|
2134
|
+
].includes(((0,_flusys_nestjs_shared_utils__rspack_import_0.expressionToText)(value) ?? '').trim().toLowerCase());
|
|
2135
|
+
default:
|
|
2136
|
+
return (0,_flusys_nestjs_shared_utils__rspack_import_0.expressionToText)(value);
|
|
2137
|
+
}
|
|
2081
2138
|
}
|
|
2082
|
-
|
|
2083
|
-
|
|
2084
|
-
|
|
2085
|
-
|
|
2086
|
-
return
|
|
2139
|
+
function computeField(field, ctx) {
|
|
2140
|
+
for (const rule of field.rules ?? []){
|
|
2141
|
+
if (!rule.condition || (0,_flusys_nestjs_shared_utils__rspack_import_0.evaluateConditionGroup)(rule.condition, ctx)) return (0,_flusys_nestjs_shared_utils__rspack_import_0.evaluateExpression)(rule.value, ctx);
|
|
2142
|
+
}
|
|
2143
|
+
return field.defaultValue ?? null;
|
|
2087
2144
|
}
|
|
2088
2145
|
/**
|
|
2089
|
-
*
|
|
2090
|
-
*
|
|
2091
|
-
*
|
|
2092
|
-
|
|
2093
|
-
|
|
2094
|
-
|
|
2095
|
-
if (!computedFields || computedFields.length === 0) {
|
|
2096
|
-
return {};
|
|
2097
|
-
}
|
|
2146
|
+
* Computed values for a submission, keyed by each computed field's `key`. Fields run in order,
|
|
2147
|
+
* so a field may use earlier ones (`computed.<key>`); a field whose rules fail at run time gets
|
|
2148
|
+
* its default value instead of failing the submission.
|
|
2149
|
+
*/ function calculateComputedFields(data, schema) {
|
|
2150
|
+
const parsed = asSchema(schema);
|
|
2151
|
+
const computedFields = parsed.settings?.computedFields ?? [];
|
|
2098
2152
|
const result = {};
|
|
2153
|
+
if (computedFields.length === 0) return result;
|
|
2154
|
+
const ctx = {
|
|
2155
|
+
resolveRef: createResolver(data, formFields(parsed), result)
|
|
2156
|
+
};
|
|
2099
2157
|
for (const field of computedFields){
|
|
2158
|
+
let value;
|
|
2100
2159
|
try {
|
|
2101
|
-
|
|
2102
|
-
|
|
2103
|
-
|
|
2104
|
-
// If calculation fails, use default value or null
|
|
2105
|
-
result[field.key] = field.defaultValue ?? null;
|
|
2160
|
+
value = computeField(field, ctx);
|
|
2161
|
+
} catch {
|
|
2162
|
+
value = field.defaultValue ?? null;
|
|
2106
2163
|
}
|
|
2164
|
+
result[field.key] = castValue(value, field.valueType);
|
|
2107
2165
|
}
|
|
2108
2166
|
return result;
|
|
2109
2167
|
}
|
|
2110
|
-
/**
|
|
2111
|
-
|
|
2112
|
-
|
|
2113
|
-
|
|
2114
|
-
|
|
2115
|
-
|
|
2116
|
-
|
|
2168
|
+
/** First problem in the schema's computed fields, or null. Run on save so authors see it there, not at submit. */ function findComputedFieldIssue(schema) {
|
|
2169
|
+
const parsed = asSchema(schema);
|
|
2170
|
+
const computedFields = parsed.settings?.computedFields ?? [];
|
|
2171
|
+
const fields = formFields(parsed);
|
|
2172
|
+
const knownRefs = new Set(fields.flatMap((f)=>f.name ? [
|
|
2173
|
+
f.id,
|
|
2174
|
+
f.name
|
|
2175
|
+
] : [
|
|
2176
|
+
f.id
|
|
2177
|
+
]));
|
|
2178
|
+
const earlierKeys = new Set();
|
|
2179
|
+
for (const field of computedFields){
|
|
2180
|
+
const label = String(field?.name || field?.key || '');
|
|
2181
|
+
if (typeof field?.key !== 'string' || !COMPUTED_KEY_PATTERN.test(field.key)) {
|
|
2182
|
+
return {
|
|
2183
|
+
field: label,
|
|
2184
|
+
code: 'invalid_key',
|
|
2185
|
+
variables: {
|
|
2186
|
+
key: String(field?.key ?? '')
|
|
2187
|
+
}
|
|
2188
|
+
};
|
|
2117
2189
|
}
|
|
2118
|
-
|
|
2119
|
-
|
|
2120
|
-
|
|
2121
|
-
|
|
2122
|
-
|
|
2123
|
-
|
|
2124
|
-
|
|
2125
|
-
|
|
2126
|
-
|
|
2127
|
-
|
|
2128
|
-
|
|
2129
|
-
|
|
2130
|
-
|
|
2131
|
-
|
|
2132
|
-
|
|
2133
|
-
|
|
2134
|
-
|
|
2135
|
-
|
|
2136
|
-
|
|
2137
|
-
}
|
|
2138
|
-
|
|
2139
|
-
|
|
2140
|
-
|
|
2141
|
-
|
|
2142
|
-
|
|
2143
|
-
|
|
2144
|
-
|
|
2145
|
-
|
|
2146
|
-
|
|
2147
|
-
|
|
2148
|
-
|
|
2149
|
-
return isEmptyValue(fieldValue);
|
|
2150
|
-
case 'is_not_empty':
|
|
2151
|
-
return !isEmptyValue(fieldValue);
|
|
2152
|
-
case 'contains':
|
|
2153
|
-
return String(fieldValue).includes(String(compareValue));
|
|
2154
|
-
case 'not_contains':
|
|
2155
|
-
return !String(fieldValue).includes(String(compareValue));
|
|
2156
|
-
case 'starts_with':
|
|
2157
|
-
return String(fieldValue).startsWith(String(compareValue));
|
|
2158
|
-
case 'ends_with':
|
|
2159
|
-
return String(fieldValue).endsWith(String(compareValue));
|
|
2160
|
-
case 'greater_than':
|
|
2161
|
-
return Number(fieldValue) > Number(compareValue);
|
|
2162
|
-
case 'less_than':
|
|
2163
|
-
return Number(fieldValue) < Number(compareValue);
|
|
2164
|
-
case 'greater_or_equal':
|
|
2165
|
-
return Number(fieldValue) >= Number(compareValue);
|
|
2166
|
-
case 'less_or_equal':
|
|
2167
|
-
return Number(fieldValue) <= Number(compareValue);
|
|
2168
|
-
case 'is_before':
|
|
2169
|
-
return new Date(String(fieldValue)) < new Date(String(compareValue));
|
|
2170
|
-
case 'is_after':
|
|
2171
|
-
return new Date(String(fieldValue)) > new Date(String(compareValue));
|
|
2172
|
-
case 'is_checked':
|
|
2173
|
-
return fieldValue === true || fieldValue === 'true' || fieldValue === 1;
|
|
2174
|
-
case 'is_not_checked':
|
|
2175
|
-
return fieldValue === false || fieldValue === 'false' || fieldValue === 0 || !fieldValue;
|
|
2176
|
-
case 'is_any_of':
|
|
2177
|
-
case 'in':
|
|
2178
|
-
return Array.isArray(compareValue) && compareValue.includes(fieldValue);
|
|
2179
|
-
case 'is_none_of':
|
|
2180
|
-
case 'not_in':
|
|
2181
|
-
return !Array.isArray(compareValue) || !compareValue.includes(fieldValue);
|
|
2182
|
-
default:
|
|
2183
|
-
return false;
|
|
2184
|
-
}
|
|
2185
|
-
}
|
|
2186
|
-
/**
|
|
2187
|
-
* Execute a computation and return the result
|
|
2188
|
-
*/ function executeComputation(formData, computation, valueType) {
|
|
2189
|
-
const { config } = computation;
|
|
2190
|
-
// Use type guards for safe access
|
|
2191
|
-
if (computation.type === 'direct' && isDirectValueConfig(config)) {
|
|
2192
|
-
return valueType === 'number' ? Number(config.value) : String(config.value);
|
|
2193
|
-
}
|
|
2194
|
-
if (computation.type === 'field_reference' && isFieldReferenceConfig(config)) {
|
|
2195
|
-
const value = formData[config.fieldId];
|
|
2196
|
-
if (value === null || value === undefined) {
|
|
2197
|
-
return null;
|
|
2190
|
+
if (earlierKeys.has(field.key)) return {
|
|
2191
|
+
field: label,
|
|
2192
|
+
code: 'duplicate_key',
|
|
2193
|
+
variables: {
|
|
2194
|
+
key: field.key
|
|
2195
|
+
}
|
|
2196
|
+
};
|
|
2197
|
+
if (!Array.isArray(field.rules)) return {
|
|
2198
|
+
field: label,
|
|
2199
|
+
code: 'invalid_node',
|
|
2200
|
+
variables: {
|
|
2201
|
+
type: 'rules'
|
|
2202
|
+
}
|
|
2203
|
+
};
|
|
2204
|
+
const isKnownRef = (ref)=>knownRefs.has(ref) || ref.startsWith(COMPUTED_REF_PREFIX) && earlierKeys.has(ref.slice(COMPUTED_REF_PREFIX.length));
|
|
2205
|
+
try {
|
|
2206
|
+
for (const rule of field.rules){
|
|
2207
|
+
if (rule.condition) (0,_flusys_nestjs_shared_utils__rspack_import_0.assertValidConditionGroup)(rule.condition, {
|
|
2208
|
+
isKnownRef
|
|
2209
|
+
});
|
|
2210
|
+
(0,_flusys_nestjs_shared_utils__rspack_import_0.assertValidExpression)(rule.value, {
|
|
2211
|
+
isKnownRef
|
|
2212
|
+
});
|
|
2213
|
+
}
|
|
2214
|
+
} catch (error) {
|
|
2215
|
+
if ((0,_flusys_nestjs_shared_utils__rspack_import_0.isExpressionError)(error)) return {
|
|
2216
|
+
field: label,
|
|
2217
|
+
code: error.code,
|
|
2218
|
+
variables: error.variables
|
|
2219
|
+
};
|
|
2220
|
+
throw error;
|
|
2198
2221
|
}
|
|
2199
|
-
|
|
2222
|
+
earlierKeys.add(field.key);
|
|
2200
2223
|
}
|
|
2201
|
-
if (computation.type === 'arithmetic' && isArithmeticConfig(config)) {
|
|
2202
|
-
return calculateArithmetic(formData, config);
|
|
2203
|
-
}
|
|
2204
|
-
// Unknown computation type
|
|
2205
2224
|
return null;
|
|
2206
2225
|
}
|
|
2207
|
-
/**
|
|
2208
|
-
* Perform arithmetic calculation
|
|
2209
|
-
*/ function calculateArithmetic(formData, config) {
|
|
2210
|
-
const values = config.operands.map((operand)=>{
|
|
2211
|
-
if (operand.type === 'constant') {
|
|
2212
|
-
return operand.value ?? 0;
|
|
2213
|
-
} else {
|
|
2214
|
-
const fieldValue = formData[operand.fieldId ?? ''];
|
|
2215
|
-
return fieldValue !== null && fieldValue !== undefined ? Number(fieldValue) : 0;
|
|
2216
|
-
}
|
|
2217
|
-
});
|
|
2218
|
-
if (values.length === 0) {
|
|
2219
|
-
return null;
|
|
2220
|
-
}
|
|
2221
|
-
switch(config.operation){
|
|
2222
|
-
case 'sum':
|
|
2223
|
-
case 'increment':
|
|
2224
|
-
return values.reduce((acc, val)=>acc + val, 0);
|
|
2225
|
-
case 'subtract':
|
|
2226
|
-
case 'decrement':
|
|
2227
|
-
return values.reduce((acc, val, idx)=>idx === 0 ? val : acc - val, 0);
|
|
2228
|
-
case 'multiply':
|
|
2229
|
-
return values.reduce((acc, val)=>acc * val, 1);
|
|
2230
|
-
case 'divide':
|
|
2231
|
-
{
|
|
2232
|
-
const [first, ...rest] = values;
|
|
2233
|
-
return rest.reduce((acc, val)=>val !== 0 ? acc / val : acc, first);
|
|
2234
|
-
}
|
|
2235
|
-
case 'average':
|
|
2236
|
-
return values.reduce((acc, val)=>acc + val, 0) / values.length;
|
|
2237
|
-
case 'min':
|
|
2238
|
-
return Math.min(...values);
|
|
2239
|
-
case 'max':
|
|
2240
|
-
return Math.max(...values);
|
|
2241
|
-
default:
|
|
2242
|
-
return null;
|
|
2243
|
-
}
|
|
2244
|
-
}
|
|
2245
2226
|
|
|
2246
2227
|
__webpack_require__.d(__webpack_exports__, {
|
|
2247
|
-
|
|
2228
|
+
Qc: () => (findComputedFieldIssue),
|
|
2229
|
+
XZ: () => (calculateComputedFields)
|
|
2230
|
+
}, {
|
|
2231
|
+
xI: COMPUTED_REF_PREFIX
|
|
2248
2232
|
});
|
|
2249
2233
|
|
|
2250
2234
|
|
|
2251
2235
|
},
|
|
2252
2236
|
988(__unused_rspack_module, __webpack_exports__, __webpack_require__) {
|
|
2253
|
-
/* import */ var
|
|
2254
|
-
/* import */ var
|
|
2237
|
+
/* import */ var _flusys_nestjs_shared_utils__rspack_import_0 = __webpack_require__(216);
|
|
2238
|
+
/* import */ var _nestjs_common__rspack_import_1 = __webpack_require__(157);
|
|
2239
|
+
/* import */ var _config_index_js__rspack_import_2 = __webpack_require__(137);
|
|
2255
2240
|
|
|
2256
2241
|
|
|
2257
|
-
|
|
2258
|
-
/**
|
|
2259
|
-
|
|
2260
|
-
* Uses same cache key format as PermissionGuard in nestjs-shared
|
|
2261
|
-
*/ function buildPermissionCacheKey(user, enableCompanyFeature) {
|
|
2262
|
-
if (enableCompanyFeature && user.companyId) {
|
|
2263
|
-
return `${CACHE_PREFIX}:company:${user.companyId}:branch:${user.branchId || 'null'}:user:${user.id}`;
|
|
2264
|
-
}
|
|
2265
|
-
return `${CACHE_PREFIX}:user:${user.id}`;
|
|
2266
|
-
}
|
|
2267
|
-
/**
|
|
2268
|
-
* Get user permissions from cache
|
|
2269
|
-
* Fail-closed: if cache fails, deny access rather than allowing potentially unauthorized access
|
|
2270
|
-
*/ async function getUserPermissionsFromCache(user, cacheManager, enableCompanyFeature) {
|
|
2271
|
-
const cacheKey = buildPermissionCacheKey(user, enableCompanyFeature);
|
|
2242
|
+
|
|
2243
|
+
/** Whether `user` passes a form's AND / OR permission rule; fails closed when permissions cannot be read. */ async function hasFormPermission(user, logic, sources) {
|
|
2244
|
+
let granted;
|
|
2272
2245
|
try {
|
|
2273
|
-
|
|
2274
|
-
|
|
2246
|
+
granted = await (0,_flusys_nestjs_shared_utils__rspack_import_0.loadPermissionCodes)({
|
|
2247
|
+
userId: user.id,
|
|
2248
|
+
companyId: user.companyId,
|
|
2249
|
+
branchId: user.branchId
|
|
2250
|
+
}, sources);
|
|
2275
2251
|
} catch {
|
|
2276
|
-
throw new
|
|
2252
|
+
throw new _nestjs_common__rspack_import_1.ForbiddenException({
|
|
2277
2253
|
message: 'Unable to verify permissions. Please try again.',
|
|
2278
|
-
messageKey:
|
|
2254
|
+
messageKey: _config_index_js__rspack_import_2/* .FORM_MESSAGES.PERMISSION_CHECK_FAILED */.Q.PERMISSION_CHECK_FAILED
|
|
2279
2255
|
});
|
|
2280
2256
|
}
|
|
2281
|
-
|
|
2282
|
-
/**
|
|
2283
|
-
* Validate user has at least one of the required permissions
|
|
2284
|
-
*
|
|
2285
|
-
* @param user - The logged-in user
|
|
2286
|
-
* @param requiredPermissions - Array of required permission strings (user needs at least one)
|
|
2287
|
-
* @param cacheManager - Cache manager instance
|
|
2288
|
-
* @param enableCompanyFeature - Whether company feature is enabled
|
|
2289
|
-
* @returns true if user has permission, false otherwise
|
|
2290
|
-
*/ async function validateUserPermissions(user, requiredPermissions, cacheManager, enableCompanyFeature) {
|
|
2291
|
-
if (!requiredPermissions.length) {
|
|
2292
|
-
return true;
|
|
2293
|
-
}
|
|
2294
|
-
const userPermissions = await getUserPermissionsFromCache(user, cacheManager, enableCompanyFeature);
|
|
2295
|
-
return requiredPermissions.some((perm)=>userPermissions.includes(perm));
|
|
2257
|
+
return (0,_flusys_nestjs_shared_utils__rspack_import_0.evaluatePermissionLogic)(logic, granted).passed;
|
|
2296
2258
|
}
|
|
2297
2259
|
|
|
2298
2260
|
__webpack_require__.d(__webpack_exports__, {
|
|
2299
|
-
|
|
2261
|
+
E: () => (hasFormPermission)
|
|
2300
2262
|
});
|
|
2301
2263
|
|
|
2302
2264
|
|
|
@@ -2318,6 +2280,12 @@ module.exports = __rspack_external__flusys_nestjs_shared_decorators_c129b601;
|
|
|
2318
2280
|
module.exports = __rspack_external__flusys_nestjs_shared_dtos_c4585026;
|
|
2319
2281
|
|
|
2320
2282
|
|
|
2283
|
+
},
|
|
2284
|
+
103(module) {
|
|
2285
|
+
|
|
2286
|
+
module.exports = __rspack_external__flusys_nestjs_shared_interfaces_413f2706;
|
|
2287
|
+
|
|
2288
|
+
|
|
2321
2289
|
},
|
|
2322
2290
|
236(module) {
|
|
2323
2291
|
|