@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.
- package/config/index.d.ts +3 -3
- package/controllers/form-result.controller.d.ts +3 -3
- package/controllers/form.controller.d.ts +3 -3
- package/controllers/index.d.ts +2 -2
- package/docs/form-builder-swagger.config.d.ts +2 -2
- package/docs/index.d.ts +1 -1
- package/dtos/form.dto.d.ts +1 -1
- package/dtos/index.d.ts +2 -2
- package/entities/form-with-company.entity.d.ts +1 -1
- package/entities/form.entity.d.ts +1 -1
- package/entities/index.d.ts +7 -7
- package/enums/index.d.ts +1 -1
- package/fesm/262.js +1841 -0
- package/fesm/98.js +807 -0
- package/fesm/config/index.js +98 -3
- package/fesm/controllers/index.js +14 -2
- package/fesm/docs/index.js +171 -1
- package/fesm/dtos/index.js +571 -2
- package/fesm/entities/index.js +342 -10
- package/fesm/enums/index.js +38 -1
- package/fesm/index.js +482 -10
- package/fesm/interfaces/index.js +17 -3
- package/fesm/modules/index.js +178 -1
- package/fesm/runtime.js +85 -0
- package/fesm/services/index.js +35 -4
- package/index.d.ts +10 -10
- package/interfaces/form-builder-module.interface.d.ts +3 -3
- package/interfaces/form-result.interface.d.ts +1 -1
- package/interfaces/form.interface.d.ts +2 -2
- package/interfaces/index.d.ts +3 -3
- package/modules/form-builder.module.d.ts +2 -2
- package/modules/index.d.ts +1 -1
- package/package.json +26 -36
- package/services/form-builder-config.service.d.ts +4 -4
- package/services/form-builder-datasource.provider.d.ts +3 -3
- package/services/form-result.service.d.ts +6 -6
- package/services/form.service.d.ts +7 -7
- package/services/index.d.ts +4 -4
- package/utils/index.d.ts +2 -2
- package/utils/permission.utils.d.ts +1 -1
- package/cjs/config/event-actions.js +0 -33
- package/cjs/config/form-builder.constants.js +0 -13
- package/cjs/config/index.js +0 -20
- package/cjs/config/message-keys.js +0 -38
- package/cjs/controllers/form-result.controller.js +0 -281
- package/cjs/controllers/form-result.controller.spec.js +0 -257
- package/cjs/controllers/form.controller.js +0 -231
- package/cjs/controllers/form.controller.spec.js +0 -212
- package/cjs/controllers/index.js +0 -19
- package/cjs/docs/form-builder-swagger.config.js +0 -150
- package/cjs/docs/form-builder-swagger.config.spec.js +0 -75
- package/cjs/docs/index.js +0 -11
- package/cjs/dtos/form-result.dto.js +0 -248
- package/cjs/dtos/form.dto.js +0 -270
- package/cjs/dtos/index.js +0 -19
- package/cjs/entities/form-result.entity.js +0 -100
- package/cjs/entities/form-with-company.entity.js +0 -65
- package/cjs/entities/form.entity.js +0 -127
- package/cjs/entities/index.js +0 -52
- package/cjs/entities/index.spec.js +0 -18
- package/cjs/enums/form-access-type.enum.js +0 -19
- package/cjs/enums/index.js +0 -18
- package/cjs/index.js +0 -28
- package/cjs/interfaces/form-builder-module.interface.js +0 -4
- package/cjs/interfaces/form-result.interface.js +0 -4
- package/cjs/interfaces/form.interface.js +0 -4
- package/cjs/interfaces/index.js +0 -20
- package/cjs/modules/form-builder.module.js +0 -136
- package/cjs/modules/form-builder.module.spec.js +0 -133
- package/cjs/modules/index.js +0 -18
- package/cjs/services/form-builder-config.service.js +0 -69
- package/cjs/services/form-builder-config.service.spec.js +0 -121
- package/cjs/services/form-builder-datasource.provider.js +0 -125
- package/cjs/services/form-builder-datasource.provider.spec.js +0 -147
- package/cjs/services/form-result.service.js +0 -366
- package/cjs/services/form-result.service.spec.js +0 -823
- package/cjs/services/form.service.js +0 -341
- package/cjs/services/form.service.spec.js +0 -746
- package/cjs/services/index.js +0 -21
- package/cjs/utils/computed-field.utils.js +0 -199
- package/cjs/utils/computed-field.utils.spec.js +0 -1205
- package/cjs/utils/index.js +0 -19
- package/cjs/utils/permission.utils.js +0 -44
- package/cjs/utils/permission.utils.spec.js +0 -118
- package/fesm/config/event-actions.js +0 -12
- package/fesm/config/form-builder.constants.js +0 -3
- package/fesm/config/message-keys.js +0 -20
- package/fesm/controllers/form-result.controller.js +0 -271
- package/fesm/controllers/form-result.controller.spec.js +0 -253
- package/fesm/controllers/form.controller.js +0 -221
- package/fesm/controllers/form.controller.spec.js +0 -208
- package/fesm/docs/form-builder-swagger.config.js +0 -146
- package/fesm/docs/form-builder-swagger.config.spec.js +0 -71
- package/fesm/dtos/form-result.dto.js +0 -215
- package/fesm/dtos/form.dto.js +0 -243
- package/fesm/entities/form-result.entity.js +0 -90
- package/fesm/entities/form-with-company.entity.js +0 -55
- package/fesm/entities/form.entity.js +0 -117
- package/fesm/entities/index.spec.js +0 -14
- package/fesm/enums/form-access-type.enum.js +0 -9
- package/fesm/interfaces/form-builder-module.interface.js +0 -3
- package/fesm/interfaces/form-result.interface.js +0 -6
- package/fesm/interfaces/form.interface.js +0 -3
- package/fesm/modules/form-builder.module.js +0 -126
- package/fesm/modules/form-builder.module.spec.js +0 -129
- package/fesm/services/form-builder-config.service.js +0 -59
- package/fesm/services/form-builder-config.service.spec.js +0 -117
- package/fesm/services/form-builder-datasource.provider.js +0 -74
- package/fesm/services/form-builder-datasource.provider.spec.js +0 -143
- package/fesm/services/form-result.service.js +0 -356
- package/fesm/services/form-result.service.spec.js +0 -778
- package/fesm/services/form.service.js +0 -331
- package/fesm/services/form.service.spec.js +0 -701
- package/fesm/utils/computed-field.utils.js +0 -195
- package/fesm/utils/computed-field.utils.spec.js +0 -1201
- package/fesm/utils/index.js +0 -2
- package/fesm/utils/permission.utils.js +0 -42
- package/fesm/utils/permission.utils.spec.js +0 -114
|
@@ -1,231 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", {
|
|
3
|
-
value: true
|
|
4
|
-
});
|
|
5
|
-
Object.defineProperty(exports, "FormController", {
|
|
6
|
-
enumerable: true,
|
|
7
|
-
get: function() {
|
|
8
|
-
return FormController;
|
|
9
|
-
}
|
|
10
|
-
});
|
|
11
|
-
const _classes = require("@flusys/nestjs-shared/classes");
|
|
12
|
-
const _decorators = require("@flusys/nestjs-shared/decorators");
|
|
13
|
-
const _guards = require("@flusys/nestjs-shared/guards");
|
|
14
|
-
const _interfaces = require("@flusys/nestjs-shared/interfaces");
|
|
15
|
-
const _common = require("@nestjs/common");
|
|
16
|
-
const _swagger = require("@nestjs/swagger");
|
|
17
|
-
const _config = require("../config");
|
|
18
|
-
const _dtos = require("../dtos");
|
|
19
|
-
const _formservice = require("../services/form.service");
|
|
20
|
-
function _define_property(obj, key, value) {
|
|
21
|
-
if (key in obj) {
|
|
22
|
-
Object.defineProperty(obj, key, {
|
|
23
|
-
value: value,
|
|
24
|
-
enumerable: true,
|
|
25
|
-
configurable: true,
|
|
26
|
-
writable: true
|
|
27
|
-
});
|
|
28
|
-
} else {
|
|
29
|
-
obj[key] = value;
|
|
30
|
-
}
|
|
31
|
-
return obj;
|
|
32
|
-
}
|
|
33
|
-
function _ts_decorate(decorators, target, key, desc) {
|
|
34
|
-
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
35
|
-
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
36
|
-
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;
|
|
37
|
-
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
38
|
-
}
|
|
39
|
-
function _ts_metadata(k, v) {
|
|
40
|
-
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
41
|
-
}
|
|
42
|
-
function _ts_param(paramIndex, decorator) {
|
|
43
|
-
return function(target, key) {
|
|
44
|
-
decorator(target, key, paramIndex);
|
|
45
|
-
};
|
|
46
|
-
}
|
|
47
|
-
let FormController = class FormController extends (0, _classes.createApiController)(_dtos.CreateFormDto, _dtos.UpdateFormDto, _dtos.FormResponseDto, {
|
|
48
|
-
entityName: 'form',
|
|
49
|
-
security: {
|
|
50
|
-
insert: {
|
|
51
|
-
level: 'permission',
|
|
52
|
-
permissions: [
|
|
53
|
-
_classes.FORM_PERMISSIONS.CREATE
|
|
54
|
-
]
|
|
55
|
-
},
|
|
56
|
-
insertMany: {
|
|
57
|
-
level: 'permission',
|
|
58
|
-
permissions: [
|
|
59
|
-
_classes.FORM_PERMISSIONS.CREATE
|
|
60
|
-
]
|
|
61
|
-
},
|
|
62
|
-
getById: {
|
|
63
|
-
level: 'permission',
|
|
64
|
-
permissions: [
|
|
65
|
-
_classes.FORM_PERMISSIONS.READ
|
|
66
|
-
]
|
|
67
|
-
},
|
|
68
|
-
getAll: {
|
|
69
|
-
level: 'permission',
|
|
70
|
-
permissions: [
|
|
71
|
-
_classes.FORM_PERMISSIONS.READ
|
|
72
|
-
]
|
|
73
|
-
},
|
|
74
|
-
update: {
|
|
75
|
-
level: 'permission',
|
|
76
|
-
permissions: [
|
|
77
|
-
_classes.FORM_PERMISSIONS.UPDATE
|
|
78
|
-
]
|
|
79
|
-
},
|
|
80
|
-
updateMany: {
|
|
81
|
-
level: 'permission',
|
|
82
|
-
permissions: [
|
|
83
|
-
_classes.FORM_PERMISSIONS.UPDATE
|
|
84
|
-
]
|
|
85
|
-
},
|
|
86
|
-
delete: {
|
|
87
|
-
level: 'permission',
|
|
88
|
-
permissions: [
|
|
89
|
-
_classes.FORM_PERMISSIONS.DELETE
|
|
90
|
-
]
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
}) {
|
|
94
|
-
// Public Endpoints
|
|
95
|
-
/**
|
|
96
|
-
* Get form access info (no authentication required)
|
|
97
|
-
*/ async getFormAccessInfo(id) {
|
|
98
|
-
const data = await this.formService.getFormAccessInfo(id);
|
|
99
|
-
return {
|
|
100
|
-
success: true,
|
|
101
|
-
message: 'Form access info retrieved',
|
|
102
|
-
messageKey: _config.FORM_MESSAGES.GET_ACCESS_INFO_SUCCESS,
|
|
103
|
-
data
|
|
104
|
-
};
|
|
105
|
-
}
|
|
106
|
-
async getPublicForm(id) {
|
|
107
|
-
const data = await this.formService.getPublicForm(id);
|
|
108
|
-
return {
|
|
109
|
-
success: true,
|
|
110
|
-
message: 'Form retrieved',
|
|
111
|
-
messageKey: _config.FORM_MESSAGES.GET_SUCCESS,
|
|
112
|
-
data
|
|
113
|
-
};
|
|
114
|
-
}
|
|
115
|
-
async getAuthenticatedForm(id, user) {
|
|
116
|
-
const data = await this.formService.getAuthenticatedForm(id, user);
|
|
117
|
-
return {
|
|
118
|
-
success: true,
|
|
119
|
-
message: 'Form retrieved',
|
|
120
|
-
messageKey: _config.FORM_MESSAGES.GET_SUCCESS,
|
|
121
|
-
data
|
|
122
|
-
};
|
|
123
|
-
}
|
|
124
|
-
async getBySlug(slug, _user) {
|
|
125
|
-
const data = await this.formService.getBySlug(slug);
|
|
126
|
-
return {
|
|
127
|
-
success: true,
|
|
128
|
-
message: 'Form retrieved',
|
|
129
|
-
messageKey: _config.FORM_MESSAGES.GET_SUCCESS,
|
|
130
|
-
data
|
|
131
|
-
};
|
|
132
|
-
}
|
|
133
|
-
async getPublicFormBySlug(slug) {
|
|
134
|
-
const data = await this.formService.getPublicFormBySlug(slug);
|
|
135
|
-
return {
|
|
136
|
-
success: true,
|
|
137
|
-
message: 'Form retrieved',
|
|
138
|
-
messageKey: _config.FORM_MESSAGES.GET_SUCCESS,
|
|
139
|
-
data
|
|
140
|
-
};
|
|
141
|
-
}
|
|
142
|
-
constructor(formService){
|
|
143
|
-
super(formService), _define_property(this, "formService", void 0), this.formService = formService;
|
|
144
|
-
}
|
|
145
|
-
};
|
|
146
|
-
_ts_decorate([
|
|
147
|
-
(0, _common.Post)('access-info/:id'),
|
|
148
|
-
(0, _decorators.Public)(),
|
|
149
|
-
(0, _common.HttpCode)(_common.HttpStatus.OK),
|
|
150
|
-
(0, _swagger.ApiOperation)({
|
|
151
|
-
summary: 'Get form access info (no auth required)'
|
|
152
|
-
}),
|
|
153
|
-
_ts_param(0, (0, _common.Param)('id')),
|
|
154
|
-
_ts_metadata("design:type", Function),
|
|
155
|
-
_ts_metadata("design:paramtypes", [
|
|
156
|
-
String
|
|
157
|
-
]),
|
|
158
|
-
_ts_metadata("design:returntype", Promise)
|
|
159
|
-
], FormController.prototype, "getFormAccessInfo", null);
|
|
160
|
-
_ts_decorate([
|
|
161
|
-
(0, _common.Post)('public/:id'),
|
|
162
|
-
(0, _decorators.Public)(),
|
|
163
|
-
(0, _common.HttpCode)(_common.HttpStatus.OK),
|
|
164
|
-
(0, _swagger.ApiOperation)({
|
|
165
|
-
summary: 'Get public form for submission (no auth required)'
|
|
166
|
-
}),
|
|
167
|
-
_ts_param(0, (0, _common.Param)('id')),
|
|
168
|
-
_ts_metadata("design:type", Function),
|
|
169
|
-
_ts_metadata("design:paramtypes", [
|
|
170
|
-
String
|
|
171
|
-
]),
|
|
172
|
-
_ts_metadata("design:returntype", Promise)
|
|
173
|
-
], FormController.prototype, "getPublicForm", null);
|
|
174
|
-
_ts_decorate([
|
|
175
|
-
(0, _common.Post)('authenticated/:id'),
|
|
176
|
-
(0, _common.UseGuards)(_guards.JwtAuthGuard),
|
|
177
|
-
(0, _swagger.ApiBearerAuth)(),
|
|
178
|
-
(0, _common.HttpCode)(_common.HttpStatus.OK),
|
|
179
|
-
(0, _swagger.ApiOperation)({
|
|
180
|
-
summary: 'Get form for authenticated submission'
|
|
181
|
-
}),
|
|
182
|
-
_ts_param(0, (0, _common.Param)('id')),
|
|
183
|
-
_ts_param(1, (0, _decorators.CurrentUser)()),
|
|
184
|
-
_ts_metadata("design:type", Function),
|
|
185
|
-
_ts_metadata("design:paramtypes", [
|
|
186
|
-
String,
|
|
187
|
-
typeof _interfaces.ILoggedUserInfo === "undefined" ? Object : _interfaces.ILoggedUserInfo
|
|
188
|
-
]),
|
|
189
|
-
_ts_metadata("design:returntype", Promise)
|
|
190
|
-
], FormController.prototype, "getAuthenticatedForm", null);
|
|
191
|
-
_ts_decorate([
|
|
192
|
-
(0, _common.Post)('by-slug/:slug'),
|
|
193
|
-
(0, _common.UseGuards)(_guards.JwtAuthGuard, _guards.PermissionGuard),
|
|
194
|
-
(0, _swagger.ApiBearerAuth)(),
|
|
195
|
-
(0, _decorators.RequirePermission)(_classes.FORM_PERMISSIONS.READ),
|
|
196
|
-
(0, _common.HttpCode)(_common.HttpStatus.OK),
|
|
197
|
-
(0, _swagger.ApiOperation)({
|
|
198
|
-
summary: 'Get form by slug'
|
|
199
|
-
}),
|
|
200
|
-
_ts_param(0, (0, _common.Param)('slug')),
|
|
201
|
-
_ts_param(1, (0, _decorators.CurrentUser)()),
|
|
202
|
-
_ts_metadata("design:type", Function),
|
|
203
|
-
_ts_metadata("design:paramtypes", [
|
|
204
|
-
String,
|
|
205
|
-
typeof _interfaces.ILoggedUserInfo === "undefined" ? Object : _interfaces.ILoggedUserInfo
|
|
206
|
-
]),
|
|
207
|
-
_ts_metadata("design:returntype", Promise)
|
|
208
|
-
], FormController.prototype, "getBySlug", null);
|
|
209
|
-
_ts_decorate([
|
|
210
|
-
(0, _common.Post)('public/by-slug/:slug'),
|
|
211
|
-
(0, _decorators.Public)(),
|
|
212
|
-
(0, _common.HttpCode)(_common.HttpStatus.OK),
|
|
213
|
-
(0, _swagger.ApiOperation)({
|
|
214
|
-
summary: 'Get public form by slug (no auth required)'
|
|
215
|
-
}),
|
|
216
|
-
_ts_param(0, (0, _common.Param)('slug')),
|
|
217
|
-
_ts_metadata("design:type", Function),
|
|
218
|
-
_ts_metadata("design:paramtypes", [
|
|
219
|
-
String
|
|
220
|
-
]),
|
|
221
|
-
_ts_metadata("design:returntype", Promise)
|
|
222
|
-
], FormController.prototype, "getPublicFormBySlug", null);
|
|
223
|
-
FormController = _ts_decorate([
|
|
224
|
-
(0, _swagger.ApiTags)('Form Builder - Forms'),
|
|
225
|
-
(0, _common.Controller)('form-builder/form'),
|
|
226
|
-
_ts_param(0, (0, _common.Inject)(_formservice.FormService)),
|
|
227
|
-
_ts_metadata("design:type", Function),
|
|
228
|
-
_ts_metadata("design:paramtypes", [
|
|
229
|
-
typeof _formservice.FormService === "undefined" ? Object : _formservice.FormService
|
|
230
|
-
])
|
|
231
|
-
], FormController);
|
|
@@ -1,212 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", {
|
|
3
|
-
value: true
|
|
4
|
-
});
|
|
5
|
-
const _testing = require("@nestjs/testing");
|
|
6
|
-
const _modules = require("@flusys/nestjs-shared/modules");
|
|
7
|
-
const _loggedusermock = require("@test-utils/mocks/logged-user.mock");
|
|
8
|
-
const _formaccesstypeenum = require("../enums/form-access-type.enum");
|
|
9
|
-
const _formcontroller = require("./form.controller");
|
|
10
|
-
const _formservice = require("../services/form.service");
|
|
11
|
-
describe('FormController', ()=>{
|
|
12
|
-
let controller;
|
|
13
|
-
let mockService;
|
|
14
|
-
beforeEach(async ()=>{
|
|
15
|
-
mockService = {
|
|
16
|
-
insert: jest.fn(),
|
|
17
|
-
insertMany: jest.fn(),
|
|
18
|
-
findById: jest.fn(),
|
|
19
|
-
findByIds: jest.fn(),
|
|
20
|
-
getAll: jest.fn(),
|
|
21
|
-
update: jest.fn(),
|
|
22
|
-
updateMany: jest.fn(),
|
|
23
|
-
delete: jest.fn(),
|
|
24
|
-
getFormAccessInfo: jest.fn(),
|
|
25
|
-
getPublicForm: jest.fn(),
|
|
26
|
-
getAuthenticatedForm: jest.fn(),
|
|
27
|
-
getBySlug: jest.fn(),
|
|
28
|
-
getPublicFormBySlug: jest.fn()
|
|
29
|
-
};
|
|
30
|
-
const module = await _testing.Test.createTestingModule({
|
|
31
|
-
controllers: [
|
|
32
|
-
_formcontroller.FormController
|
|
33
|
-
],
|
|
34
|
-
// UtilsService is a real (dependency-free) provider — required to satisfy the
|
|
35
|
-
// Slug interceptor applied by the inherited insert/update endpoints.
|
|
36
|
-
providers: [
|
|
37
|
-
{
|
|
38
|
-
provide: _formservice.FormService,
|
|
39
|
-
useValue: mockService
|
|
40
|
-
},
|
|
41
|
-
_modules.UtilsService
|
|
42
|
-
]
|
|
43
|
-
}).compile();
|
|
44
|
-
controller = module.get(_formcontroller.FormController);
|
|
45
|
-
});
|
|
46
|
-
afterEach(()=>{
|
|
47
|
-
jest.clearAllMocks();
|
|
48
|
-
});
|
|
49
|
-
describe('getFormAccessInfo', ()=>{
|
|
50
|
-
it('returns access info without requiring authentication', async ()=>{
|
|
51
|
-
mockService.getFormAccessInfo.mockResolvedValue({
|
|
52
|
-
id: 'form-1',
|
|
53
|
-
name: 'Survey',
|
|
54
|
-
description: null,
|
|
55
|
-
accessType: _formaccesstypeenum.FormAccessType.PUBLIC,
|
|
56
|
-
actionGroups: null,
|
|
57
|
-
isActive: true
|
|
58
|
-
});
|
|
59
|
-
const result = await controller.getFormAccessInfo('form-1');
|
|
60
|
-
expect(result).toEqual({
|
|
61
|
-
success: true,
|
|
62
|
-
message: 'Form access info retrieved',
|
|
63
|
-
messageKey: 'form.get.access.info.success',
|
|
64
|
-
data: expect.objectContaining({
|
|
65
|
-
id: 'form-1',
|
|
66
|
-
accessType: _formaccesstypeenum.FormAccessType.PUBLIC
|
|
67
|
-
})
|
|
68
|
-
});
|
|
69
|
-
expect(mockService.getFormAccessInfo).toHaveBeenCalledWith('form-1');
|
|
70
|
-
});
|
|
71
|
-
it('propagates NotFoundException raised by the service', async ()=>{
|
|
72
|
-
mockService.getFormAccessInfo.mockRejectedValue(Object.assign(new Error('not found'), {
|
|
73
|
-
messageKey: 'form.not.found'
|
|
74
|
-
}));
|
|
75
|
-
await expect(controller.getFormAccessInfo('missing')).rejects.toThrow();
|
|
76
|
-
});
|
|
77
|
-
});
|
|
78
|
-
describe('getPublicForm', ()=>{
|
|
79
|
-
it('returns the public form projection', async ()=>{
|
|
80
|
-
mockService.getPublicForm.mockResolvedValue({
|
|
81
|
-
id: 'form-1',
|
|
82
|
-
name: 'Survey',
|
|
83
|
-
description: null,
|
|
84
|
-
schema: {
|
|
85
|
-
sections: []
|
|
86
|
-
},
|
|
87
|
-
schemaVersion: 1
|
|
88
|
-
});
|
|
89
|
-
const result = await controller.getPublicForm('form-1');
|
|
90
|
-
expect(result.success).toBe(true);
|
|
91
|
-
expect(result.messageKey).toBe('form.get.success');
|
|
92
|
-
expect(result.data.id).toBe('form-1');
|
|
93
|
-
});
|
|
94
|
-
});
|
|
95
|
-
describe('getAuthenticatedForm', ()=>{
|
|
96
|
-
it('forwards the current user to the service and returns the form', async ()=>{
|
|
97
|
-
const user = (0, _loggedusermock.buildMockUser)();
|
|
98
|
-
mockService.getAuthenticatedForm.mockResolvedValue({
|
|
99
|
-
id: 'form-1',
|
|
100
|
-
name: 'Survey',
|
|
101
|
-
description: null,
|
|
102
|
-
schema: {},
|
|
103
|
-
schemaVersion: 1
|
|
104
|
-
});
|
|
105
|
-
const result = await controller.getAuthenticatedForm('form-1', user);
|
|
106
|
-
expect(mockService.getAuthenticatedForm).toHaveBeenCalledWith('form-1', user);
|
|
107
|
-
expect(result.data.id).toBe('form-1');
|
|
108
|
-
});
|
|
109
|
-
});
|
|
110
|
-
describe('getBySlug', ()=>{
|
|
111
|
-
it('returns the form when found by slug', async ()=>{
|
|
112
|
-
mockService.getBySlug.mockResolvedValue({
|
|
113
|
-
id: 'form-1',
|
|
114
|
-
name: 'Survey',
|
|
115
|
-
description: null,
|
|
116
|
-
slug: 'survey',
|
|
117
|
-
schema: {},
|
|
118
|
-
schemaVersion: 1,
|
|
119
|
-
accessType: _formaccesstypeenum.FormAccessType.AUTHENTICATED,
|
|
120
|
-
actionGroups: null,
|
|
121
|
-
tags: null,
|
|
122
|
-
companyId: null,
|
|
123
|
-
isActive: true,
|
|
124
|
-
createdAt: new Date(),
|
|
125
|
-
updatedAt: new Date(),
|
|
126
|
-
deletedAt: null,
|
|
127
|
-
createdById: null,
|
|
128
|
-
updatedById: null,
|
|
129
|
-
deletedById: null
|
|
130
|
-
});
|
|
131
|
-
const result = await controller.getBySlug('survey', (0, _loggedusermock.buildMockUser)());
|
|
132
|
-
expect(result.data?.slug).toBe('survey');
|
|
133
|
-
});
|
|
134
|
-
it('returns null data when no form matches the slug', async ()=>{
|
|
135
|
-
mockService.getBySlug.mockResolvedValue(null);
|
|
136
|
-
const result = await controller.getBySlug('missing', (0, _loggedusermock.buildMockUser)());
|
|
137
|
-
expect(result.data).toBeNull();
|
|
138
|
-
});
|
|
139
|
-
});
|
|
140
|
-
describe('getPublicFormBySlug', ()=>{
|
|
141
|
-
it('returns the public form projection when found', async ()=>{
|
|
142
|
-
mockService.getPublicFormBySlug.mockResolvedValue({
|
|
143
|
-
id: 'form-1',
|
|
144
|
-
name: 'Survey',
|
|
145
|
-
description: null,
|
|
146
|
-
schema: {},
|
|
147
|
-
schemaVersion: 1
|
|
148
|
-
});
|
|
149
|
-
const result = await controller.getPublicFormBySlug('survey');
|
|
150
|
-
expect(result.data?.id).toBe('form-1');
|
|
151
|
-
});
|
|
152
|
-
it('returns null data when no public form matches the slug', async ()=>{
|
|
153
|
-
mockService.getPublicFormBySlug.mockResolvedValue(null);
|
|
154
|
-
const result = await controller.getPublicFormBySlug('missing');
|
|
155
|
-
expect(result.data).toBeNull();
|
|
156
|
-
});
|
|
157
|
-
});
|
|
158
|
-
// ==========================================================================
|
|
159
|
-
// Inherited base CRUD wiring (createApiController)
|
|
160
|
-
// ==========================================================================
|
|
161
|
-
describe('inherited CRUD endpoints', ()=>{
|
|
162
|
-
it('insert delegates to FormService.insert and wraps the result', async ()=>{
|
|
163
|
-
mockService.insert.mockResolvedValue({
|
|
164
|
-
id: 'form-1',
|
|
165
|
-
name: 'Survey',
|
|
166
|
-
description: null,
|
|
167
|
-
slug: null,
|
|
168
|
-
schema: {},
|
|
169
|
-
schemaVersion: 1,
|
|
170
|
-
accessType: _formaccesstypeenum.FormAccessType.AUTHENTICATED,
|
|
171
|
-
actionGroups: null,
|
|
172
|
-
tags: null,
|
|
173
|
-
companyId: null,
|
|
174
|
-
isActive: true,
|
|
175
|
-
createdAt: new Date(),
|
|
176
|
-
updatedAt: new Date(),
|
|
177
|
-
deletedAt: null,
|
|
178
|
-
createdById: null,
|
|
179
|
-
updatedById: null,
|
|
180
|
-
deletedById: null
|
|
181
|
-
});
|
|
182
|
-
const user = (0, _loggedusermock.buildMockUser)();
|
|
183
|
-
const result = await controller.insert({
|
|
184
|
-
name: 'Survey',
|
|
185
|
-
schema: {}
|
|
186
|
-
}, user);
|
|
187
|
-
expect(mockService.insert).toHaveBeenCalledWith({
|
|
188
|
-
name: 'Survey',
|
|
189
|
-
schema: {}
|
|
190
|
-
}, user);
|
|
191
|
-
expect(result.success).toBe(true);
|
|
192
|
-
expect(result.data.name).toBe('Survey');
|
|
193
|
-
});
|
|
194
|
-
it('delete delegates to FormService.delete', async ()=>{
|
|
195
|
-
mockService.delete.mockResolvedValue(null);
|
|
196
|
-
const user = (0, _loggedusermock.buildMockUser)();
|
|
197
|
-
const result = await controller.delete({
|
|
198
|
-
id: [
|
|
199
|
-
'form-1'
|
|
200
|
-
],
|
|
201
|
-
type: 'delete'
|
|
202
|
-
}, user);
|
|
203
|
-
expect(mockService.delete).toHaveBeenCalledWith({
|
|
204
|
-
id: [
|
|
205
|
-
'form-1'
|
|
206
|
-
],
|
|
207
|
-
type: 'delete'
|
|
208
|
-
}, user);
|
|
209
|
-
expect(result.success).toBe(true);
|
|
210
|
-
});
|
|
211
|
-
});
|
|
212
|
-
});
|
package/cjs/controllers/index.js
DELETED
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", {
|
|
3
|
-
value: true
|
|
4
|
-
});
|
|
5
|
-
_export_star(require("./form.controller"), exports);
|
|
6
|
-
_export_star(require("./form-result.controller"), exports);
|
|
7
|
-
function _export_star(from, to) {
|
|
8
|
-
Object.keys(from).forEach(function(k) {
|
|
9
|
-
if (k !== "default" && !Object.prototype.hasOwnProperty.call(to, k)) {
|
|
10
|
-
Object.defineProperty(to, k, {
|
|
11
|
-
enumerable: true,
|
|
12
|
-
get: function() {
|
|
13
|
-
return from[k];
|
|
14
|
-
}
|
|
15
|
-
});
|
|
16
|
-
}
|
|
17
|
-
});
|
|
18
|
-
return from;
|
|
19
|
-
}
|
|
@@ -1,150 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", {
|
|
3
|
-
value: true
|
|
4
|
-
});
|
|
5
|
-
Object.defineProperty(exports, "formBuilderSwaggerConfig", {
|
|
6
|
-
enumerable: true,
|
|
7
|
-
get: function() {
|
|
8
|
-
return formBuilderSwaggerConfig;
|
|
9
|
-
}
|
|
10
|
-
});
|
|
11
|
-
/** Schema properties to exclude when company feature is disabled */ const COMPANY_SCHEMA_EXCLUSIONS = [
|
|
12
|
-
{
|
|
13
|
-
schemaName: 'CreateFormDto',
|
|
14
|
-
properties: [
|
|
15
|
-
'companyId'
|
|
16
|
-
]
|
|
17
|
-
},
|
|
18
|
-
{
|
|
19
|
-
schemaName: 'UpdateFormDto',
|
|
20
|
-
properties: [
|
|
21
|
-
'companyId'
|
|
22
|
-
]
|
|
23
|
-
},
|
|
24
|
-
{
|
|
25
|
-
schemaName: 'FormQueryDto',
|
|
26
|
-
properties: [
|
|
27
|
-
'companyId'
|
|
28
|
-
]
|
|
29
|
-
},
|
|
30
|
-
{
|
|
31
|
-
schemaName: 'FormResponseDto',
|
|
32
|
-
properties: [
|
|
33
|
-
'companyId'
|
|
34
|
-
]
|
|
35
|
-
}
|
|
36
|
-
];
|
|
37
|
-
function formBuilderSwaggerConfig(bootstrapConfig) {
|
|
38
|
-
const enableCompanyFeature = bootstrapConfig?.enableCompanyFeature ?? true;
|
|
39
|
-
const isMultiTenant = bootstrapConfig?.databaseMode === 'multi-tenant';
|
|
40
|
-
const multiTenantNote = isMultiTenant ? `\n> **Multi-Tenant Mode**: Include \`x-tenant-id\` header to target a specific tenant database.\n` : '';
|
|
41
|
-
return {
|
|
42
|
-
title: 'Form Builder API',
|
|
43
|
-
description: `
|
|
44
|
-
# Form Builder API
|
|
45
|
-
${multiTenantNote}
|
|
46
|
-
|
|
47
|
-
Dynamic form builder with schema versioning, conditional logic, and access control.
|
|
48
|
-
|
|
49
|
-
## Features
|
|
50
|
-
|
|
51
|
-
### 📋 Form Management
|
|
52
|
-
- Create and manage dynamic forms
|
|
53
|
-
- Schema versioning for form updates
|
|
54
|
-
- Slug-based URLs for sharing${enableCompanyFeature ? '\n- **Company isolation**' : ''}
|
|
55
|
-
|
|
56
|
-
### 🔒 Access Control
|
|
57
|
-
- **Public**: No authentication required
|
|
58
|
-
- **Authenticated**: JWT authentication required
|
|
59
|
-
- **Action Group**: Permission-based access via IAM
|
|
60
|
-
|
|
61
|
-
### 📊 Form Results
|
|
62
|
-
- Submit and track form responses
|
|
63
|
-
- Draft support for partial submissions
|
|
64
|
-
- Schema snapshot preservation${enableCompanyFeature ? '\n- **Company-level permissions**' : ''}
|
|
65
|
-
|
|
66
|
-
### 🔀 Conditional Logic
|
|
67
|
-
- Show/hide fields based on values
|
|
68
|
-
- Show/hide sections dynamically
|
|
69
|
-
- Jump to sections based on conditions
|
|
70
|
-
- Conditional required validation
|
|
71
|
-
${enableCompanyFeature ? `
|
|
72
|
-
## Multi-Tenant Support
|
|
73
|
-
|
|
74
|
-
Forms and results are automatically isolated by:
|
|
75
|
-
- **Company ID**: Company-level data isolation
|
|
76
|
-
|
|
77
|
-
All queries automatically filter by current user's company context.
|
|
78
|
-
` : ''}
|
|
79
|
-
## Form Access Types
|
|
80
|
-
|
|
81
|
-
### Public Forms
|
|
82
|
-
- No authentication required
|
|
83
|
-
- Anyone can view and submit
|
|
84
|
-
- Use \`/form-builder/form/public/:id\` to get form
|
|
85
|
-
- Use \`/form-builder/result/submit-public\` to submit
|
|
86
|
-
|
|
87
|
-
### Authenticated Forms
|
|
88
|
-
- JWT authentication required
|
|
89
|
-
- User must be logged in
|
|
90
|
-
- Use \`/form-builder/form/authenticated/:id\` to get form
|
|
91
|
-
- Use \`/form-builder/result/submit\` to submit
|
|
92
|
-
|
|
93
|
-
### Action Group Forms
|
|
94
|
-
- Permission-based access via IAM
|
|
95
|
-
- User must have specific permissions
|
|
96
|
-
- Use \`/form-builder/form/authenticated/:id\` to get form
|
|
97
|
-
- Use \`/form-builder/result/submit\` to submit
|
|
98
|
-
|
|
99
|
-
## Draft Support
|
|
100
|
-
|
|
101
|
-
Save form progress and complete later:
|
|
102
|
-
1. Submit with \`isDraft: true\` to save draft
|
|
103
|
-
2. Get draft with \`/form-builder/result/my-draft\`
|
|
104
|
-
3. Update draft with \`/form-builder/result/update-draft\`
|
|
105
|
-
4. Finalize by setting \`isDraft: false\`
|
|
106
|
-
|
|
107
|
-
## Response Format
|
|
108
|
-
|
|
109
|
-
All endpoints return standardized responses with success status, data, message, and timestamp.
|
|
110
|
-
|
|
111
|
-
## Error Handling
|
|
112
|
-
|
|
113
|
-
Errors return structured responses with success false, error message, error code, and timestamp.
|
|
114
|
-
|
|
115
|
-
## Common Error Codes
|
|
116
|
-
|
|
117
|
-
- **400 Bad Request**: Invalid input data
|
|
118
|
-
- **401 Unauthorized**: Missing or invalid authentication
|
|
119
|
-
- **403 Forbidden**: Insufficient permissions or wrong access type
|
|
120
|
-
- **404 Not Found**: Form or result not found
|
|
121
|
-
- **500 Internal Server Error**: Server error
|
|
122
|
-
|
|
123
|
-
## API Endpoints
|
|
124
|
-
|
|
125
|
-
All form builder endpoints are prefixed with \`/form-builder\`:
|
|
126
|
-
- \`/form-builder/form/*\` - Form management
|
|
127
|
-
- \`/form-builder/result/*\` - Form result/submission management
|
|
128
|
-
|
|
129
|
-
## Examples
|
|
130
|
-
|
|
131
|
-
### Get Form Access Info
|
|
132
|
-
|
|
133
|
-
POST /form-builder/form/access-info/:id
|
|
134
|
-
Returns access type and requirements (no auth required)
|
|
135
|
-
|
|
136
|
-
### Submit Public Form
|
|
137
|
-
|
|
138
|
-
POST /form-builder/result/submit-public with JSON body containing formId and formData
|
|
139
|
-
|
|
140
|
-
### Submit Authenticated Form
|
|
141
|
-
|
|
142
|
-
POST /form-builder/result/submit with JWT token and JSON body containing formId and formData
|
|
143
|
-
`,
|
|
144
|
-
version: '1.0',
|
|
145
|
-
path: 'api/docs/form-builder',
|
|
146
|
-
bearerAuth: true,
|
|
147
|
-
excludeTags: [],
|
|
148
|
-
excludeSchemaProperties: enableCompanyFeature ? undefined : COMPANY_SCHEMA_EXCLUSIONS
|
|
149
|
-
};
|
|
150
|
-
}
|
|
@@ -1,75 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", {
|
|
3
|
-
value: true
|
|
4
|
-
});
|
|
5
|
-
const _formbuilderswaggerconfig = require("./form-builder-swagger.config");
|
|
6
|
-
describe('formBuilderSwaggerConfig', ()=>{
|
|
7
|
-
it('should default to company feature enabled and single-database mode when no config is given', ()=>{
|
|
8
|
-
const config = (0, _formbuilderswaggerconfig.formBuilderSwaggerConfig)();
|
|
9
|
-
expect(config.title).toBe('Form Builder API');
|
|
10
|
-
expect(config.path).toBe('api/docs/form-builder');
|
|
11
|
-
expect(config.bearerAuth).toBe(true);
|
|
12
|
-
expect(config.excludeTags).toEqual([]);
|
|
13
|
-
expect(config.excludeSchemaProperties).toBeUndefined();
|
|
14
|
-
expect(config.description).not.toContain('Multi-Tenant Mode');
|
|
15
|
-
});
|
|
16
|
-
it('should exclude companyId schema properties when the company feature is disabled', ()=>{
|
|
17
|
-
const config = (0, _formbuilderswaggerconfig.formBuilderSwaggerConfig)({
|
|
18
|
-
enableCompanyFeature: false
|
|
19
|
-
});
|
|
20
|
-
expect(config.excludeSchemaProperties).toEqual([
|
|
21
|
-
{
|
|
22
|
-
schemaName: 'CreateFormDto',
|
|
23
|
-
properties: [
|
|
24
|
-
'companyId'
|
|
25
|
-
]
|
|
26
|
-
},
|
|
27
|
-
{
|
|
28
|
-
schemaName: 'UpdateFormDto',
|
|
29
|
-
properties: [
|
|
30
|
-
'companyId'
|
|
31
|
-
]
|
|
32
|
-
},
|
|
33
|
-
{
|
|
34
|
-
schemaName: 'FormQueryDto',
|
|
35
|
-
properties: [
|
|
36
|
-
'companyId'
|
|
37
|
-
]
|
|
38
|
-
},
|
|
39
|
-
{
|
|
40
|
-
schemaName: 'FormResponseDto',
|
|
41
|
-
properties: [
|
|
42
|
-
'companyId'
|
|
43
|
-
]
|
|
44
|
-
}
|
|
45
|
-
]);
|
|
46
|
-
});
|
|
47
|
-
it('should not exclude any schema properties when the company feature is enabled', ()=>{
|
|
48
|
-
const config = (0, _formbuilderswaggerconfig.formBuilderSwaggerConfig)({
|
|
49
|
-
enableCompanyFeature: true
|
|
50
|
-
});
|
|
51
|
-
expect(config.excludeSchemaProperties).toBeUndefined();
|
|
52
|
-
});
|
|
53
|
-
it('should describe company isolation and multi-tenant support only when the company feature is enabled', ()=>{
|
|
54
|
-
const withCompany = (0, _formbuilderswaggerconfig.formBuilderSwaggerConfig)({
|
|
55
|
-
enableCompanyFeature: true
|
|
56
|
-
});
|
|
57
|
-
const withoutCompany = (0, _formbuilderswaggerconfig.formBuilderSwaggerConfig)({
|
|
58
|
-
enableCompanyFeature: false
|
|
59
|
-
});
|
|
60
|
-
expect(withCompany.description).toContain('Company isolation');
|
|
61
|
-
expect(withCompany.description).toContain('## Multi-Tenant Support');
|
|
62
|
-
expect(withoutCompany.description).not.toContain('Company isolation');
|
|
63
|
-
expect(withoutCompany.description).not.toContain('## Multi-Tenant Support');
|
|
64
|
-
});
|
|
65
|
-
it('should mention multi-tenant mode in the description only for multi-tenant database mode', ()=>{
|
|
66
|
-
const multiTenant = (0, _formbuilderswaggerconfig.formBuilderSwaggerConfig)({
|
|
67
|
-
databaseMode: 'multi-tenant'
|
|
68
|
-
});
|
|
69
|
-
const single = (0, _formbuilderswaggerconfig.formBuilderSwaggerConfig)({
|
|
70
|
-
databaseMode: 'single'
|
|
71
|
-
});
|
|
72
|
-
expect(multiTenant.description).toContain('Multi-Tenant Mode');
|
|
73
|
-
expect(single.description).not.toContain('Multi-Tenant Mode');
|
|
74
|
-
});
|
|
75
|
-
});
|