@flusys/nestjs-iam 6.0.1 → 6.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.
- package/cjs/controllers/action.controller.js +17 -9
- package/cjs/controllers/action.controller.spec.js +79 -0
- package/cjs/controllers/company-action-permission.controller.spec.js +65 -0
- package/cjs/controllers/my-permission.controller.spec.js +56 -0
- package/cjs/controllers/role-permission.controller.spec.js +140 -0
- package/cjs/controllers/role.controller.spec.js +86 -0
- package/cjs/controllers/user-action-permission.controller.js +0 -3
- package/cjs/controllers/user-action-permission.controller.spec.js +68 -0
- package/cjs/docs/iam-swagger.config.js +6 -0
- package/cjs/docs/iam-swagger.config.spec.js +99 -0
- package/cjs/dtos/action.dto.js +17 -0
- package/cjs/entities/index.spec.js +56 -0
- package/cjs/helpers/company-access.helper.spec.js +68 -0
- package/cjs/helpers/permission-mode.helper.spec.js +54 -0
- package/cjs/modules/iam.module.js +3 -1
- package/cjs/modules/iam.module.spec.js +293 -0
- package/cjs/services/action.service.js +90 -7
- package/cjs/services/action.service.spec.js +314 -0
- package/cjs/services/iam-config.service.spec.js +110 -0
- package/cjs/services/iam-datasource.service.spec.js +117 -0
- package/cjs/services/permission-cache.service.js +113 -110
- package/cjs/services/permission-cache.service.spec.js +252 -0
- package/cjs/services/permission.service.js +213 -92
- package/cjs/services/permission.service.spec.js +967 -0
- package/cjs/services/role.service.js +47 -3
- package/cjs/services/role.service.spec.js +312 -0
- package/controllers/action.controller.d.ts +5 -3
- package/dtos/action.dto.d.ts +3 -0
- package/entities/index.d.ts +2 -2
- package/fesm/controllers/action.controller.js +18 -10
- package/fesm/controllers/action.controller.spec.js +75 -0
- package/fesm/controllers/company-action-permission.controller.spec.js +61 -0
- package/fesm/controllers/my-permission.controller.spec.js +52 -0
- package/fesm/controllers/role-permission.controller.spec.js +136 -0
- package/fesm/controllers/role.controller.spec.js +82 -0
- package/fesm/controllers/user-action-permission.controller.js +0 -3
- package/fesm/controllers/user-action-permission.controller.spec.js +64 -0
- package/fesm/docs/iam-swagger.config.js +6 -0
- package/fesm/docs/iam-swagger.config.spec.js +95 -0
- package/fesm/dtos/action.dto.js +14 -0
- package/fesm/entities/index.spec.js +52 -0
- package/fesm/helpers/company-access.helper.spec.js +64 -0
- package/fesm/helpers/permission-mode.helper.spec.js +50 -0
- package/fesm/modules/iam.module.js +4 -2
- package/fesm/modules/iam.module.spec.js +289 -0
- package/fesm/services/action.service.js +90 -7
- package/fesm/services/action.service.spec.js +310 -0
- package/fesm/services/iam-config.service.spec.js +106 -0
- package/fesm/services/iam-datasource.service.spec.js +113 -0
- package/fesm/services/permission-cache.service.js +101 -108
- package/fesm/services/permission-cache.service.spec.js +248 -0
- package/fesm/services/permission.service.js +213 -92
- package/fesm/services/permission.service.spec.js +963 -0
- package/fesm/services/role.service.js +48 -4
- package/fesm/services/role.service.spec.js +308 -0
- package/package.json +3 -3
- package/services/action.service.d.ts +7 -3
- package/services/permission-cache.service.d.ts +13 -19
- package/services/permission.service.d.ts +6 -3
- package/services/role.service.d.ts +7 -3
|
@@ -8,13 +8,14 @@ Object.defineProperty(exports, "ActionController", {
|
|
|
8
8
|
return ActionController;
|
|
9
9
|
}
|
|
10
10
|
});
|
|
11
|
-
const _guards = require("@flusys/nestjs-shared/guards");
|
|
12
11
|
const _nestjsshared = require("@flusys/nestjs-shared");
|
|
13
|
-
const
|
|
12
|
+
const _guards = require("@flusys/nestjs-shared/guards");
|
|
14
13
|
const _common = require("@nestjs/common");
|
|
15
14
|
const _swagger = require("@nestjs/swagger");
|
|
15
|
+
const _config = require("../config");
|
|
16
16
|
const _actiondto = require("../dtos/action.dto");
|
|
17
17
|
const _actionservice = require("../services/action.service");
|
|
18
|
+
const _iamconfigservice = require("../services/iam-config.service");
|
|
18
19
|
function _define_property(obj, key, value) {
|
|
19
20
|
if (key in obj) {
|
|
20
21
|
Object.defineProperty(obj, key, {
|
|
@@ -89,8 +90,8 @@ let ActionController = class ActionController extends (0, _nestjsshared.createAp
|
|
|
89
90
|
}
|
|
90
91
|
}
|
|
91
92
|
}) {
|
|
92
|
-
async getActionsForPermission(user) {
|
|
93
|
-
const actions = await this.actionService.getActionsForPermission(user);
|
|
93
|
+
async getActionsForPermission(dto, user) {
|
|
94
|
+
const actions = await this.actionService.getActionsForPermission(user, dto?.companyId);
|
|
94
95
|
return {
|
|
95
96
|
success: true,
|
|
96
97
|
message: 'Actions retrieved successfully',
|
|
@@ -107,8 +108,8 @@ let ActionController = class ActionController extends (0, _nestjsshared.createAp
|
|
|
107
108
|
data: tree
|
|
108
109
|
};
|
|
109
110
|
}
|
|
110
|
-
constructor(actionService){
|
|
111
|
-
super(actionService), _define_property(this, "actionService", void 0), this.actionService = actionService;
|
|
111
|
+
constructor(actionService, iamConfigService){
|
|
112
|
+
super(actionService), _define_property(this, "actionService", void 0), _define_property(this, "iamConfigService", void 0), this.actionService = actionService, this.iamConfigService = iamConfigService;
|
|
112
113
|
}
|
|
113
114
|
};
|
|
114
115
|
_ts_decorate([
|
|
@@ -117,15 +118,20 @@ _ts_decorate([
|
|
|
117
118
|
(0, _swagger.ApiBearerAuth)(),
|
|
118
119
|
(0, _swagger.ApiOperation)({
|
|
119
120
|
summary: 'Get actions for permission assignment',
|
|
120
|
-
description:
|
|
121
|
+
description: "Returns actions available for permission assignment, filtered by company whitelist when company feature is enabled. Optional companyId scopes the whitelist to a specific company (must match the caller's own company); defaults to the caller's session company when omitted."
|
|
121
122
|
}),
|
|
122
123
|
(0, _swagger.ApiResponse)({
|
|
123
124
|
status: 200,
|
|
124
125
|
type: _nestjsshared.SingleResponseDto
|
|
125
126
|
}),
|
|
126
|
-
|
|
127
|
+
(0, _swagger.ApiBody)({
|
|
128
|
+
type: _actiondto.ActionTreeForPermissionDto
|
|
129
|
+
}),
|
|
130
|
+
_ts_param(0, (0, _common.Body)()),
|
|
131
|
+
_ts_param(1, (0, _nestjsshared.CurrentUser)()),
|
|
127
132
|
_ts_metadata("design:type", Function),
|
|
128
133
|
_ts_metadata("design:paramtypes", [
|
|
134
|
+
typeof _actiondto.ActionTreeForPermissionDto === "undefined" ? Object : _actiondto.ActionTreeForPermissionDto,
|
|
129
135
|
typeof _nestjsshared.ILoggedUserInfo === "undefined" ? Object : _nestjsshared.ILoggedUserInfo
|
|
130
136
|
]),
|
|
131
137
|
_ts_metadata("design:returntype", Promise)
|
|
@@ -159,8 +165,10 @@ ActionController = _ts_decorate([
|
|
|
159
165
|
(0, _swagger.ApiTags)('IAM - Actions'),
|
|
160
166
|
(0, _common.Controller)('iam/actions'),
|
|
161
167
|
_ts_param(0, (0, _common.Inject)(_actionservice.ActionService)),
|
|
168
|
+
_ts_param(1, (0, _common.Inject)(_iamconfigservice.IAMConfigService)),
|
|
162
169
|
_ts_metadata("design:type", Function),
|
|
163
170
|
_ts_metadata("design:paramtypes", [
|
|
164
|
-
typeof _actionservice.ActionService === "undefined" ? Object : _actionservice.ActionService
|
|
171
|
+
typeof _actionservice.ActionService === "undefined" ? Object : _actionservice.ActionService,
|
|
172
|
+
typeof _iamconfigservice.IAMConfigService === "undefined" ? Object : _iamconfigservice.IAMConfigService
|
|
165
173
|
])
|
|
166
174
|
], ActionController);
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", {
|
|
3
|
+
value: true
|
|
4
|
+
});
|
|
5
|
+
const _loggedusermock = require("@test-utils/mocks/logged-user.mock");
|
|
6
|
+
const _actioncontroller = require("./action.controller");
|
|
7
|
+
describe('ActionController', ()=>{
|
|
8
|
+
let controller;
|
|
9
|
+
let mockActionService;
|
|
10
|
+
let mockIamConfigService;
|
|
11
|
+
beforeEach(()=>{
|
|
12
|
+
mockActionService = {
|
|
13
|
+
insert: jest.fn(),
|
|
14
|
+
findById: jest.fn(),
|
|
15
|
+
getAll: jest.fn(),
|
|
16
|
+
update: jest.fn(),
|
|
17
|
+
delete: jest.fn(),
|
|
18
|
+
getActionsForPermission: jest.fn(),
|
|
19
|
+
getActionTree: jest.fn()
|
|
20
|
+
};
|
|
21
|
+
mockIamConfigService = {};
|
|
22
|
+
controller = new _actioncontroller.ActionController(mockActionService, mockIamConfigService);
|
|
23
|
+
});
|
|
24
|
+
it('wires the injected service onto the generated controller base', ()=>{
|
|
25
|
+
expect(controller.actionService).toBe(mockActionService);
|
|
26
|
+
expect(controller.service).toBe(mockActionService);
|
|
27
|
+
});
|
|
28
|
+
describe('getActionsForPermission', ()=>{
|
|
29
|
+
it('returns actions scoped to the caller session company when no companyId is given', async ()=>{
|
|
30
|
+
const user = (0, _loggedusermock.buildMockUser)();
|
|
31
|
+
mockActionService.getActionsForPermission.mockResolvedValue([
|
|
32
|
+
{
|
|
33
|
+
id: 'action-1',
|
|
34
|
+
code: 'user.create'
|
|
35
|
+
}
|
|
36
|
+
]);
|
|
37
|
+
const result = await controller.getActionsForPermission({}, user);
|
|
38
|
+
expect(mockActionService.getActionsForPermission).toHaveBeenCalledWith(user, undefined);
|
|
39
|
+
expect(result.success).toBe(true);
|
|
40
|
+
expect(result.data).toEqual([
|
|
41
|
+
{
|
|
42
|
+
id: 'action-1',
|
|
43
|
+
code: 'user.create'
|
|
44
|
+
}
|
|
45
|
+
]);
|
|
46
|
+
});
|
|
47
|
+
it('forwards an explicit companyId override', async ()=>{
|
|
48
|
+
const user = (0, _loggedusermock.buildMockUser)();
|
|
49
|
+
mockActionService.getActionsForPermission.mockResolvedValue([]);
|
|
50
|
+
await controller.getActionsForPermission({
|
|
51
|
+
companyId: 'company-2'
|
|
52
|
+
}, user);
|
|
53
|
+
expect(mockActionService.getActionsForPermission).toHaveBeenCalledWith(user, 'company-2');
|
|
54
|
+
});
|
|
55
|
+
});
|
|
56
|
+
describe('getActionTree', ()=>{
|
|
57
|
+
it('returns the hierarchical action tree with query filters applied', async ()=>{
|
|
58
|
+
const user = (0, _loggedusermock.buildMockUser)();
|
|
59
|
+
mockActionService.getActionTree.mockResolvedValue([
|
|
60
|
+
{
|
|
61
|
+
id: 'action-1',
|
|
62
|
+
children: []
|
|
63
|
+
}
|
|
64
|
+
]);
|
|
65
|
+
const result = await controller.getActionTree({
|
|
66
|
+
search: 'user',
|
|
67
|
+
isActive: true,
|
|
68
|
+
withDeleted: false
|
|
69
|
+
}, user);
|
|
70
|
+
expect(mockActionService.getActionTree).toHaveBeenCalledWith(user, 'user', true, false);
|
|
71
|
+
expect(result.data).toEqual([
|
|
72
|
+
{
|
|
73
|
+
id: 'action-1',
|
|
74
|
+
children: []
|
|
75
|
+
}
|
|
76
|
+
]);
|
|
77
|
+
});
|
|
78
|
+
});
|
|
79
|
+
});
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", {
|
|
3
|
+
value: true
|
|
4
|
+
});
|
|
5
|
+
const _companyactionpermissioncontroller = require("./company-action-permission.controller");
|
|
6
|
+
describe('CompanyActionPermissionController', ()=>{
|
|
7
|
+
let controller;
|
|
8
|
+
let mockPermissionService;
|
|
9
|
+
beforeEach(()=>{
|
|
10
|
+
mockPermissionService = {
|
|
11
|
+
assignCompanyActions: jest.fn(),
|
|
12
|
+
getCompanyActions: jest.fn()
|
|
13
|
+
};
|
|
14
|
+
controller = new _companyactionpermissioncontroller.CompanyActionPermissionController(mockPermissionService);
|
|
15
|
+
});
|
|
16
|
+
describe('assignCompanyActions', ()=>{
|
|
17
|
+
it('whitelists actions for a company', async ()=>{
|
|
18
|
+
mockPermissionService.assignCompanyActions.mockResolvedValue({
|
|
19
|
+
added: 3,
|
|
20
|
+
removed: 0,
|
|
21
|
+
total: 3
|
|
22
|
+
});
|
|
23
|
+
const result = await controller.assignCompanyActions({
|
|
24
|
+
companyId: 'company-1',
|
|
25
|
+
actionIds: [
|
|
26
|
+
'action-1',
|
|
27
|
+
'action-2',
|
|
28
|
+
'action-3'
|
|
29
|
+
]
|
|
30
|
+
});
|
|
31
|
+
expect(mockPermissionService.assignCompanyActions).toHaveBeenCalledWith({
|
|
32
|
+
companyId: 'company-1',
|
|
33
|
+
actionIds: [
|
|
34
|
+
'action-1',
|
|
35
|
+
'action-2',
|
|
36
|
+
'action-3'
|
|
37
|
+
]
|
|
38
|
+
});
|
|
39
|
+
expect(result.success).toBe(true);
|
|
40
|
+
expect(result.data).toEqual({
|
|
41
|
+
added: 3,
|
|
42
|
+
removed: 0,
|
|
43
|
+
total: 3
|
|
44
|
+
});
|
|
45
|
+
});
|
|
46
|
+
});
|
|
47
|
+
describe('getCompanyActions', ()=>{
|
|
48
|
+
it('returns the whitelisted actions for a company', async ()=>{
|
|
49
|
+
mockPermissionService.getCompanyActions.mockResolvedValue([
|
|
50
|
+
{
|
|
51
|
+
actionId: 'action-1'
|
|
52
|
+
}
|
|
53
|
+
]);
|
|
54
|
+
const result = await controller.getCompanyActions({
|
|
55
|
+
companyId: 'company-1'
|
|
56
|
+
});
|
|
57
|
+
expect(mockPermissionService.getCompanyActions).toHaveBeenCalledWith('company-1');
|
|
58
|
+
expect(result.data).toEqual([
|
|
59
|
+
{
|
|
60
|
+
actionId: 'action-1'
|
|
61
|
+
}
|
|
62
|
+
]);
|
|
63
|
+
});
|
|
64
|
+
});
|
|
65
|
+
});
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", {
|
|
3
|
+
value: true
|
|
4
|
+
});
|
|
5
|
+
const _loggedusermock = require("@test-utils/mocks/logged-user.mock");
|
|
6
|
+
const _mypermissioncontroller = require("./my-permission.controller");
|
|
7
|
+
describe('MyPermissionController', ()=>{
|
|
8
|
+
let controller;
|
|
9
|
+
let mockPermissionService;
|
|
10
|
+
beforeEach(()=>{
|
|
11
|
+
mockPermissionService = {
|
|
12
|
+
getMyPermissions: jest.fn()
|
|
13
|
+
};
|
|
14
|
+
controller = new _mypermissioncontroller.MyPermissionController(mockPermissionService);
|
|
15
|
+
});
|
|
16
|
+
describe('getMyPermissions', ()=>{
|
|
17
|
+
it('resolves permissions for the current user, branch, and company', async ()=>{
|
|
18
|
+
const user = (0, _loggedusermock.buildMockUser)({
|
|
19
|
+
id: 'user-1',
|
|
20
|
+
companyId: 'company-1',
|
|
21
|
+
branchId: 'branch-1'
|
|
22
|
+
});
|
|
23
|
+
const permissions = {
|
|
24
|
+
menus: [],
|
|
25
|
+
actions: [
|
|
26
|
+
'user.create'
|
|
27
|
+
]
|
|
28
|
+
};
|
|
29
|
+
mockPermissionService.getMyPermissions.mockResolvedValue(permissions);
|
|
30
|
+
const result = await controller.getMyPermissions({
|
|
31
|
+
parentCodes: [
|
|
32
|
+
'user'
|
|
33
|
+
]
|
|
34
|
+
}, user);
|
|
35
|
+
expect(mockPermissionService.getMyPermissions).toHaveBeenCalledWith('user-1', 'branch-1', 'company-1', [
|
|
36
|
+
'user'
|
|
37
|
+
]);
|
|
38
|
+
expect(result).toEqual({
|
|
39
|
+
success: true,
|
|
40
|
+
message: 'Permissions loaded successfully',
|
|
41
|
+
messageKey: expect.any(String),
|
|
42
|
+
data: permissions
|
|
43
|
+
});
|
|
44
|
+
});
|
|
45
|
+
it('passes null for missing branch and company context', async ()=>{
|
|
46
|
+
const user = (0, _loggedusermock.buildMockUser)({
|
|
47
|
+
id: 'user-1',
|
|
48
|
+
companyId: undefined,
|
|
49
|
+
branchId: undefined
|
|
50
|
+
});
|
|
51
|
+
mockPermissionService.getMyPermissions.mockResolvedValue({});
|
|
52
|
+
await controller.getMyPermissions({}, user);
|
|
53
|
+
expect(mockPermissionService.getMyPermissions).toHaveBeenCalledWith('user-1', null, null, undefined);
|
|
54
|
+
});
|
|
55
|
+
});
|
|
56
|
+
});
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", {
|
|
3
|
+
value: true
|
|
4
|
+
});
|
|
5
|
+
const _common = require("@nestjs/common");
|
|
6
|
+
const _loggedusermock = require("@test-utils/mocks/logged-user.mock");
|
|
7
|
+
const _rolepermissioncontroller = require("./role-permission.controller");
|
|
8
|
+
describe('RolePermissionController', ()=>{
|
|
9
|
+
let controller;
|
|
10
|
+
let mockPermissionService;
|
|
11
|
+
let mockConfig;
|
|
12
|
+
beforeEach(()=>{
|
|
13
|
+
mockPermissionService = {
|
|
14
|
+
assignRoleActions: jest.fn(),
|
|
15
|
+
getRoleActions: jest.fn(),
|
|
16
|
+
assignUserRoles: jest.fn(),
|
|
17
|
+
getUserRoles: jest.fn()
|
|
18
|
+
};
|
|
19
|
+
mockConfig = {
|
|
20
|
+
isCompanyFeatureEnabled: jest.fn().mockReturnValue(false)
|
|
21
|
+
};
|
|
22
|
+
controller = new _rolepermissioncontroller.RolePermissionController(mockPermissionService, mockConfig);
|
|
23
|
+
});
|
|
24
|
+
describe('assignRoleActions', ()=>{
|
|
25
|
+
it('assigns actions to a role and returns the operation summary', async ()=>{
|
|
26
|
+
mockPermissionService.assignRoleActions.mockResolvedValue({
|
|
27
|
+
added: 2,
|
|
28
|
+
removed: 1,
|
|
29
|
+
total: 3
|
|
30
|
+
});
|
|
31
|
+
const result = await controller.assignRoleActions({
|
|
32
|
+
roleId: 'role-1',
|
|
33
|
+
actionIds: [
|
|
34
|
+
'action-1',
|
|
35
|
+
'action-2'
|
|
36
|
+
]
|
|
37
|
+
});
|
|
38
|
+
expect(mockPermissionService.assignRoleActions).toHaveBeenCalledWith({
|
|
39
|
+
roleId: 'role-1',
|
|
40
|
+
actionIds: [
|
|
41
|
+
'action-1',
|
|
42
|
+
'action-2'
|
|
43
|
+
]
|
|
44
|
+
});
|
|
45
|
+
expect(result.success).toBe(true);
|
|
46
|
+
expect(result.data).toEqual({
|
|
47
|
+
added: 2,
|
|
48
|
+
removed: 1,
|
|
49
|
+
total: 3
|
|
50
|
+
});
|
|
51
|
+
});
|
|
52
|
+
});
|
|
53
|
+
describe('getRoleActions', ()=>{
|
|
54
|
+
it('returns actions assigned to the role', async ()=>{
|
|
55
|
+
mockPermissionService.getRoleActions.mockResolvedValue([
|
|
56
|
+
{
|
|
57
|
+
actionId: 'action-1'
|
|
58
|
+
}
|
|
59
|
+
]);
|
|
60
|
+
const result = await controller.getRoleActions({
|
|
61
|
+
roleId: 'role-1'
|
|
62
|
+
});
|
|
63
|
+
expect(mockPermissionService.getRoleActions).toHaveBeenCalledWith('role-1');
|
|
64
|
+
expect(result.data).toEqual([
|
|
65
|
+
{
|
|
66
|
+
actionId: 'action-1'
|
|
67
|
+
}
|
|
68
|
+
]);
|
|
69
|
+
});
|
|
70
|
+
});
|
|
71
|
+
describe('assignUserRoles', ()=>{
|
|
72
|
+
it('assigns roles to a user when the caller has access to the target company', async ()=>{
|
|
73
|
+
mockConfig.isCompanyFeatureEnabled.mockReturnValue(true);
|
|
74
|
+
const user = (0, _loggedusermock.buildMockUser)({
|
|
75
|
+
companyId: 'company-1'
|
|
76
|
+
});
|
|
77
|
+
mockPermissionService.assignUserRoles.mockResolvedValue({
|
|
78
|
+
added: 1,
|
|
79
|
+
removed: 0,
|
|
80
|
+
total: 1
|
|
81
|
+
});
|
|
82
|
+
const result = await controller.assignUserRoles({
|
|
83
|
+
userId: 'user-2',
|
|
84
|
+
roleIds: [
|
|
85
|
+
'role-1'
|
|
86
|
+
],
|
|
87
|
+
companyId: 'company-1'
|
|
88
|
+
}, user);
|
|
89
|
+
expect(mockPermissionService.assignUserRoles).toHaveBeenCalledWith({
|
|
90
|
+
userId: 'user-2',
|
|
91
|
+
roleIds: [
|
|
92
|
+
'role-1'
|
|
93
|
+
],
|
|
94
|
+
companyId: 'company-1'
|
|
95
|
+
});
|
|
96
|
+
expect(result.data).toEqual({
|
|
97
|
+
added: 1,
|
|
98
|
+
removed: 0,
|
|
99
|
+
total: 1
|
|
100
|
+
});
|
|
101
|
+
});
|
|
102
|
+
it('rejects assignment when the caller has no access to the target company', async ()=>{
|
|
103
|
+
mockConfig.isCompanyFeatureEnabled.mockReturnValue(true);
|
|
104
|
+
const user = (0, _loggedusermock.buildMockUser)({
|
|
105
|
+
companyId: 'company-1'
|
|
106
|
+
});
|
|
107
|
+
await expect(controller.assignUserRoles({
|
|
108
|
+
userId: 'user-2',
|
|
109
|
+
roleIds: [
|
|
110
|
+
'role-1'
|
|
111
|
+
],
|
|
112
|
+
companyId: 'company-2'
|
|
113
|
+
}, user)).rejects.toThrow(_common.ForbiddenException);
|
|
114
|
+
expect(mockPermissionService.assignUserRoles).not.toHaveBeenCalled();
|
|
115
|
+
});
|
|
116
|
+
});
|
|
117
|
+
describe('getUserRoles', ()=>{
|
|
118
|
+
it('returns roles assigned to the user scoped by branch and company', async ()=>{
|
|
119
|
+
const user = (0, _loggedusermock.buildMockUser)({
|
|
120
|
+
companyId: 'company-1'
|
|
121
|
+
});
|
|
122
|
+
mockPermissionService.getUserRoles.mockResolvedValue([
|
|
123
|
+
{
|
|
124
|
+
roleId: 'role-1'
|
|
125
|
+
}
|
|
126
|
+
]);
|
|
127
|
+
const result = await controller.getUserRoles({
|
|
128
|
+
userId: 'user-2',
|
|
129
|
+
branchId: 'branch-1',
|
|
130
|
+
companyId: 'company-1'
|
|
131
|
+
}, user);
|
|
132
|
+
expect(mockPermissionService.getUserRoles).toHaveBeenCalledWith('user-2', 'branch-1', 'company-1');
|
|
133
|
+
expect(result.data).toEqual([
|
|
134
|
+
{
|
|
135
|
+
roleId: 'role-1'
|
|
136
|
+
}
|
|
137
|
+
]);
|
|
138
|
+
});
|
|
139
|
+
});
|
|
140
|
+
});
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", {
|
|
3
|
+
value: true
|
|
4
|
+
});
|
|
5
|
+
const _loggedusermock = require("@test-utils/mocks/logged-user.mock");
|
|
6
|
+
const _rolecontroller = require("./role.controller");
|
|
7
|
+
function buildRole(overrides = {}) {
|
|
8
|
+
return {
|
|
9
|
+
id: 'role-1',
|
|
10
|
+
name: 'Admin',
|
|
11
|
+
description: null,
|
|
12
|
+
isActive: true,
|
|
13
|
+
readOnly: false,
|
|
14
|
+
createdAt: new Date(),
|
|
15
|
+
updatedAt: new Date(),
|
|
16
|
+
...overrides
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
describe('RoleController', ()=>{
|
|
20
|
+
let controller;
|
|
21
|
+
let mockRoleService;
|
|
22
|
+
beforeEach(()=>{
|
|
23
|
+
mockRoleService = {
|
|
24
|
+
insert: jest.fn(),
|
|
25
|
+
findById: jest.fn(),
|
|
26
|
+
getAll: jest.fn(),
|
|
27
|
+
update: jest.fn(),
|
|
28
|
+
delete: jest.fn()
|
|
29
|
+
};
|
|
30
|
+
controller = new _rolecontroller.RoleController(mockRoleService);
|
|
31
|
+
});
|
|
32
|
+
it('wires the injected service onto the generated controller base', ()=>{
|
|
33
|
+
expect(controller.roleService).toBe(mockRoleService);
|
|
34
|
+
expect(controller.service).toBe(mockRoleService);
|
|
35
|
+
});
|
|
36
|
+
describe('insert', ()=>{
|
|
37
|
+
it('creates a role and returns the mapped response', async ()=>{
|
|
38
|
+
const user = (0, _loggedusermock.buildMockUser)();
|
|
39
|
+
mockRoleService.insert.mockResolvedValue(buildRole());
|
|
40
|
+
const result = await controller.insert({
|
|
41
|
+
name: 'Admin'
|
|
42
|
+
}, user);
|
|
43
|
+
expect(mockRoleService.insert).toHaveBeenCalledWith({
|
|
44
|
+
name: 'Admin'
|
|
45
|
+
}, user);
|
|
46
|
+
expect(result.success).toBe(true);
|
|
47
|
+
expect(result.data).toEqual(expect.objectContaining({
|
|
48
|
+
id: 'role-1',
|
|
49
|
+
name: 'Admin'
|
|
50
|
+
}));
|
|
51
|
+
});
|
|
52
|
+
});
|
|
53
|
+
describe('getAll', ()=>{
|
|
54
|
+
it('paginates roles and maps the response list', async ()=>{
|
|
55
|
+
mockRoleService.getAll.mockResolvedValue({
|
|
56
|
+
data: [
|
|
57
|
+
buildRole()
|
|
58
|
+
],
|
|
59
|
+
total: 1
|
|
60
|
+
});
|
|
61
|
+
const result = await controller.getAll({}, (0, _loggedusermock.buildMockUser)(), '');
|
|
62
|
+
expect(mockRoleService.getAll).toHaveBeenCalledWith('', {}, (0, _loggedusermock.buildMockUser)());
|
|
63
|
+
expect(result.data).toHaveLength(1);
|
|
64
|
+
});
|
|
65
|
+
});
|
|
66
|
+
describe('delete', ()=>{
|
|
67
|
+
it('delegates soft-delete to the service', async ()=>{
|
|
68
|
+
mockRoleService.delete.mockResolvedValue({
|
|
69
|
+
count: 1
|
|
70
|
+
});
|
|
71
|
+
const result = await controller.delete({
|
|
72
|
+
id: [
|
|
73
|
+
'role-1'
|
|
74
|
+
],
|
|
75
|
+
type: 'delete'
|
|
76
|
+
}, (0, _loggedusermock.buildMockUser)());
|
|
77
|
+
expect(mockRoleService.delete).toHaveBeenCalledWith({
|
|
78
|
+
id: [
|
|
79
|
+
'role-1'
|
|
80
|
+
],
|
|
81
|
+
type: 'delete'
|
|
82
|
+
}, (0, _loggedusermock.buildMockUser)());
|
|
83
|
+
expect(result.success).toBe(true);
|
|
84
|
+
});
|
|
85
|
+
});
|
|
86
|
+
});
|
|
@@ -13,7 +13,6 @@ const _common = require("@nestjs/common");
|
|
|
13
13
|
const _swagger = require("@nestjs/swagger");
|
|
14
14
|
const _config = require("../config");
|
|
15
15
|
const _permissiondto = require("../dtos/permission.dto");
|
|
16
|
-
const _helpers = require("../helpers");
|
|
17
16
|
const _iamconfigservice = require("../services/iam-config.service");
|
|
18
17
|
const _permissionservice = require("../services/permission.service");
|
|
19
18
|
function _define_property(obj, key, value) {
|
|
@@ -45,7 +44,6 @@ function _ts_param(paramIndex, decorator) {
|
|
|
45
44
|
}
|
|
46
45
|
let UserActionPermissionController = class UserActionPermissionController {
|
|
47
46
|
async assignUserActions(dto, user) {
|
|
48
|
-
(0, _helpers.validateCompanyAccess)(this.config, dto.companyId, user);
|
|
49
47
|
const result = await this.permissionService.assignUserActions(dto);
|
|
50
48
|
return {
|
|
51
49
|
success: true,
|
|
@@ -60,7 +58,6 @@ let UserActionPermissionController = class UserActionPermissionController {
|
|
|
60
58
|
};
|
|
61
59
|
}
|
|
62
60
|
async getUserActions(dto, user) {
|
|
63
|
-
(0, _helpers.validateCompanyAccess)(this.config, dto.companyId, user);
|
|
64
61
|
const actions = await this.permissionService.getUserActions(dto.userId, dto.branchId, dto.companyId);
|
|
65
62
|
return {
|
|
66
63
|
success: true,
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", {
|
|
3
|
+
value: true
|
|
4
|
+
});
|
|
5
|
+
const _loggedusermock = require("@test-utils/mocks/logged-user.mock");
|
|
6
|
+
const _useractionpermissioncontroller = require("./user-action-permission.controller");
|
|
7
|
+
describe('UserActionPermissionController', ()=>{
|
|
8
|
+
let controller;
|
|
9
|
+
let mockPermissionService;
|
|
10
|
+
let mockConfig;
|
|
11
|
+
beforeEach(()=>{
|
|
12
|
+
mockPermissionService = {
|
|
13
|
+
assignUserActions: jest.fn(),
|
|
14
|
+
getUserActions: jest.fn()
|
|
15
|
+
};
|
|
16
|
+
mockConfig = {};
|
|
17
|
+
controller = new _useractionpermissioncontroller.UserActionPermissionController(mockPermissionService, mockConfig);
|
|
18
|
+
});
|
|
19
|
+
describe('assignUserActions', ()=>{
|
|
20
|
+
it('assigns direct action permissions to a user', async ()=>{
|
|
21
|
+
const user = (0, _loggedusermock.buildMockUser)();
|
|
22
|
+
mockPermissionService.assignUserActions.mockResolvedValue({
|
|
23
|
+
added: 1,
|
|
24
|
+
removed: 0,
|
|
25
|
+
total: 1
|
|
26
|
+
});
|
|
27
|
+
const result = await controller.assignUserActions({
|
|
28
|
+
userId: 'user-2',
|
|
29
|
+
actionIds: [
|
|
30
|
+
'action-1'
|
|
31
|
+
]
|
|
32
|
+
}, user);
|
|
33
|
+
expect(mockPermissionService.assignUserActions).toHaveBeenCalledWith({
|
|
34
|
+
userId: 'user-2',
|
|
35
|
+
actionIds: [
|
|
36
|
+
'action-1'
|
|
37
|
+
]
|
|
38
|
+
});
|
|
39
|
+
expect(result.success).toBe(true);
|
|
40
|
+
expect(result.data).toEqual({
|
|
41
|
+
added: 1,
|
|
42
|
+
removed: 0,
|
|
43
|
+
total: 1
|
|
44
|
+
});
|
|
45
|
+
});
|
|
46
|
+
});
|
|
47
|
+
describe('getUserActions', ()=>{
|
|
48
|
+
it('returns direct action permissions for a user scoped by branch/company', async ()=>{
|
|
49
|
+
const user = (0, _loggedusermock.buildMockUser)();
|
|
50
|
+
mockPermissionService.getUserActions.mockResolvedValue([
|
|
51
|
+
{
|
|
52
|
+
actionId: 'action-1'
|
|
53
|
+
}
|
|
54
|
+
]);
|
|
55
|
+
const result = await controller.getUserActions({
|
|
56
|
+
userId: 'user-2',
|
|
57
|
+
branchId: 'branch-1',
|
|
58
|
+
companyId: 'company-1'
|
|
59
|
+
}, user);
|
|
60
|
+
expect(mockPermissionService.getUserActions).toHaveBeenCalledWith('user-2', 'branch-1', 'company-1');
|
|
61
|
+
expect(result.data).toEqual([
|
|
62
|
+
{
|
|
63
|
+
actionId: 'action-1'
|
|
64
|
+
}
|
|
65
|
+
]);
|
|
66
|
+
});
|
|
67
|
+
});
|
|
68
|
+
});
|
|
@@ -49,6 +49,12 @@ function iamSwaggerConfig(enableCompanyFeature = false, permissionMode = _permis
|
|
|
49
49
|
'branchId'
|
|
50
50
|
]
|
|
51
51
|
},
|
|
52
|
+
{
|
|
53
|
+
schemaName: 'ActionTreeForPermissionDto',
|
|
54
|
+
properties: [
|
|
55
|
+
'companyId'
|
|
56
|
+
]
|
|
57
|
+
},
|
|
52
58
|
// Response DTOs with branchId
|
|
53
59
|
{
|
|
54
60
|
schemaName: 'UserActionResponseDto',
|