@flusys/nestjs-form-builder 1.1.0-beta → 1.1.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 (54) hide show
  1. package/README.md +723 -0
  2. package/cjs/controllers/form-result.controller.js +67 -5
  3. package/cjs/controllers/form.controller.js +48 -15
  4. package/cjs/docs/form-builder-swagger.config.js +6 -100
  5. package/cjs/dtos/form-result.dto.js +6 -93
  6. package/cjs/dtos/form.dto.js +21 -163
  7. package/cjs/entities/form-with-company.entity.js +12 -2
  8. package/cjs/entities/form.entity.js +103 -3
  9. package/cjs/entities/index.js +28 -16
  10. package/cjs/index.js +1 -0
  11. package/cjs/interfaces/form-result.interface.js +1 -6
  12. package/cjs/modules/form-builder.module.js +57 -83
  13. package/cjs/services/form-builder-config.service.js +6 -16
  14. package/cjs/services/form-builder-datasource.provider.js +17 -63
  15. package/cjs/services/form-result.service.js +107 -181
  16. package/cjs/services/form.service.js +56 -72
  17. package/cjs/utils/computed-field.utils.js +17 -29
  18. package/cjs/utils/permission.utils.js +11 -16
  19. package/controllers/form-result.controller.d.ts +10 -12
  20. package/dtos/form-result.dto.d.ts +2 -19
  21. package/dtos/form.dto.d.ts +6 -32
  22. package/entities/form-with-company.entity.d.ts +2 -2
  23. package/entities/form.entity.d.ts +12 -2
  24. package/entities/index.d.ts +7 -2
  25. package/fesm/controllers/form-result.controller.js +69 -7
  26. package/fesm/controllers/form.controller.js +50 -17
  27. package/fesm/docs/form-builder-swagger.config.js +6 -100
  28. package/fesm/dtos/form-result.dto.js +9 -99
  29. package/fesm/dtos/form.dto.js +22 -165
  30. package/fesm/entities/form-with-company.entity.js +12 -2
  31. package/fesm/entities/form.entity.js +104 -4
  32. package/fesm/entities/index.js +18 -24
  33. package/fesm/index.js +2 -0
  34. package/fesm/modules/form-builder.module.js +57 -83
  35. package/fesm/services/form-builder-config.service.js +6 -16
  36. package/fesm/services/form-builder-datasource.provider.js +17 -63
  37. package/fesm/services/form-result.service.js +107 -181
  38. package/fesm/services/form.service.js +56 -72
  39. package/fesm/utils/computed-field.utils.js +17 -29
  40. package/fesm/utils/permission.utils.js +2 -9
  41. package/index.d.ts +1 -0
  42. package/interfaces/form-builder-module.interface.d.ts +4 -7
  43. package/interfaces/form-result.interface.d.ts +2 -9
  44. package/interfaces/form.interface.d.ts +2 -10
  45. package/modules/form-builder.module.d.ts +4 -3
  46. package/package.json +3 -3
  47. package/services/form-builder-config.service.d.ts +5 -3
  48. package/services/form-builder-datasource.provider.d.ts +3 -6
  49. package/services/form-result.service.d.ts +5 -0
  50. package/services/form.service.d.ts +13 -10
  51. package/utils/permission.utils.d.ts +0 -2
  52. package/cjs/entities/form-base.entity.js +0 -113
  53. package/entities/form-base.entity.d.ts +0 -13
  54. package/fesm/entities/form-base.entity.js +0 -106
@@ -10,6 +10,7 @@ Object.defineProperty(exports, "FormService", {
10
10
  });
11
11
  const _classes = require("@flusys/nestjs-shared/classes");
12
12
  const _modules = require("@flusys/nestjs-shared/modules");
13
+ const _utils = require("@flusys/nestjs-shared/utils");
13
14
  const _common = require("@nestjs/common");
14
15
  const _typeorm = require("typeorm");
15
16
  const _formbuilderconfigservice = require("./form-builder-config.service");
@@ -45,17 +46,11 @@ function _ts_param(paramIndex, decorator) {
45
46
  };
46
47
  }
