@flusys/nestjs-form-builder 7.1.0 → 8.0.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.
Files changed (118) hide show
  1. package/config/index.d.ts +3 -3
  2. package/controllers/form-result.controller.d.ts +3 -3
  3. package/controllers/form.controller.d.ts +3 -3
  4. package/controllers/index.d.ts +2 -2
  5. package/docs/form-builder-swagger.config.d.ts +2 -2
  6. package/docs/index.d.ts +1 -1
  7. package/dtos/form.dto.d.ts +1 -1
  8. package/dtos/index.d.ts +2 -2
  9. package/entities/form-with-company.entity.d.ts +1 -1
  10. package/entities/form.entity.d.ts +1 -1
  11. package/entities/index.d.ts +7 -7
  12. package/enums/index.d.ts +1 -1
  13. package/fesm/262.js +1841 -0
  14. package/fesm/98.js +807 -0
  15. package/fesm/config/index.js +98 -3
  16. package/fesm/controllers/index.js +14 -2
  17. package/fesm/docs/index.js +171 -1
  18. package/fesm/dtos/index.js +571 -2
  19. package/fesm/entities/index.js +342 -10
  20. package/fesm/enums/index.js +38 -1
  21. package/fesm/index.js +482 -10
  22. package/fesm/interfaces/index.js +17 -3
  23. package/fesm/modules/index.js +178 -1
  24. package/fesm/runtime.js +85 -0
  25. package/fesm/services/index.js +35 -4
  26. package/index.d.ts +10 -10
  27. package/interfaces/form-builder-module.interface.d.ts +3 -3
  28. package/interfaces/form-result.interface.d.ts +1 -1
  29. package/interfaces/form.interface.d.ts +2 -2
  30. package/interfaces/index.d.ts +3 -3
  31. package/modules/form-builder.module.d.ts +2 -2
  32. package/modules/index.d.ts +1 -1
  33. package/package.json +26 -36
  34. package/services/form-builder-config.service.d.ts +4 -4
  35. package/services/form-builder-datasource.provider.d.ts +3 -3
  36. package/services/form-result.service.d.ts +6 -6
  37. package/services/form.service.d.ts +7 -7
  38. package/services/index.d.ts +4 -4
  39. package/utils/index.d.ts +2 -2
  40. package/utils/permission.utils.d.ts +1 -1
  41. package/cjs/config/event-actions.js +0 -33
  42. package/cjs/config/form-builder.constants.js +0 -13
  43. package/cjs/config/index.js +0 -20
  44. package/cjs/config/message-keys.js +0 -38
  45. package/cjs/controllers/form-result.controller.js +0 -281
  46. package/cjs/controllers/form-result.controller.spec.js +0 -257
  47. package/cjs/controllers/form.controller.js +0 -231
  48. package/cjs/controllers/form.controller.spec.js +0 -212
  49. package/cjs/controllers/index.js +0 -19
  50. package/cjs/docs/form-builder-swagger.config.js +0 -150
  51. package/cjs/docs/form-builder-swagger.config.spec.js +0 -75
  52. package/cjs/docs/index.js +0 -11
  53. package/cjs/dtos/form-result.dto.js +0 -248
  54. package/cjs/dtos/form.dto.js +0 -270
  55. package/cjs/dtos/index.js +0 -19
  56. package/cjs/entities/form-result.entity.js +0 -100
  57. package/cjs/entities/form-with-company.entity.js +0 -65
  58. package/cjs/entities/form.entity.js +0 -127
  59. package/cjs/entities/index.js +0 -52
  60. package/cjs/entities/index.spec.js +0 -18
  61. package/cjs/enums/form-access-type.enum.js +0 -19
  62. package/cjs/enums/index.js +0 -18
  63. package/cjs/index.js +0 -28
  64. package/cjs/interfaces/form-builder-module.interface.js +0 -4
  65. package/cjs/interfaces/form-result.interface.js +0 -4
  66. package/cjs/interfaces/form.interface.js +0 -4
  67. package/cjs/interfaces/index.js +0 -20
  68. package/cjs/modules/form-builder.module.js +0 -136
  69. package/cjs/modules/form-builder.module.spec.js +0 -133
  70. package/cjs/modules/index.js +0 -18
  71. package/cjs/services/form-builder-config.service.js +0 -69
  72. package/cjs/services/form-builder-config.service.spec.js +0 -121
  73. package/cjs/services/form-builder-datasource.provider.js +0 -125
  74. package/cjs/services/form-builder-datasource.provider.spec.js +0 -147
  75. package/cjs/services/form-result.service.js +0 -366
  76. package/cjs/services/form-result.service.spec.js +0 -823
  77. package/cjs/services/form.service.js +0 -341
  78. package/cjs/services/form.service.spec.js +0 -746
  79. package/cjs/services/index.js +0 -21
  80. package/cjs/utils/computed-field.utils.js +0 -199
  81. package/cjs/utils/computed-field.utils.spec.js +0 -1205
  82. package/cjs/utils/index.js +0 -19
  83. package/cjs/utils/permission.utils.js +0 -44
  84. package/cjs/utils/permission.utils.spec.js +0 -118
  85. package/fesm/config/event-actions.js +0 -12
  86. package/fesm/config/form-builder.constants.js +0 -3
  87. package/fesm/config/message-keys.js +0 -20
  88. package/fesm/controllers/form-result.controller.js +0 -271
  89. package/fesm/controllers/form-result.controller.spec.js +0 -253
  90. package/fesm/controllers/form.controller.js +0 -221
  91. package/fesm/controllers/form.controller.spec.js +0 -208
  92. package/fesm/docs/form-builder-swagger.config.js +0 -146
  93. package/fesm/docs/form-builder-swagger.config.spec.js +0 -71
  94. package/fesm/dtos/form-result.dto.js +0 -215
  95. package/fesm/dtos/form.dto.js +0 -243
  96. package/fesm/entities/form-result.entity.js +0 -90
  97. package/fesm/entities/form-with-company.entity.js +0 -55
  98. package/fesm/entities/form.entity.js +0 -117
  99. package/fesm/entities/index.spec.js +0 -14
  100. package/fesm/enums/form-access-type.enum.js +0 -9
  101. package/fesm/interfaces/form-builder-module.interface.js +0 -3
  102. package/fesm/interfaces/form-result.interface.js +0 -6
  103. package/fesm/interfaces/form.interface.js +0 -3
  104. package/fesm/modules/form-builder.module.js +0 -126
  105. package/fesm/modules/form-builder.module.spec.js +0 -129
  106. package/fesm/services/form-builder-config.service.js +0 -59
  107. package/fesm/services/form-builder-config.service.spec.js +0 -117
  108. package/fesm/services/form-builder-datasource.provider.js +0 -74
  109. package/fesm/services/form-builder-datasource.provider.spec.js +0 -143
  110. package/fesm/services/form-result.service.js +0 -356
  111. package/fesm/services/form-result.service.spec.js +0 -778
  112. package/fesm/services/form.service.js +0 -331
  113. package/fesm/services/form.service.spec.js +0 -701
  114. package/fesm/utils/computed-field.utils.js +0 -195
  115. package/fesm/utils/computed-field.utils.spec.js +0 -1201
  116. package/fesm/utils/index.js +0 -2
  117. package/fesm/utils/permission.utils.js +0 -42
  118. package/fesm/utils/permission.utils.spec.js +0 -114
