@flusys/nestjs-form-builder 7.0.2 → 8.0.0-beta.1
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
package/fesm/utils/index.js
DELETED
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
import { FORM_MESSAGES } from '../config';
|
|
2
|
-
import { ForbiddenException } from '@nestjs/common';
|
|
3
|
-
const CACHE_PREFIX = 'permissions';
|
|
4
|
-
/**
|
|
5
|
-
* Build permission cache key for a user
|
|
6
|
-
* Uses same cache key format as PermissionGuard in nestjs-shared
|
|
7
|
-
*/ function buildPermissionCacheKey(user, enableCompanyFeature) {
|
|
8
|
-
if (enableCompanyFeature && user.companyId) {
|
|
9
|
-
return `${CACHE_PREFIX}:company:${user.companyId}:branch:${user.branchId || 'null'}:user:${user.id}`;
|
|
10
|
-
}
|
|
11
|
-
return `${CACHE_PREFIX}:user:${user.id}`;
|
|
12
|
-
}
|
|
13
|
-
/**
|
|
14
|
-
* Get user permissions from cache
|
|
15
|
-
* Fail-closed: if cache fails, deny access rather than allowing potentially unauthorized access
|
|
16
|
-
*/ async function getUserPermissionsFromCache(user, cacheManager, enableCompanyFeature) {
|
|
17
|
-
const cacheKey = buildPermissionCacheKey(user, enableCompanyFeature);
|
|
18
|
-
try {
|
|
19
|
-
const permissions = await cacheManager.get(cacheKey);
|
|
20
|
-
return permissions ?? [];
|
|
21
|
-
} catch {
|
|
22
|
-
throw new ForbiddenException({
|
|
23
|
-
message: 'Unable to verify permissions. Please try again.',
|
|
24
|
-
messageKey: FORM_MESSAGES.PERMISSION_CHECK_FAILED
|
|
25
|
-
});
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
/**
|
|
29
|
-
* Validate user has at least one of the required permissions
|
|
30
|
-
*
|
|
31
|
-
* @param user - The logged-in user
|
|
32
|
-
* @param requiredPermissions - Array of required permission strings (user needs at least one)
|
|
33
|
-
* @param cacheManager - Cache manager instance
|
|
34
|
-
* @param enableCompanyFeature - Whether company feature is enabled
|
|
35
|
-
* @returns true if user has permission, false otherwise
|
|
36
|
-
*/ export async function validateUserPermissions(user, requiredPermissions, cacheManager, enableCompanyFeature) {
|
|
37
|
-
if (!requiredPermissions.length) {
|
|
38
|
-
return true;
|
|
39
|
-
}
|
|
40
|
-
const userPermissions = await getUserPermissionsFromCache(user, cacheManager, enableCompanyFeature);
|
|
41
|
-
return requiredPermissions.some((perm)=>userPermissions.includes(perm));
|
|
42
|
-
}
|
|
@@ -1,114 +0,0 @@
|
|
|
1
|
-
import { ForbiddenException } from '@nestjs/common';
|
|
2
|
-
import { buildMockUser } from '@test-utils/mocks/logged-user.mock';
|
|
3
|
-
import { validateUserPermissions } from './permission.utils';
|
|
4
|
-
function buildMockCache() {
|
|
5
|
-
return {
|
|
6
|
-
get: jest.fn(),
|
|
7
|
-
set: jest.fn(),
|
|
8
|
-
del: jest.fn()
|
|
9
|
-
};
|
|
10
|
-
}
|
|
11
|
-
describe('validateUserPermissions', ()=>{
|
|
12
|
-
it('returns true immediately without touching the cache when no permissions are required', async ()=>{
|
|
13
|
-
const cache = buildMockCache();
|
|
14
|
-
const result = await validateUserPermissions(buildMockUser(), [], cache, false);
|
|
15
|
-
expect(result).toBe(true);
|
|
16
|
-
expect(cache.get).not.toHaveBeenCalled();
|
|
17
|
-
});
|
|
18
|
-
it('returns true when the user has at least one of the required permissions', async ()=>{
|
|
19
|
-
const cache = buildMockCache();
|
|
20
|
-
cache.get.mockResolvedValue([
|
|
21
|
-
'hr.survey.submit',
|
|
22
|
-
'other.permission'
|
|
23
|
-
]);
|
|
24
|
-
const result = await validateUserPermissions(buildMockUser(), [
|
|
25
|
-
'hr.survey.submit',
|
|
26
|
-
'employee.feedback.submit'
|
|
27
|
-
], cache, false);
|
|
28
|
-
expect(result).toBe(true);
|
|
29
|
-
});
|
|
30
|
-
it('returns false when the user has none of the required permissions', async ()=>{
|
|
31
|
-
const cache = buildMockCache();
|
|
32
|
-
cache.get.mockResolvedValue([
|
|
33
|
-
'some.other.permission'
|
|
34
|
-
]);
|
|
35
|
-
const result = await validateUserPermissions(buildMockUser(), [
|
|
36
|
-
'hr.survey.submit'
|
|
37
|
-
], cache, false);
|
|
38
|
-
expect(result).toBe(false);
|
|
39
|
-
});
|
|
40
|
-
it('treats a missing cache entry as no permissions (returns false)', async ()=>{
|
|
41
|
-
const cache = buildMockCache();
|
|
42
|
-
cache.get.mockResolvedValue(undefined);
|
|
43
|
-
const result = await validateUserPermissions(buildMockUser(), [
|
|
44
|
-
'hr.survey.submit'
|
|
45
|
-
], cache, false);
|
|
46
|
-
expect(result).toBe(false);
|
|
47
|
-
});
|
|
48
|
-
it('fails closed with a ForbiddenException when the cache lookup throws', async ()=>{
|
|
49
|
-
const cache = buildMockCache();
|
|
50
|
-
cache.get.mockRejectedValue(new Error('redis down'));
|
|
51
|
-
await expect(validateUserPermissions(buildMockUser(), [
|
|
52
|
-
'hr.survey.submit'
|
|
53
|
-
], cache, false)).rejects.toMatchObject({
|
|
54
|
-
response: expect.objectContaining({
|
|
55
|
-
messageKey: 'form.permission.check.failed'
|
|
56
|
-
})
|
|
57
|
-
});
|
|
58
|
-
await expect(validateUserPermissions(buildMockUser(), [
|
|
59
|
-
'hr.survey.submit'
|
|
60
|
-
], cache, false)).rejects.toBeInstanceOf(ForbiddenException);
|
|
61
|
-
});
|
|
62
|
-
describe('cache key construction', ()=>{
|
|
63
|
-
it('uses a company/branch/user scoped key when the company feature is enabled and both are present', async ()=>{
|
|
64
|
-
const cache = buildMockCache();
|
|
65
|
-
cache.get.mockResolvedValue([]);
|
|
66
|
-
const user = buildMockUser({
|
|
67
|
-
companyId: 'company-1',
|
|
68
|
-
branchId: 'branch-1',
|
|
69
|
-
id: 'user-1'
|
|
70
|
-
});
|
|
71
|
-
await validateUserPermissions(user, [
|
|
72
|
-
'perm.read'
|
|
73
|
-
], cache, true);
|
|
74
|
-
expect(cache.get).toHaveBeenCalledWith('permissions:company:company-1:branch:branch-1:user:user-1');
|
|
75
|
-
});
|
|
76
|
-
it('uses "null" as the branch placeholder when branchId is missing under the company feature', async ()=>{
|
|
77
|
-
const cache = buildMockCache();
|
|
78
|
-
cache.get.mockResolvedValue([]);
|
|
79
|
-
const user = buildMockUser({
|
|
80
|
-
companyId: 'company-1',
|
|
81
|
-
branchId: undefined,
|
|
82
|
-
id: 'user-1'
|
|
83
|
-
});
|
|
84
|
-
await validateUserPermissions(user, [
|
|
85
|
-
'perm.read'
|
|
86
|
-
], cache, true);
|
|
87
|
-
expect(cache.get).toHaveBeenCalledWith('permissions:company:company-1:branch:null:user:user-1');
|
|
88
|
-
});
|
|
89
|
-
it('falls back to a plain user-scoped key when the company feature is enabled but companyId is missing', async ()=>{
|
|
90
|
-
const cache = buildMockCache();
|
|
91
|
-
cache.get.mockResolvedValue([]);
|
|
92
|
-
const user = buildMockUser({
|
|
93
|
-
companyId: undefined,
|
|
94
|
-
id: 'user-1'
|
|
95
|
-
});
|
|
96
|
-
await validateUserPermissions(user, [
|
|
97
|
-
'perm.read'
|
|
98
|
-
], cache, true);
|
|
99
|
-
expect(cache.get).toHaveBeenCalledWith('permissions:user:user-1');
|
|
100
|
-
});
|
|
101
|
-
it('uses a plain user-scoped key when the company feature is disabled', async ()=>{
|
|
102
|
-
const cache = buildMockCache();
|
|
103
|
-
cache.get.mockResolvedValue([]);
|
|
104
|
-
const user = buildMockUser({
|
|
105
|
-
companyId: 'company-1',
|
|
106
|
-
id: 'user-1'
|
|
107
|
-
});
|
|
108
|
-
await validateUserPermissions(user, [
|
|
109
|
-
'perm.read'
|
|
110
|
-
], cache, false);
|
|
111
|
-
expect(cache.get).toHaveBeenCalledWith('permissions:user:user-1');
|
|
112
|
-
});
|
|
113
|
-
});
|
|
114
|
-
});
|