47
48
  let FormService = class FormService extends _classes.RequestScopedApiService {
48
- /**
49
- * Resolve entity class for this service
50
- * @returns Form or FormWithCompany based on configuration
51
- */ resolveEntity() {
49
+ resolveEntity() {
52
50
  const enableCompanyFeature = this.formBuilderConfig.isCompanyFeatureEnabled();
53
51
  return enableCompanyFeature ? _entities.FormWithCompany : _entities.Form;
54
52
  }
55
- /**
56
- * Get DataSource provider for this service
57
- * @returns FormBuilderDataSourceProvider instance
58
- */ getDataSourceProvider() {
53
+ getDataSourceProvider() {
59
54
  return this.dataSourceProvider;
60
55
  }
61
56
  // Entity Conversion
@@ -94,7 +89,7 @@ let FormService = class FormService extends _classes.RequestScopedApiService {
94
89
  form.companyId = dto.companyId;
95
90
  }
96
91
  // If companyId is not in form at all, set from user
97
- if (!('companyId' in form) || form.companyId === undefined) {
92
+ if (form.companyId === undefined) {
98
93
  form.companyId = user?.companyId ?? null;
99
94
  }
100
95
  } else {
@@ -132,22 +127,18 @@ let FormService = class FormService extends _classes.RequestScopedApiService {
132
127
  isRaw: false
133
128
  };
134
129
  }
135
- /**
136
- * Override: Extra query manipulation - Auto-filter by user's company
137
- */ async getExtraManipulateQuery(query, filterDto, user) {
130
+ async getExtraManipulateQuery(query, filterDto, user) {
138
131
  const result = await super.getExtraManipulateQuery(query, filterDto, user);
139
- // If company feature enabled and user has companyId, filter by user's company
140
- const enableCompanyFeature = this.formBuilderConfig.isCompanyFeatureEnabled();
141
- if (enableCompanyFeature && user?.companyId) {
142
- query.andWhere('form.companyId = :companyId', {
143
- companyId: user.companyId
144
- });
145
- }
132
+ // Apply company filter using shared utility
133
+ (0, _utils.applyCompanyFilter)(query, {
134
+ isCompanyFeatureEnabled: this.formBuilderConfig.isCompanyFeatureEnabled(),
135
+ entityAlias: 'form'
136
+ }, user);
146
137
  return result;
147
138
  }
148
- /**
149
- * Override: Convert entity to response DTO
150
- */ convertEntityToResponseDto(entity, _isRaw) {
139
+ convertEntityToResponseDto(entity, _isRaw) {
140
+ // Type guard for company-enabled entity
141
+ const entityWithCompany = entity;
151
142
  return {
152
143
  id: entity.id,
153
144
  name: entity.name,
@@ -158,7 +149,7 @@ let FormService = class FormService extends _classes.RequestScopedApiService {
158
149
  accessType: entity.accessType,
159
150
  actionGroups: entity.actionGroups,
160
151
  isActive: entity.isActive,
161
- companyId: ('companyId' in entity ? entity.companyId : null) ?? null,
152
+ companyId: entityWithCompany.companyId ?? null,
162
153
  metadata: entity.metadata,
163
154
  createdAt: entity.createdAt,
164
155
  updatedAt: entity.updatedAt,
@@ -168,33 +159,37 @@ let FormService = class FormService extends _classes.RequestScopedApiService {
168
159
  deletedById: entity.deletedById
169
160
  };
170
161
  }
171
- // Public Form Access
172
- /**
173
- * Get form for public submission (no auth)
174
- */ async getPublicForm(formId) {
162
+ toPublicForm(form) {
163
+ return {
164
+ id: form.id,
165
+ name: form.name,
166
+ description: form.description,
167
+ schema: form.schema,
168
+ schemaVersion: form.schemaVersion
169
+ };
170
+ }
171
+ async findPublicActiveForm(where) {
175
172
  await this.ensureRepositoryInitialized();
176
- const form = await this.repository.findOne({
173
+ return this.repository.findOne({
177
174
  where: {
178
- id: formId,
175
+ ...where,
179
176
  accessType: _formaccesstypeenum.FormAccessType.PUBLIC,
180
177
  isActive: true,
181
178
  deletedAt: (0, _typeorm.IsNull)()
182
179
  }
183
180
  });
181
+ }
182
+ // Public Form Access
183
+ async getPublicForm(formId) {
184
+ const form = await this.findPublicActiveForm({
185
+ id: formId
186
+ });
184
187
  if (!form) {
185
188
  throw new _common.NotFoundException('Form not found or not available for public access');
186
189
  }
187
- return {
188
- id: form.id,
189
- name: form.name,
190
- description: form.description,
191
- schema: form.schema,
192
- schemaVersion: form.schemaVersion
193
- };
190
+ return this.toPublicForm(form);
194
191
  }
195
- /**
196
- * Get form for submission with access validation
197
- */ async getFormForSubmission(formId, user) {
192
+ async getFormForSubmission(formId, user) {
198
193
  await this.ensureRepositoryInitialized();
199
194
  const form = await this.repository.findOne({
200
195
  where: {
@@ -207,27 +202,19 @@ let FormService = class FormService extends _classes.RequestScopedApiService {
207
202
  throw new _common.NotFoundException('Form not found or inactive');
208
203
  }
209
204
  // Access validation based on accessType
210
- switch(form.accessType){
211
- case _formaccesstypeenum.FormAccessType.PUBLIC:
212
- return form; // Anyone can access
213
- case _formaccesstypeenum.FormAccessType.AUTHENTICATED:
214
- if (!user) {
215
- throw new _common.UnauthorizedException('Authentication required to submit this form');
216
- }
217
- return form;
218
- case _formaccesstypeenum.FormAccessType.ACTION_GROUP:
219
- if (!user) {
220
- throw new _common.UnauthorizedException('Authentication required to submit this form');
221
- }
222
- // Permission check is handled by the controller/guard
223
- return form;
224
- default:
225
- throw new _common.BadRequestException('Invalid access type');
205
+ if (form.accessType === _formaccesstypeenum.FormAccessType.PUBLIC) {
206
+ return form; // Anyone can access
207
+ }
208
+ // All non-public forms require authentication
209
+ if (!user) {
210
+ throw new _common.UnauthorizedException('Authentication required to submit this form');
211
+ }
212
+ if (form.accessType === _formaccesstypeenum.FormAccessType.AUTHENTICATED || form.accessType === _formaccesstypeenum.FormAccessType.ACTION_GROUP) {
213
+ return form; // Permission check for ACTION_GROUP is handled by the controller/guard
226
214
  }
215
+ throw new _common.BadRequestException('Invalid access type');
227
216
  }
228
- /**
229
- * Get form by slug
230
- */ async getBySlug(slug) {
217
+ async getBySlug(slug) {
231
218
  await this.ensureRepositoryInitialized();
232
219
  const form = await this.repository.findOne({
233
220
  where: {
@@ -238,9 +225,15 @@ let FormService = class FormService extends _classes.RequestScopedApiService {
238
225
  return form ? this.convertEntityToResponseDto(form, false) : null;
239
226
  }
240
227
  /**
241
- * Get form access info (public endpoint)
242
- * Returns basic form info including access requirements
243
- */ async getFormAccessInfo(formId) {
228
+ * Get public form by slug (no authentication required)
229
+ * Returns null if form doesn't exist, is not public, or is inactive
230
+ */ async getPublicFormBySlug(slug) {
231
+ const form = await this.findPublicActiveForm({
232
+ slug
233
+ });
234
+ return form ? this.toPublicForm(form) : null;
235
+ }
236
+ async getFormAccessInfo(formId) {
244
237
  await this.ensureRepositoryInitialized();
245
238
  const form = await this.repository.findOne({
246
239
  where: {
@@ -268,10 +261,7 @@ let FormService = class FormService extends _classes.RequestScopedApiService {
268
261
  isActive: form.isActive
269
262
  };
270
263
  }
271
- /**
272
- * Get form for authenticated submission
273
- * Returns full form for users who are logged in
274
- */ async getAuthenticatedForm(formId, user) {
264
+ async getAuthenticatedForm(formId, user) {
275
265
  const form = await this.getFormForSubmission(formId, user);
276
266
  // For action_group access, check permissions from cache
277
267
  if (form.accessType === _formaccesstypeenum.FormAccessType.ACTION_GROUP && form.actionGroups?.length) {
@@ -280,13 +270,7 @@ let FormService = class FormService extends _classes.RequestScopedApiService {
280
270
  throw new _common.ForbiddenException('You do not have permission to access this form');
281
271
  }
282
272
  }
283
- return {
284
- id: form.id,
285
- name: form.name,
286
- description: form.description,
287
- schema: form.schema,
288
- schemaVersion: form.schemaVersion
289
- };
273
+ return this.toPublicForm(form);
290
274
  }
291
275
  constructor(cacheManager, utilsService, formBuilderConfig, dataSourceProvider){
292
276
  super('form', null, cacheManager, utilsService, FormService.name, true), _define_property(this, "cacheManager", void 0), _define_property(this, "utilsService", void 0), _define_property(this, "formBuilderConfig", void 0), _define_property(this, "dataSourceProvider", void 0), this.cacheManager = cacheManager, this.utilsService = utilsService, this.formBuilderConfig = formBuilderConfig, this.dataSourceProvider = dataSourceProvider;
@@ -23,16 +23,22 @@ Object.defineProperty(exports, "calculateComputedFields", {
23
23
  }
24
24
  });
25
25
  // ============================================================================
26
- // Type Guards
26
+ // Type Guards & Helpers
27
27
  // ============================================================================
28
+ function isObject(value) {
29
+ return typeof value === 'object' && value !== null;
30
+ }
28
31
  function isDirectValueConfig(config) {
29
- return typeof config === 'object' && config !== null && config.type === 'direct' && 'value' in config;
32
+ return isObject(config) && config.type === 'direct' && 'value' in config;
30
33
  }
31
34
  function isFieldReferenceConfig(config) {
32
- return typeof config === 'object' && config !== null && config.type === 'field_reference' && 'fieldId' in config;
35
+ return isObject(config) && config.type === 'field_reference' && 'fieldId' in config;
33
36
  }
34
37
  function isArithmeticConfig(config) {
35
- return typeof config === 'object' && config !== null && config.type === 'arithmetic' && 'operation' in config && 'operands' in config && Array.isArray(config.operands);
38
+ return isObject(config) && config.type === 'arithmetic' && 'operation' in config && 'operands' in config && Array.isArray(config.operands);
39
+ }
40
+ function isEmptyValue(value) {
41
+ return value === null || value === undefined || value === '' || Array.isArray(value) && value.length === 0;
36
42
  }
37
43
  /**
38
44
  * Normalize operator to uppercase string (handles both enum and string values)
@@ -95,9 +101,9 @@ function calculateComputedFields(formData, computedFields) {
95
101
  case 'not_equals':
96
102
  return fieldValue !== compareValue && String(fieldValue) !== String(compareValue);
97
103
  case 'is_empty':
98
- return fieldValue === null || fieldValue === undefined || fieldValue === '' || Array.isArray(fieldValue) && fieldValue.length === 0;
104
+ return isEmptyValue(fieldValue);
99
105
  case 'is_not_empty':
100
- return fieldValue !== null && fieldValue !== undefined && fieldValue !== '' && !(Array.isArray(fieldValue) && fieldValue.length === 0);
106
+ return !isEmptyValue(fieldValue);
101
107
  case 'contains':
102
108
  return String(fieldValue).includes(String(compareValue));
103
109
  case 'not_contains':
@@ -123,25 +129,11 @@ function calculateComputedFields(formData, computedFields) {
123
129
  case 'is_not_checked':
124
130
  return fieldValue === false || fieldValue === 'false' || fieldValue === 0 || !fieldValue;
125
131
  case 'is_any_of':
126
- if (Array.isArray(compareValue)) {
127
- return compareValue.includes(fieldValue);
128
- }
129
- return false;
130
- case 'is_none_of':
131
- if (Array.isArray(compareValue)) {
132
- return !compareValue.includes(fieldValue);
133
- }
134
- return true;
135
132
  case 'in':
136
- if (Array.isArray(compareValue)) {
137
- return compareValue.includes(fieldValue);
138
- }
139
- return false;
133
+ return Array.isArray(compareValue) && compareValue.includes(fieldValue);
134
+ case 'is_none_of':
140
135
  case 'not_in':
141
- if (Array.isArray(compareValue)) {
142
- return !compareValue.includes(fieldValue);
143
- }
144
- return true;
136
+ return !Array.isArray(compareValue) || !compareValue.includes(fieldValue);
145
137
  default:
146
138
  return false;
147
139
  }
@@ -183,8 +175,10 @@ function calculateComputedFields(formData, computedFields) {
183
175
  }
184
176
  switch(config.operation){
185
177
  case 'sum':
178
+ case 'increment':
186
179
  return values.reduce((acc, val)=>acc + val, 0);
187
180
  case 'subtract':
181
+ case 'decrement':
188
182
  return values.reduce((acc, val, idx)=>idx === 0 ? val : acc - val, 0);
189
183
  case 'multiply':
190
184
  return values.reduce((acc, val)=>acc * val, 1);
@@ -199,12 +193,6 @@ function calculateComputedFields(formData, computedFields) {
199
193
  return Math.min(...values);
200
194
  case 'max':
201
195
  return Math.max(...values);
202
- case 'increment':
203
- // First value is the base, rest are increments
204
- return values.reduce((acc, val)=>acc + val, 0);
205
- case 'decrement':
206
- // First value is the base, rest are decrements
207
- return values.reduce((acc, val, idx)=>idx === 0 ? val : acc - val, 0);
208
196
  default:
209
197
  return null;
210
198
  }
@@ -2,26 +2,18 @@
2
2
  Object.defineProperty(exports, "__esModule", {
3
3
  value: true
4
4
  });
5
- function _export(target, all) {
6
- for(var name in all)Object.defineProperty(target, name, {
7
- enumerable: true,
8
- get: Object.getOwnPropertyDescriptor(all, name).get
9
- });
10
- }
11
- _export(exports, {
12
- get buildPermissionCacheKey () {
13
- return buildPermissionCacheKey;
14
- },
15
- get getUserPermissionsFromCache () {
16
- return getUserPermissionsFromCache;
17
- },
18
- get validateUserPermissions () {
5
+ Object.defineProperty(exports, "validateUserPermissions", {
6
+ enumerable: true,
7
+ get: function() {
19
8
  return validateUserPermissions;
20
9
  }
21
10
  });
22
11
  const _common = require("@nestjs/common");
23
12
  const CACHE_PREFIX = 'permissions';
24
- function buildPermissionCacheKey(user, enableCompanyFeature) {
13
+ /**
14
+ * Build permission cache key for a user
15
+ * Uses same cache key format as PermissionGuard in nestjs-shared
16
+ */ function buildPermissionCacheKey(user, enableCompanyFeature) {
25
17
  if (enableCompanyFeature && user.companyId) {
26
18
  // Company-based permissions
27
19
  return `${CACHE_PREFIX}:company:${user.companyId}:branch:${user.branchId || 'null'}:user:${user.id}`;
@@ -29,7 +21,10 @@ function buildPermissionCacheKey(user, enableCompanyFeature) {
29
21
  // User-based permissions
30
22
  return `${CACHE_PREFIX}:user:${user.id}`;
31
23
  }
32
- async function getUserPermissionsFromCache(user, cacheManager, enableCompanyFeature, logger) {
24
+ /**
25
+ * Get user permissions from cache
26
+ * Fail-closed: if cache fails, deny access rather than allowing potentially unauthorized access
27
+ */ async function getUserPermissionsFromCache(user, cacheManager, enableCompanyFeature, logger) {
33
28
  const cacheKey = buildPermissionCacheKey(user, enableCompanyFeature);
34
29
  try {
35
30
  const permissions = await cacheManager.get(cacheKey);
@@ -1,15 +1,16 @@
1
+ import { ListResponseDto, SingleResponseDto } from '@flusys/nestjs-shared/dtos';
1
2
  import { ILoggedUserInfo } from '@flusys/nestjs-shared/interfaces';
2
3
  import { CreateFormResultDto, FormResultResponseDto, GetMyDraftDto, GetResultsByFormDto, SubmitFormDto, UpdateDraftDto, UpdateFormResultDto } from '../dtos';
3
4
  import { FormResultService } from '../services/form-result.service';
4
5
  declare const FormResultController_base: abstract new (service: FormResultService) => {
5
6
  service: FormResultService;
6
- insert(addDto: CreateFormResultDto, user: ILoggedUserInfo | null): Promise<import("@flusys/nestjs-shared").SingleResponseDto<FormResultResponseDto>>;
7
- insertMany(addDto: CreateFormResultDto[], user: ILoggedUserInfo | null): Promise<import("@flusys/nestjs-shared").BulkResponseDto<FormResultResponseDto>>;
8
- getById(id: string, body: import("@flusys/nestjs-shared").GetByIdBodyDto, user: ILoggedUserInfo | null): Promise<import("@flusys/nestjs-shared").SingleResponseDto<FormResultResponseDto>>;
9
- update(updateDto: UpdateFormResultDto, user: ILoggedUserInfo | null): Promise<import("@flusys/nestjs-shared").SingleResponseDto<FormResultResponseDto>>;
10
- updateMany(updateDtos: UpdateFormResultDto[], user: ILoggedUserInfo | null): Promise<import("@flusys/nestjs-shared").BulkResponseDto<FormResultResponseDto>>;
11
- getAll(filterAndPaginationDto: import("@flusys/nestjs-shared").FilterAndPaginationDto, user: ILoggedUserInfo | null, search?: string): Promise<import("@flusys/nestjs-shared").ListResponseDto<FormResultResponseDto>>;
12
- delete(deleteDto: import("@flusys/nestjs-shared").DeleteDto, user: ILoggedUserInfo | null): Promise<import("@flusys/nestjs-shared").MessageResponseDto>;
7
+ insert(addDto: CreateFormResultDto, user: ILoggedUserInfo | null): Promise<SingleResponseDto<FormResultResponseDto>>;
8
+ insertMany(addDto: CreateFormResultDto[], user: ILoggedUserInfo | null): Promise<import("@flusys/nestjs-shared/dtos").BulkResponseDto<FormResultResponseDto>>;
9
+ getById(id: string, body: import("@flusys/nestjs-shared/dtos").GetByIdBodyDto, user: ILoggedUserInfo | null): Promise<SingleResponseDto<FormResultResponseDto>>;
10
+ update(updateDto: UpdateFormResultDto, user: ILoggedUserInfo | null): Promise<SingleResponseDto<FormResultResponseDto>>;
11
+ updateMany(updateDtos: UpdateFormResultDto[], user: ILoggedUserInfo | null): Promise<import("@flusys/nestjs-shared/dtos").BulkResponseDto<FormResultResponseDto>>;
12
+ getAll(filterAndPaginationDto: import("@flusys/nestjs-shared/dtos").FilterAndPaginationDto, user: ILoggedUserInfo | null, search?: string): Promise<ListResponseDto<FormResultResponseDto>>;
13
+ delete(deleteDto: import("@flusys/nestjs-shared/dtos").DeleteDto, user: ILoggedUserInfo | null): Promise<import("@flusys/nestjs-shared/dtos").MessageResponseDto>;
13
14
  };
14
15
  export declare class FormResultController extends FormResultController_base {
15
16
  formResultService: FormResultService;
@@ -18,10 +19,7 @@ export declare class FormResultController extends FormResultController_base {
18
19
  submitPublicForm(dto: SubmitFormDto): Promise<FormResultResponseDto>;
19
20
  getMyDraft(dto: GetMyDraftDto, user: ILoggedUserInfo): Promise<FormResultResponseDto | null>;
20
21
  updateDraft(dto: UpdateDraftDto, user: ILoggedUserInfo): Promise<FormResultResponseDto>;
21
- getByFormId(dto: GetResultsByFormDto, user: ILoggedUserInfo): Promise<{
22
- data: FormResultResponseDto[];
23
- total: number;
24
- }>;
25
- hasUserSubmitted(dto: GetMyDraftDto, user: ILoggedUserInfo): Promise<boolean>;
22
+ getByFormId(dto: GetResultsByFormDto, user: ILoggedUserInfo): Promise<ListResponseDto<FormResultResponseDto>>;
23
+ hasUserSubmitted(dto: GetMyDraftDto, user: ILoggedUserInfo): Promise<SingleResponseDto<boolean>>;
26
24
  }
27
25
  export {};
@@ -1,5 +1,5 @@
1
+ import { IdentityResponseDto } from '@flusys/nestjs-shared/dtos';
1
2
  export declare class SubmitFormDto {
2
- [key: string]: unknown;
3
3
  formId: string;
4
4
  data: Record<string, unknown>;
5
5
  isDraft?: boolean;
@@ -12,31 +12,20 @@ export declare class CreateFormResultDto extends SubmitFormDto {
12
12
  }
13
13
  declare const UpdateFormResultDto_base: import("@nestjs/common").Type<Partial<CreateFormResultDto>>;
14
14
  export declare class UpdateFormResultDto extends UpdateFormResultDto_base {
15
- [key: string]: unknown;
16
15
  id: string;
17
16
  }
18
- export declare class FormResultQueryDto {
19
- [key: string]: unknown;
20
- formId?: string;
21
- isDraft?: boolean;
22
- submittedById?: string;
23
- }
24
17
  export declare class GetMyDraftDto {
25
- [key: string]: unknown;
26
18
  formId: string;
27
19
  }
28
20
  export declare class UpdateDraftDto extends SubmitFormDto {
29
21
  draftId: string;
30
22
  }
31
23
  export declare class GetResultsByFormDto {
32
- [key: string]: unknown;
33
24
  formId: string;
34
25
  page?: number;
35
26
  pageSize?: number;
36
27
  }
37
- export declare class FormResultResponseDto {
38
- [key: string]: unknown;
39
- id: string;
28
+ export declare class FormResultResponseDto extends IdentityResponseDto {
40
29
  formId: string;
41
30
  schemaVersionSnapshot: Record<string, unknown>;
42
31
  schemaVersion: number;
@@ -45,11 +34,5 @@ export declare class FormResultResponseDto {
45
34
  submittedAt: Date;
46
35
  isDraft: boolean;
47
36
  metadata: Record<string, unknown> | null;
48
- createdAt: Date;
49
- updatedAt: Date;
50
- deletedAt: Date | null;
51
- createdById: string | null;
52
- updatedById: string | null;
53
- deletedById: string | null;
54
37
  }
55
38
  export {};
@@ -1,6 +1,6 @@
1
1
  import { FormAccessType } from '../enums/form-access-type.enum';
2
+ import { IdentityResponseDto } from '@flusys/nestjs-shared/dtos';
2
3
  export declare class CreateFormDto {
3
- [key: string]: unknown;
4
4
  name: string;
5
5
  description?: string;
6
6
  slug?: string;
@@ -13,19 +13,10 @@ export declare class CreateFormDto {
13
13
  }
14
14
  declare const UpdateFormDto_base: import("@nestjs/common").Type<Partial<CreateFormDto>>;
15
15
  export declare class UpdateFormDto extends UpdateFormDto_base {
16
- [key: string]: unknown;
17
16
  id: string;
18
17
  schemaVersion?: number;
19
18
  }
20
- export declare class FormQueryDto {
21
- [key: string]: unknown;
22
- companyId?: string;
23
- isActive?: boolean;
24
- accessType?: FormAccessType;
25
- }
26
- export declare class FormResponseDto {
27
- [key: string]: unknown;
28
- id: string;
19
+ export declare class FormResponseDto extends IdentityResponseDto {
29
20
  name: string;
30
21
  description: string | null;
31
22
  slug: string | null;
@@ -36,28 +27,11 @@ export declare class FormResponseDto {
36
27
  companyId: string | null;
37
28
  isActive: boolean;
38
29
  metadata: Record<string, unknown> | null;
39
- createdAt: Date;
40
- updatedAt: Date;
41
- deletedAt: Date | null;
42
- createdById: string | null;
43
- updatedById: string | null;
44
- deletedById: string | null;
45
30
  }
46
- export declare class PublicFormResponseDto {
47
- [key: string]: unknown;
48
- id: string;
49
- name: string;
50
- description: string | null;
51
- schema: Record<string, unknown>;
52
- schemaVersion: number;
31
+ declare const PublicFormResponseDto_base: import("@nestjs/common").Type<Pick<FormResponseDto, "description" | "name" | "schema" | "id" | "schemaVersion">>;
32
+ export declare class PublicFormResponseDto extends PublicFormResponseDto_base {
53
33
  }
54
- export declare class FormAccessInfoResponseDto {
55
- [key: string]: unknown;
56
- id: string;
57
- name: string;
58
- description: string | null;
59
- accessType: FormAccessType;
60
- actionGroups: string[] | null;
61
- isActive: boolean;
34
+ declare const FormAccessInfoResponseDto_base: import("@nestjs/common").Type<Pick<FormResponseDto, "description" | "name" | "accessType" | "actionGroups" | "isActive" | "id">>;
35
+ export declare class FormAccessInfoResponseDto extends FormAccessInfoResponseDto_base {
62
36
  }
63
37
  export {};
@@ -1,4 +1,4 @@
1
- import { FormBase } from './form-base.entity';
2
- export declare class FormWithCompany extends FormBase {
1
+ import { Form } from './form.entity';
2
+ export declare class FormWithCompany extends Form {
3
3
  companyId: string | null;
4
4
  }
@@ -1,3 +1,13 @@
1
- import { FormBase } from './form-base.entity';
2
- export declare class Form extends FormBase {
1
+ import { Identity } from '@flusys/nestjs-shared/entities';
2
+ import { FormAccessType } from '../enums/form-access-type.enum';
3
+ export declare class Form extends Identity {
4
+ name: string;
5
+ description: string | null;
6
+ slug: string | null;
7
+ schema: Record<string, unknown>;
8
+ schemaVersion: number;
9
+ accessType: FormAccessType;
10
+ actionGroups: string[] | null;
11
+ isActive: boolean;
12
+ metadata: Record<string, unknown> | null;
3
13
  }
@@ -1,5 +1,10 @@
1
- export * from './form-base.entity';
2
1
  export * from './form.entity';
3
- export * from './form-with-company.entity';
4
2
  export * from './form-result.entity';
3
+ export * from './form-with-company.entity';
4
+ import { Form } from './form.entity';
5
+ import { FormResult } from './form-result.entity';
6
+ import { FormWithCompany } from './form-with-company.entity';
7
+ export declare const FormCoreEntities: (typeof Form | typeof FormResult)[];
8
+ export declare const FormCompanyEntities: (typeof FormResult | typeof FormWithCompany)[];
5
9
  export declare function getFormBuilderEntitiesByConfig(enableCompanyFeature: boolean): any[];
10
+ export { Form as FormBase } from './form.entity';
@@ -25,8 +25,8 @@ function _ts_param(paramIndex, decorator) {
25
25
  decorator(target, key, paramIndex);
26
26
  };
27
27
  }
28
- import { createApiController } from '@flusys/nestjs-shared/classes';
29
- import { CurrentUser, Public } from '@flusys/nestjs-shared/decorators';
28
+ import { createApiController, FORM_RESULT_PERMISSIONS } from '@flusys/nestjs-shared/classes';
29
+ import { CurrentUser, Public, RequirePermission } from '@flusys/nestjs-shared/decorators';
30
30
  import { JwtAuthGuard } from '@flusys/nestjs-shared/guards';
31
31
  import { ILoggedUserInfo } from '@flusys/nestjs-shared/interfaces';
32
32
  import { Body, Controller, HttpCode, HttpStatus, Inject, Post, UseGuards } from '@nestjs/common';
@@ -34,7 +34,50 @@ import { ApiBearerAuth, ApiOperation, ApiTags } from '@nestjs/swagger';
34
34
  import { CreateFormResultDto, FormResultResponseDto, GetMyDraftDto, GetResultsByFormDto, SubmitFormDto, UpdateDraftDto, UpdateFormResultDto } from '../dtos';
35
35
  import { FormResultService } from '../services/form-result.service';
36
36
  export class FormResultController extends createApiController(CreateFormResultDto, UpdateFormResultDto, FormResultResponseDto, {
37
- security: 'jwt'
37
+ security: {
38
+ insert: {
39
+ level: 'permission',
40
+ permissions: [
41
+ FORM_RESULT_PERMISSIONS.CREATE
42
+ ]
43
+ },
44
+ insertMany: {
45
+ level: 'permission',
46
+ permissions: [
47
+ FORM_RESULT_PERMISSIONS.CREATE
48
+ ]
49
+ },
50
+ getById: {
51
+ level: 'permission',
52
+ permissions: [
53
+ FORM_RESULT_PERMISSIONS.READ
54
+ ]
55
+ },
56
+ getAll: {
57
+ level: 'permission',
58
+ permissions: [
59
+ FORM_RESULT_PERMISSIONS.READ
60
+ ]
61
+ },
62
+ update: {
63
+ level: 'permission',
64
+ permissions: [
65
+ FORM_RESULT_PERMISSIONS.UPDATE
66
+ ]
67
+ },
68
+ updateMany: {
69
+ level: 'permission',
70
+ permissions: [
71
+ FORM_RESULT_PERMISSIONS.UPDATE
72
+ ]
73
+ },
74
+ delete: {
75
+ level: 'permission',
76
+ permissions: [
77
+ FORM_RESULT_PERMISSIONS.DELETE
78
+ ]
79
+ }
80
+ }
38
81
  }) {
39
82
  // Submit Endpoints
40
83
  /**
@@ -63,16 +106,34 @@ export class FormResultController extends createApiController(CreateFormResultDt
63
106
  /**
64
107
  * Get results by form ID with pagination
65
108
  */ async getByFormId(dto, user) {
66
- return this.formResultService.getByFormId(dto.formId, user, {
67
- page: dto.page ?? 0,
68
- pageSize: dto.pageSize ?? 10
109
+ const page = dto.page ?? 0;
110
+ const pageSize = dto.pageSize ?? 10;
111
+ const result = await this.formResultService.getByFormId(dto.formId, user, {
112
+ page,
113
+ pageSize
69
114
  });
115
+ return {
116
+ success: true,
117
+ message: 'Form results retrieved successfully',
118
+ data: result.data,
119
+ meta: {
120
+ total: result.total,
121
+ page,
122
+ pageSize,
123
+ count: result.data.length
124
+ }
125
+ };
70
126
  }
71
127
  /**
72
128
  * Check if current user has already submitted this form (non-draft)
73
129
  * Used for single response mode
74
130
  */ async hasUserSubmitted(dto, user) {
75
- return this.formResultService.hasUserSubmitted(dto.formId, user);
131
+ const hasSubmitted = await this.formResultService.hasUserSubmitted(dto.formId, user);
132
+ return {
133
+ success: true,
134
+ message: hasSubmitted ? 'User has submitted this form' : 'User has not submitted this form',
135
+ data: hasSubmitted
136
+ };
76
137
  }
77
138
  constructor(formResultService){
78
139
  super(formResultService), _define_property(this, "formResultService", void 0), this.formResultService = formResultService;
@@ -147,6 +208,7 @@ _ts_decorate([
147
208
  Post('by-form'),
148
209
  UseGuards(JwtAuthGuard),
149
210
  ApiBearerAuth(),
211
+ RequirePermission(FORM_RESULT_PERMISSIONS.READ),
150
212
  HttpCode(HttpStatus.OK),
151
213
  ApiOperation({
152
214
  summary: 'Get results by form ID'