@@ -1,331 +0,0 @@
1
- function _define_property(obj, key, value) {
2
- if (key in obj) {
3
- Object.defineProperty(obj, key, {
4
- value: value,
5
- enumerable: true,
6
- configurable: true,
7
- writable: true
8
- });
9
- } else {
10
- obj[key] = value;
11
- }
12
- return obj;
13
- }
14
- function _ts_decorate(decorators, target, key, desc) {
15
- var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
16
- if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
17
- else for(var i = decorators.length - 1; i >= 0; i--)if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
18
- return c > 3 && r && Object.defineProperty(target, key, r), r;
19
- }
20
- function _ts_metadata(k, v) {
21
- if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
22
- }
23
- function _ts_param(paramIndex, decorator) {
24
- return function(target, key) {
25
- decorator(target, key, paramIndex);
26
- };
27
- }
28
- import { envConfig } from '@flusys/nestjs-core';
29
- import { HybridCache, ApiService } from '@flusys/nestjs-shared/classes';
30
- import { UtilsService } from '@flusys/nestjs-shared/modules';
31
- import { applyCompanyFilter } from '@flusys/nestjs-shared/utils';
32
- import { BadRequestException, ForbiddenException, Inject, Injectable, NotFoundException, Scope, UnauthorizedException } from '@nestjs/common';
33
- import { IsNull } from 'typeorm';
34
- import { FORM_BUILDER_EVENT_ENTITIES, FORM_BUILDER_EVENT_MODULE, FORM_MESSAGES } from '../config';
35
- import { Form, FormWithCompany } from '../entities';
36
- import { FormAccessType } from '../enums/form-access-type.enum';
37
- import { validateUserPermissions } from '../utils/permission.utils';
38
- import { FormBuilderConfigService } from './form-builder-config.service';
39
- import { FormBuilderDataSourceProvider } from './form-builder-datasource.provider';
40
- export class FormService extends ApiService {
41
- // Entity Conversion
42
- async convertSingleDtoToEntity(dto, user) {
43
- let form = {};
44
- let isUpdate = false;
45
- // NOTE: Using 'id' in dto check instead of instanceof - instanceof may not work after esbuild bundling
46
- if ('id' in dto && dto.id && typeof dto.id === 'string') {
47
- const dbData = await this.repository.findOne({
48
- where: {
49
- id: dto.id
50
- }
51
- });
52
- if (!dbData) {
53
- throw new NotFoundException({
54
- message: 'Form not found',
55
- messageKey: FORM_MESSAGES.NOT_FOUND
56
- });
57
- }
58
- form = dbData;
59
- isUpdate = true;
60
- // Auto-increment schema version if schema changed
61
- if (dto.schema && JSON.stringify(dto.schema) !== JSON.stringify(form.schema)) {
62
- dto.schemaVersion = form.schemaVersion + 1;
63
- }
64
- }
65
- // Merge DTO into form
66
- form = {
67
- ...form,
68
- ...dto
69
- };
70
- // Set company context if enabled
71
- const enableCompanyFeature = this.formBuilderConfig.isCompanyFeatureEnabled();
72
- if (enableCompanyFeature) {
73
- if (isUpdate) {
74
- // During update: Only set companyId if explicitly provided
75
- if (dto.companyId !== undefined) {
76
- form.companyId = dto.companyId;
77
- }
78
- // If companyId is not in form at all, set from user
79
- if (form.companyId === undefined) {
80
- form.companyId = user?.companyId ?? null;
81
- }
82
- } else {
83
- // During creation: Use DTO's companyId if provided, otherwise use user's
84
- form.companyId = dto.companyId ?? user?.companyId ?? null;
85
- }
86
- }
87
- return form;
88
- }
89
- async getSelectQuery(query, _user, select) {
90
- if (!select || !select.length) {
91
- select = [
92
- 'id',
93
- 'name',
94
- 'description',
95
- 'slug',
96
- 'schema',
97
- 'schemaVersion',
98
- 'accessType',
99
- 'actionGroups',
100
- 'tags',
101
- 'isActive',
102
- 'createdAt',
103
- 'updatedAt'
104
- ];
105
- }
106
- const selectFields = select.map((field)=>`${this.entityName}.${field}`);
107
- // Add company context fields if company feature is enabled
108
- if (this.formBuilderConfig.isCompanyFeatureEnabled()) {
109
- selectFields.push('form.companyId');
110
- }
111
- query.select(selectFields);
112
- return {
113
- query,
114
- isRaw: false
115
- };
116
- }
117
- // Supports filtering by one or more tags (array-contains-all) via the generic get-all filter,
118
- // e.g. { filter: { tags: ['survey', 'review'] } }, since tags is a JSON array column.
119
- async getFilterQuery(query, filter, user) {
120
- const { tags, ...rest } = filter;
121
- if (tags !== undefined && tags !== null) {
122
- const tagList = (Array.isArray(tags) ? tags : [
123
- tags
124
- ]).map(String);
125
- if (tagList.length > 0) {
126
- this.applyTagFilter(query, tagList);
127
- }
128
- }
129
- return super.getFilterQuery(query, rest, user);
130
- }
131
- applyTagFilter(query, tags) {
132
- const driver = envConfig.getTypeOrmConfig().type;
133
- if (driver === 'postgres') {
134
- query.andWhere(`${this.entityName}.tags @> :tagValues::jsonb`, {
135
- tagValues: JSON.stringify(tags)
136
- });
137
- } else if (driver === 'mysql') {
138
- query.andWhere(`JSON_CONTAINS(${this.entityName}.tags, :tagValues)`, {
139
- tagValues: JSON.stringify(tags)
140
- });
141
- } else {
142
- tags.forEach((tag, index)=>{
143
- query.andWhere(`${this.entityName}.tags LIKE :tagValue${index}`, {
144
- [`tagValue${index}`]: `%"${tag}"%`
145
- });
146
- });
147
- }
148
- }
149
- async getExtraManipulateQuery(query, filterDto, user) {
150
- const result = await super.getExtraManipulateQuery(query, filterDto, user);
151
- // Apply company filter using shared utility
152
- applyCompanyFilter(query, {
153
- isCompanyFeatureEnabled: this.formBuilderConfig.isCompanyFeatureEnabled(),
154
- entityAlias: 'form'
155
- }, user);
156
- return result;
157
- }
158
- convertEntityToResponseDto(entity, _isRaw) {
159
- // Type guard for company-enabled entity
160
- const entityWithCompany = entity;
161
- return {
162
- id: entity.id,
163
- name: entity.name,
164
- description: entity.description,
165
- slug: entity.slug,
166
- schema: entity.schema,
167
- schemaVersion: entity.schemaVersion,
168
- accessType: entity.accessType,
169
- actionGroups: entity.actionGroups,
170
- tags: entity.tags,
171
- isActive: entity.isActive,
172
- companyId: entityWithCompany.companyId ?? null,
173
- createdAt: entity.createdAt,
174
- updatedAt: entity.updatedAt,
175
- deletedAt: entity.deletedAt,
176
- createdById: entity.createdById,
177
- updatedById: entity.updatedById,
178
- deletedById: entity.deletedById
179
- };
180
- }
181
- toPublicForm(form) {
182
- return {
183
- id: form.id,
184
- name: form.name,
185
- description: form.description,
186
- schema: form.schema,
187
- schemaVersion: form.schemaVersion
188
- };
189
- }
190
- async findPublicActiveForm(where) {
191
- await this.ensureDataSourceRepository();
192
- return await this.repository.findOne({
193
- where: {
194
- ...where,
195
- accessType: FormAccessType.PUBLIC,
196
- isActive: true,
197
- deletedAt: IsNull()
198
- }
199
- });
200
- }
201
- // Public Form Access
202
- async getPublicForm(formId) {
203
- const form = await this.findPublicActiveForm({
204
- id: formId
205
- });
206
- if (!form) {
207
- throw new NotFoundException({
208
- message: 'Form not found or not available for public access',
209
- messageKey: FORM_MESSAGES.NOT_PUBLIC
210
- });
211
- }
212
- return this.toPublicForm(form);
213
- }
214
- async getFormForSubmission(formId, user) {
215
- await this.ensureDataSourceRepository();
216
- const form = await this.repository.findOne({
217
- where: {
218
- id: formId,
219
- isActive: true,
220
- deletedAt: IsNull()
221
- }
222
- });
223
- if (!form) {
224
- throw new NotFoundException({
225
- message: 'Form not found or inactive',
226
- messageKey: FORM_MESSAGES.NOT_FOUND
227
- });
228
- }
229
- // Access validation based on accessType
230
- if (form.accessType === FormAccessType.PUBLIC) {
231
- return form; // Anyone can access
232
- }
233
- // All non-public forms require authentication
234
- if (!user) {
235
- throw new UnauthorizedException({
236
- message: 'Authentication required to submit this form',
237
- messageKey: FORM_MESSAGES.AUTH_REQUIRED
238
- });
239
- }
240
- if (form.accessType === FormAccessType.AUTHENTICATED || form.accessType === FormAccessType.ACTION_GROUP) {
241
- return form; // Permission check for ACTION_GROUP is handled by the controller/guard
242
- }
243
- throw new BadRequestException({
244
- message: 'Invalid access type',
245
- messageKey: FORM_MESSAGES.INVALID_ACCESS_TYPE
246
- });
247
- }
248
- async getBySlug(slug) {
249
- await this.ensureDataSourceRepository();
250
- const form = await this.repository.findOne({
251
- where: {
252
- slug,
253
- deletedAt: IsNull()
254
- }
255
- });
256
- return form ? this.convertEntityToResponseDto(form, false) : null;
257
- }
258
- /**
259
- * Get public form by slug (no authentication required)
260
- * Returns null if form doesn't exist, is not public, or is inactive
261
- */ async getPublicFormBySlug(slug) {
262
- const form = await this.findPublicActiveForm({
263
- slug
264
- });
265
- return form ? this.toPublicForm(form) : null;
266
- }
267
- async getFormAccessInfo(formId) {
268
- await this.ensureDataSourceRepository();
269
- const form = await this.repository.findOne({
270
- where: {
271
- id: formId,
272
- deletedAt: IsNull()
273
- },
274
- select: [
275
- 'id',
276
- 'name',
277
- 'description',
278
- 'accessType',
279
- 'actionGroups',
280
- 'isActive'
281
- ]
282
- });
283
- if (!form) {
284
- throw new NotFoundException({
285
- message: 'Form not found',
286
- messageKey: FORM_MESSAGES.NOT_FOUND
287
- });
288
- }
289
- return {
290
- id: form.id,
291
- name: form.name,
292
- description: form.description,
293
- accessType: form.accessType,
294
- actionGroups: form.actionGroups,
295
- isActive: form.isActive
296
- };
297
- }
298
- async getAuthenticatedForm(formId, user) {
299
- const form = await this.getFormForSubmission(formId, user);
300
- // For action_group access, check permissions from cache
301
- if (form.accessType === FormAccessType.ACTION_GROUP && form.actionGroups?.length) {
302
- const hasPermission = await validateUserPermissions(user, form.actionGroups, this.cacheManager, this.formBuilderConfig.isCompanyFeatureEnabled());
303
- if (!hasPermission) {
304
- throw new ForbiddenException({
305
- message: 'You do not have permission to access this form',
306
- messageKey: FORM_MESSAGES.ACCESS_DENIED
307
- });
308
- }
309
- }
310
- return this.toPublicForm(form);
311
- }
312
- constructor(cacheManager, utilsService, formBuilderConfig, dataSourceProvider){
313
- super(FORM_BUILDER_EVENT_ENTITIES.FORM, cacheManager, utilsService, FormService.name, true, FORM_BUILDER_EVENT_MODULE, dataSourceProvider, formBuilderConfig.isCompanyFeatureEnabled() ? FormWithCompany : Form), _define_property(this, "cacheManager", void 0), _define_property(this, "utilsService", void 0), _define_property(this, "formBuilderConfig", void 0), this.cacheManager = cacheManager, this.utilsService = utilsService, this.formBuilderConfig = formBuilderConfig;
314
- }
315
- }
316
- FormService = _ts_decorate([
317
- Injectable({
318
- scope: Scope.REQUEST
319
- }),
320
- _ts_param(0, Inject('CACHE_INSTANCE')),
321
- _ts_param(1, Inject(UtilsService)),
322
- _ts_param(2, Inject(FormBuilderConfigService)),
323
- _ts_param(3, Inject(FormBuilderDataSourceProvider)),
324
- _ts_metadata("design:type", Function),
325
- _ts_metadata("design:paramtypes", [
326
- typeof HybridCache === "undefined" ? Object : HybridCache,
327
- typeof UtilsService === "undefined" ? Object : UtilsService,
328
- typeof FormBuilderConfigService === "undefined" ? Object : FormBuilderConfigService,
329
- typeof FormBuilderDataSourceProvider === "undefined" ? Object : FormBuilderDataSourceProvider
330
- ])
331
- ], FormService);