@holoyan/adonisjs-permissions 0.5.0 → 0.6.4
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/README.md +277 -97
- package/build/configure.js +9 -0
- package/build/index.d.ts +2 -1
- package/build/index.js +2 -1
- package/build/providers/role_permission_provider.js +5 -3
- package/build/src/acl.d.ts +14 -6
- package/build/src/acl.js +33 -12
- package/build/src/mixins/has_permissions.d.ts +1 -2
- package/build/src/mixins/has_permissions.js +0 -3
- package/build/src/model_manager.d.ts +3 -3
- package/build/src/scope.d.ts +7 -0
- package/build/src/scope.js +14 -0
- package/build/src/services/model_has_role_permissions.d.ts +12 -3
- package/build/src/services/model_has_role_permissions.js +29 -2
- package/build/src/services/permissions/empty_permission.d.ts +5 -1
- package/build/src/services/permissions/empty_permission.js +10 -1
- package/build/src/services/permissions/permission_has_model_roles.d.ts +5 -2
- package/build/src/services/permissions/permission_has_model_roles.js +10 -1
- package/build/src/services/permissions/permissions_service.d.ts +11 -3
- package/build/src/services/permissions/permissions_service.js +58 -13
- package/build/src/services/query_helper.d.ts +4 -4
- package/build/src/services/query_helper.js +8 -8
- package/build/src/services/roles/empty_roles.d.ts +5 -1
- package/build/src/services/roles/empty_roles.js +10 -1
- package/build/src/services/roles/role_has_model_permissions.d.ts +7 -6
- package/build/src/services/roles/role_has_model_permissions.js +16 -6
- package/build/src/services/roles/roles_service.d.ts +10 -5
- package/build/src/services/roles/roles_service.js +34 -19
- package/build/src/types.d.ts +22 -1
- package/build/stubs/middlewares/acl_middleware.stub +26 -0
- package/package.json +1 -1
|
@@ -6,7 +6,8 @@ export default class PermissionsService extends BaseService {
|
|
|
6
6
|
modelPermissionClassName;
|
|
7
7
|
modelRoleClassName;
|
|
8
8
|
map;
|
|
9
|
-
|
|
9
|
+
scope;
|
|
10
|
+
// private permissionQuery
|
|
10
11
|
permissionTable;
|
|
11
12
|
// private roleQuery
|
|
12
13
|
// private readonly roleTable
|
|
@@ -14,14 +15,15 @@ export default class PermissionsService extends BaseService {
|
|
|
14
15
|
modelPermissionTable;
|
|
15
16
|
// private modelRoleQuery
|
|
16
17
|
modelRoleTable;
|
|
17
|
-
constructor(permissionClassName, roleClassName, modelPermissionClassName, modelRoleClassName, map) {
|
|
18
|
+
constructor(permissionClassName, roleClassName, modelPermissionClassName, modelRoleClassName, map, scope) {
|
|
18
19
|
super();
|
|
19
20
|
this.permissionClassName = permissionClassName;
|
|
20
21
|
this.roleClassName = roleClassName;
|
|
21
22
|
this.modelPermissionClassName = modelPermissionClassName;
|
|
22
23
|
this.modelRoleClassName = modelRoleClassName;
|
|
23
24
|
this.map = map;
|
|
24
|
-
this.
|
|
25
|
+
this.scope = scope;
|
|
26
|
+
// this.permissionQuery = getPermissionModelQuery(this.permissionClassName)
|
|
25
27
|
this.permissionTable = this.permissionClassName.table;
|
|
26
28
|
// this.roleQuery = getRoleModelQuery(this.roleClassName)
|
|
27
29
|
// this.roleTable = this.roleClassName.table
|
|
@@ -30,6 +32,11 @@ export default class PermissionsService extends BaseService {
|
|
|
30
32
|
// this.modelRoleQuery = getModelRoleModelQuery(this.modelRoleClassName)
|
|
31
33
|
this.modelRoleTable = this.modelRoleClassName.table;
|
|
32
34
|
}
|
|
35
|
+
get permissionQuery() {
|
|
36
|
+
const q = getPermissionModelQuery(this.permissionClassName);
|
|
37
|
+
this.applyScopes(q);
|
|
38
|
+
return q;
|
|
39
|
+
}
|
|
33
40
|
/**
|
|
34
41
|
* return all permissions, including forbidden
|
|
35
42
|
*/
|
|
@@ -85,6 +92,16 @@ export default class PermissionsService extends BaseService {
|
|
|
85
92
|
.distinct(this.permissionTable + '.id')
|
|
86
93
|
.select(this.permissionTable + '.*');
|
|
87
94
|
}
|
|
95
|
+
async throughRoles(modelType, modelId, includeForbiddings = false) {
|
|
96
|
+
return this.modelPermissionQueryBuilder({
|
|
97
|
+
modelType,
|
|
98
|
+
modelId,
|
|
99
|
+
includeForbiddings,
|
|
100
|
+
throughRoles: true,
|
|
101
|
+
})
|
|
102
|
+
.distinct(this.permissionTable + '.id')
|
|
103
|
+
.select(this.permissionTable + '.*');
|
|
104
|
+
}
|
|
88
105
|
directGlobal(modelType, modelId, includeForbiddings = false) {
|
|
89
106
|
return this.modelPermissionQueryBuilder({
|
|
90
107
|
modelType,
|
|
@@ -106,7 +123,7 @@ export default class PermissionsService extends BaseService {
|
|
|
106
123
|
directPermissions: true,
|
|
107
124
|
includeForbiddings,
|
|
108
125
|
})
|
|
109
|
-
.
|
|
126
|
+
.where(this.permissionTable + '.entity_type', '!=', '*')
|
|
110
127
|
.distinct(this.permissionTable + '.id')
|
|
111
128
|
.select(this.permissionTable + '.*');
|
|
112
129
|
}
|
|
@@ -288,6 +305,16 @@ export default class PermissionsService extends BaseService {
|
|
|
288
305
|
const newPermissions = (await this.permissionClassName.createMany(createManyData));
|
|
289
306
|
newPermissions.map((i) => permissionIds.push(i.id));
|
|
290
307
|
}
|
|
308
|
+
// first check if there are assigned or not
|
|
309
|
+
const alreadyAssigned = await this.modelPermissionQuery
|
|
310
|
+
.whereIn('id', permissionIds)
|
|
311
|
+
.where('model_type', modelType)
|
|
312
|
+
.where('model_id', modelId)
|
|
313
|
+
.select('id');
|
|
314
|
+
const alreadyAssignedIds = alreadyAssigned.map((item) => item.id);
|
|
315
|
+
permissionIds = permissionIds.filter((item) => {
|
|
316
|
+
return !alreadyAssignedIds.includes(item);
|
|
317
|
+
});
|
|
291
318
|
let modelPermissionMany = permissionIds.map((i) => ({
|
|
292
319
|
modelType: modelType,
|
|
293
320
|
modelId: modelId,
|
|
@@ -302,6 +329,7 @@ export default class PermissionsService extends BaseService {
|
|
|
302
329
|
.where('p.allowed', true)
|
|
303
330
|
.where(this.modelPermissionTable + '.model_type', modelType)
|
|
304
331
|
.where(this.modelPermissionTable + '.model_id', modelId);
|
|
332
|
+
this.applyModelPermissionScopes(q, 'p');
|
|
305
333
|
if (entityType) {
|
|
306
334
|
q.where('p.entity_type', entityType);
|
|
307
335
|
if (entityId) {
|
|
@@ -342,13 +370,13 @@ export default class PermissionsService extends BaseService {
|
|
|
342
370
|
* to remove forbidden permission on model
|
|
343
371
|
*/
|
|
344
372
|
async unforbidAll(modelType, modelId, permissionsSlug, entityType, entityId) {
|
|
345
|
-
// todo replace using reverseModelPermissionQuery() method
|
|
346
373
|
const q = this.modelPermissionQuery
|
|
347
374
|
.leftJoin(this.permissionTable + ' as p', 'p.id', '=', this.modelPermissionTable + '.permission_id')
|
|
348
375
|
.where('model_type', modelType)
|
|
349
376
|
.where('model_id', modelId)
|
|
350
377
|
.whereIn('p.slug', permissionsSlug)
|
|
351
378
|
.where('p.allowed', false);
|
|
379
|
+
this.applyModelPermissionScopes(q, 'p');
|
|
352
380
|
if (entityType) {
|
|
353
381
|
q.where('p.entity_type', entityType);
|
|
354
382
|
if (entityId) {
|
|
@@ -374,15 +402,21 @@ export default class PermissionsService extends BaseService {
|
|
|
374
402
|
else {
|
|
375
403
|
q.leftJoin(this.modelRoleTable + ' as mr', (joinQuery) => {
|
|
376
404
|
joinQuery.onVal('mr.model_type', modelType).onVal('mr.model_id', modelId);
|
|
377
|
-
}).where((subQuery) => {
|
|
378
|
-
subQuery
|
|
379
|
-
.where((query) => {
|
|
380
|
-
query.where('mp.model_type', modelType).where('mp.model_id', modelId);
|
|
381
|
-
})
|
|
382
|
-
.orWhere((query) => {
|
|
383
|
-
query.whereRaw('mr.role_id=mp.model_id').where('mp.model_type', 'roles');
|
|
384
|
-
});
|
|
385
405
|
});
|
|
406
|
+
if (conditions.throughRoles) {
|
|
407
|
+
q.whereRaw('mr.role_id=mp.model_id').where('mp.model_type', 'roles');
|
|
408
|
+
}
|
|
409
|
+
else {
|
|
410
|
+
q.where((subQuery) => {
|
|
411
|
+
subQuery
|
|
412
|
+
.where((query) => {
|
|
413
|
+
query.where('mp.model_type', modelType).where('mp.model_id', modelId);
|
|
414
|
+
})
|
|
415
|
+
.orWhere((query) => {
|
|
416
|
+
query.whereRaw('mr.role_id=mp.model_id').where('mp.model_type', 'roles');
|
|
417
|
+
});
|
|
418
|
+
});
|
|
419
|
+
}
|
|
386
420
|
}
|
|
387
421
|
}
|
|
388
422
|
if (!includeForbiddings) {
|
|
@@ -392,6 +426,7 @@ export default class PermissionsService extends BaseService {
|
|
|
392
426
|
.leftJoin(this.modelPermissionTable + ' as mp2', 'mp2.permission_id', '=', 'p2.id')
|
|
393
427
|
.where('p2.allowed', false)
|
|
394
428
|
.whereRaw('p2.slug=' + this.permissionTable + '.slug')
|
|
429
|
+
.whereRaw('p2.scope=' + this.permissionTable + '.scope')
|
|
395
430
|
.select('p2.slug')
|
|
396
431
|
.groupBy('p2.slug');
|
|
397
432
|
if (conditions.entity) {
|
|
@@ -404,6 +439,10 @@ export default class PermissionsService extends BaseService {
|
|
|
404
439
|
}
|
|
405
440
|
return q;
|
|
406
441
|
}
|
|
442
|
+
/**
|
|
443
|
+
* @deprecated
|
|
444
|
+
* @param conditions
|
|
445
|
+
*/
|
|
407
446
|
reverseModelPermissionQuery(conditions) {
|
|
408
447
|
const { modelId, modelType, permissionSlugs, directPermissions } = conditions;
|
|
409
448
|
const q = this.modelPermissionQuery.leftJoin(this.permissionTable + ' as p', 'p.id', '=', this.modelPermissionTable + '.permission_id');
|
|
@@ -468,4 +507,10 @@ export default class PermissionsService extends BaseService {
|
|
|
468
507
|
q.where(table + '.entity_type', '*').whereNull(table + '.entity_id');
|
|
469
508
|
}
|
|
470
509
|
}
|
|
510
|
+
applyScopes(q) {
|
|
511
|
+
q.where(this.permissionTable + '.scope', this.scope.get());
|
|
512
|
+
}
|
|
513
|
+
applyModelPermissionScopes(q, table) {
|
|
514
|
+
q.where(table + '.scope', this.scope.get());
|
|
515
|
+
}
|
|
471
516
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { LucidModel, ModelQueryBuilderContract } from '@adonisjs/lucid/types/model';
|
|
2
2
|
import { BaseModel } from '@adonisjs/lucid/orm';
|
|
3
3
|
import { ModelPermissionModel, ModelRoleModel, PermissionModel, RoleModel } from '../types.js';
|
|
4
|
-
export declare function getPermissionModelQuery<T extends LucidModel>(
|
|
5
|
-
export declare function getRoleModelQuery<T extends LucidModel>(
|
|
6
|
-
export declare function getModelPermissionModelQuery<T extends LucidModel>(
|
|
7
|
-
export declare function getModelRoleModelQuery<T extends LucidModel>(
|
|
4
|
+
export declare function getPermissionModelQuery<T extends LucidModel>(className: typeof BaseModel): ModelQueryBuilderContract<T, PermissionModel<T>>;
|
|
5
|
+
export declare function getRoleModelQuery<T extends LucidModel>(className: typeof BaseModel): ModelQueryBuilderContract<T, RoleModel<T>>;
|
|
6
|
+
export declare function getModelPermissionModelQuery<T extends LucidModel>(className: typeof BaseModel): ModelQueryBuilderContract<T, ModelPermissionModel<T>>;
|
|
7
|
+
export declare function getModelRoleModelQuery<T extends LucidModel>(className: typeof BaseModel): ModelQueryBuilderContract<T, ModelRoleModel<T>>;
|
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
export function getPermissionModelQuery(
|
|
2
|
-
return
|
|
1
|
+
export function getPermissionModelQuery(className) {
|
|
2
|
+
return className.query();
|
|
3
3
|
}
|
|
4
|
-
export function getRoleModelQuery(
|
|
5
|
-
return
|
|
4
|
+
export function getRoleModelQuery(className) {
|
|
5
|
+
return className.query();
|
|
6
6
|
}
|
|
7
|
-
export function getModelPermissionModelQuery(
|
|
8
|
-
return
|
|
7
|
+
export function getModelPermissionModelQuery(className) {
|
|
8
|
+
return className.query();
|
|
9
9
|
}
|
|
10
|
-
export function getModelRoleModelQuery(
|
|
11
|
-
return
|
|
10
|
+
export function getModelRoleModelQuery(className) {
|
|
11
|
+
return className.query();
|
|
12
12
|
}
|
|
@@ -1,8 +1,12 @@
|
|
|
1
1
|
import { BaseModel } from '@adonisjs/lucid/orm';
|
|
2
|
+
import { ScopeInterface } from '../../types.js';
|
|
2
3
|
export default class EmptyRoles {
|
|
3
4
|
private roleClassName;
|
|
5
|
+
private scope;
|
|
4
6
|
private roleQuery;
|
|
5
|
-
constructor(roleClassName: typeof BaseModel);
|
|
7
|
+
constructor(roleClassName: typeof BaseModel, scope: ScopeInterface);
|
|
8
|
+
on(scope: number): this;
|
|
9
|
+
getScope(): number;
|
|
6
10
|
delete(role: string): import("@adonisjs/lucid/types/model").ModelQueryBuilderContract<import("@adonisjs/lucid/types/model").LucidModel, any>;
|
|
7
11
|
query(): import("@adonisjs/lucid/types/model").ModelQueryBuilderContract<import("@adonisjs/lucid/types/model").LucidModel, import("../../types.js").RoleModel<import("@adonisjs/lucid/types/model").LucidModel>>;
|
|
8
12
|
}
|
|
@@ -1,11 +1,20 @@
|
|
|
1
1
|
import { getRoleModelQuery } from '../query_helper.js';
|
|
2
2
|
export default class EmptyRoles {
|
|
3
3
|
roleClassName;
|
|
4
|
+
scope;
|
|
4
5
|
roleQuery;
|
|
5
|
-
constructor(roleClassName) {
|
|
6
|
+
constructor(roleClassName, scope) {
|
|
6
7
|
this.roleClassName = roleClassName;
|
|
8
|
+
this.scope = scope;
|
|
7
9
|
this.roleQuery = getRoleModelQuery(this.roleClassName);
|
|
8
10
|
}
|
|
11
|
+
on(scope) {
|
|
12
|
+
this.scope.set(scope);
|
|
13
|
+
return this;
|
|
14
|
+
}
|
|
15
|
+
getScope() {
|
|
16
|
+
return this.scope.get();
|
|
17
|
+
}
|
|
9
18
|
delete(role) {
|
|
10
19
|
// get all permissions by slug
|
|
11
20
|
// if there is permission with allowed false then check if it has `links`
|
|
@@ -1,18 +1,17 @@
|
|
|
1
1
|
import ModelService from '../model_service.js';
|
|
2
2
|
import PermissionsService from '../permissions/permissions_service.js';
|
|
3
|
-
import { AclModel, MorphInterface, PermissionInterface, RoleInterface } from '../../types.js';
|
|
3
|
+
import { AclModel, MorphInterface, PermissionInterface, RoleInterface, ScopeInterface } from '../../types.js';
|
|
4
4
|
export declare class RoleHasModelPermissions {
|
|
5
5
|
private role;
|
|
6
6
|
private permissionService;
|
|
7
7
|
private modelService;
|
|
8
8
|
private map;
|
|
9
|
-
|
|
9
|
+
private scope;
|
|
10
|
+
constructor(role: RoleInterface, permissionService: PermissionsService, modelService: ModelService, map: MorphInterface, scope: ScopeInterface);
|
|
11
|
+
on(scope: number): this;
|
|
12
|
+
getScope(): number;
|
|
10
13
|
models(): import("@adonisjs/lucid/types/model").ModelQueryBuilderContract<import("@adonisjs/lucid/types/model").LucidModel, import("../../types.js").ModelRoleModel<import("@adonisjs/lucid/types/model").LucidModel>>;
|
|
11
14
|
modelsFor(modelType: string): Promise<any>;
|
|
12
|
-
/**
|
|
13
|
-
* todo
|
|
14
|
-
* @param model
|
|
15
|
-
*/
|
|
16
15
|
permissions(): Promise<import("../../types.js").PermissionModel<import("@adonisjs/lucid/types/model").LucidModel>[]>;
|
|
17
16
|
globalPermissions(): Promise<import("../../types.js").PermissionModel<import("@adonisjs/lucid/types/model").LucidModel>[]>;
|
|
18
17
|
onResourcePermissions(): Promise<import("../../types.js").PermissionModel<import("@adonisjs/lucid/types/model").LucidModel>[]>;
|
|
@@ -52,9 +51,11 @@ export declare class RoleHasModelPermissions {
|
|
|
52
51
|
canAny(permissions: (string | PermissionInterface)[]): Promise<boolean>;
|
|
53
52
|
forbidden(permission: string | PermissionInterface, target?: AclModel | Function): Promise<boolean>;
|
|
54
53
|
assign(permission: string, target?: AclModel | Function): Promise<import("@adonisjs/lucid/types/model").LucidRow[]>;
|
|
54
|
+
allow(permission: string, target?: AclModel | Function): Promise<import("@adonisjs/lucid/types/model").LucidRow[]>;
|
|
55
55
|
give(permission: string, target?: AclModel | Function): Promise<import("@adonisjs/lucid/types/model").LucidRow[]>;
|
|
56
56
|
giveAll(permissions: string[], target?: AclModel | Function): Promise<import("@adonisjs/lucid/types/model").LucidRow[]>;
|
|
57
57
|
assingAll(permissions: string[], target?: AclModel | Function): Promise<import("@adonisjs/lucid/types/model").LucidRow[]>;
|
|
58
|
+
allowAll(permissions: string[], target?: AclModel | Function): Promise<import("@adonisjs/lucid/types/model").LucidRow[]>;
|
|
58
59
|
revokePermission(permission: string): Promise<any[]>;
|
|
59
60
|
revoke(permission: string): Promise<any[]>;
|
|
60
61
|
revokeAll(permissions: string[], target?: AclModel | Function): Promise<any[]>;
|
|
@@ -4,11 +4,20 @@ export class RoleHasModelPermissions {
|
|
|
4
4
|
permissionService;
|
|
5
5
|
modelService;
|
|
6
6
|
map;
|
|
7
|
-
|
|
7
|
+
scope;
|
|
8
|
+
constructor(role, permissionService, modelService, map, scope) {
|
|
8
9
|
this.role = role;
|
|
9
10
|
this.permissionService = permissionService;
|
|
10
11
|
this.modelService = modelService;
|
|
11
12
|
this.map = map;
|
|
13
|
+
this.scope = scope;
|
|
14
|
+
}
|
|
15
|
+
on(scope) {
|
|
16
|
+
this.scope.set(scope);
|
|
17
|
+
return this;
|
|
18
|
+
}
|
|
19
|
+
getScope() {
|
|
20
|
+
return this.scope.get();
|
|
12
21
|
}
|
|
13
22
|
models() {
|
|
14
23
|
return this.modelService.all(this.role.getModelId());
|
|
@@ -16,11 +25,6 @@ export class RoleHasModelPermissions {
|
|
|
16
25
|
modelsFor(modelType) {
|
|
17
26
|
return this.modelService.allFor(modelType, this.role.getModelId());
|
|
18
27
|
}
|
|
19
|
-
/**
|
|
20
|
-
* todo
|
|
21
|
-
* @param model
|
|
22
|
-
*/
|
|
23
|
-
// attachTo(model: LucidModel) {}
|
|
24
28
|
// permissions related BEGIN
|
|
25
29
|
async permissions() {
|
|
26
30
|
// for roles direct and all permissions are same
|
|
@@ -100,6 +104,9 @@ export class RoleHasModelPermissions {
|
|
|
100
104
|
assign(permission, target) {
|
|
101
105
|
return this.give(permission, target);
|
|
102
106
|
}
|
|
107
|
+
allow(permission, target) {
|
|
108
|
+
return this.give(permission, target);
|
|
109
|
+
}
|
|
103
110
|
async give(permission, target) {
|
|
104
111
|
const entity = await destructTarget(this.map, target);
|
|
105
112
|
return this.permissionService.giveAll(this.map.getAlias(this.role), this.role.getModelId(), [permission], entity.targetClass, entity.targetId, true);
|
|
@@ -111,6 +118,9 @@ export class RoleHasModelPermissions {
|
|
|
111
118
|
assingAll(permissions, target) {
|
|
112
119
|
return this.giveAll(permissions, target);
|
|
113
120
|
}
|
|
121
|
+
allowAll(permissions, target) {
|
|
122
|
+
return this.giveAll(permissions, target);
|
|
123
|
+
}
|
|
114
124
|
async revokePermission(permission) {
|
|
115
125
|
return this.revoke(permission);
|
|
116
126
|
}
|
|
@@ -1,19 +1,22 @@
|
|
|
1
|
-
import { AclModel, MorphInterface, RoleInterface } from '../../types.js';
|
|
1
|
+
import { AclModel, MorphInterface, RoleInterface, ScopeInterface } from '../../types.js';
|
|
2
2
|
import BaseService from '../base_service.js';
|
|
3
3
|
import { BaseModel } from '@adonisjs/lucid/orm';
|
|
4
|
+
import { ModelQueryBuilderContract } from '@adonisjs/lucid/types/model';
|
|
4
5
|
export default class RolesService extends BaseService {
|
|
5
6
|
private roleClassName;
|
|
6
7
|
private modelPermissionClassName;
|
|
7
8
|
private modelRoleClassName;
|
|
8
9
|
private map;
|
|
10
|
+
private scope;
|
|
9
11
|
private roleQuery;
|
|
10
12
|
private readonly roleTable;
|
|
11
13
|
private readonly modelPermissionTable;
|
|
12
14
|
private modelRoleQuery;
|
|
13
15
|
private readonly modelRoleTable;
|
|
14
|
-
|
|
16
|
+
private currentScope;
|
|
17
|
+
constructor(roleClassName: typeof BaseModel, modelPermissionClassName: typeof BaseModel, modelRoleClassName: typeof BaseModel, map: MorphInterface, scope: ScopeInterface);
|
|
15
18
|
private modelRolesQuery;
|
|
16
|
-
all(modelType: string, modelId: number):
|
|
19
|
+
all(modelType: string, modelId: number): ModelQueryBuilderContract<import("@adonisjs/lucid/types/model").LucidModel, import("../../types.js").RoleModel<import("@adonisjs/lucid/types/model").LucidModel>>;
|
|
17
20
|
has(modelType: string, modelId: number, role: string | RoleInterface): Promise<boolean>;
|
|
18
21
|
hasAll(modelType: string, modelId: number, roles: (string | RoleInterface)[]): Promise<boolean>;
|
|
19
22
|
hasAny(modelType: string, modelId: number, roles: (string | RoleInterface)[]): Promise<boolean>;
|
|
@@ -22,6 +25,8 @@ export default class RolesService extends BaseService {
|
|
|
22
25
|
revoke(role: string | number, model: AclModel): Promise<boolean>;
|
|
23
26
|
revokeAll(roles: (string | number)[], model: AclModel): Promise<boolean>;
|
|
24
27
|
private extractRoleModel;
|
|
25
|
-
roleModelPermissionQuery(modelType: string):
|
|
26
|
-
flush(modelType: string, modelId: number):
|
|
28
|
+
roleModelPermissionQuery(modelType: string): ModelQueryBuilderContract<import("@adonisjs/lucid/types/model").LucidModel, import("../../types.js").RoleModel<import("@adonisjs/lucid/types/model").LucidModel>>;
|
|
29
|
+
flush(modelType: string, modelId: number): ModelQueryBuilderContract<import("@adonisjs/lucid/types/model").LucidModel, any>;
|
|
30
|
+
private applyScopes;
|
|
31
|
+
private applyModelRoleScopes;
|
|
27
32
|
}
|
|
@@ -9,6 +9,7 @@ export default class RolesService extends BaseService {
|
|
|
9
9
|
modelPermissionClassName;
|
|
10
10
|
modelRoleClassName;
|
|
11
11
|
map;
|
|
12
|
+
scope;
|
|
12
13
|
// private permissionQuery
|
|
13
14
|
// private readonly permissionTable
|
|
14
15
|
roleQuery;
|
|
@@ -17,18 +18,22 @@ export default class RolesService extends BaseService {
|
|
|
17
18
|
modelPermissionTable;
|
|
18
19
|
modelRoleQuery;
|
|
19
20
|
modelRoleTable;
|
|
21
|
+
currentScope;
|
|
20
22
|
constructor(roleClassName,
|
|
21
23
|
// private permissionClassName: typeof BaseModel,
|
|
22
|
-
modelPermissionClassName, modelRoleClassName, map) {
|
|
24
|
+
modelPermissionClassName, modelRoleClassName, map, scope) {
|
|
23
25
|
super();
|
|
24
26
|
this.roleClassName = roleClassName;
|
|
25
27
|
this.modelPermissionClassName = modelPermissionClassName;
|
|
26
28
|
this.modelRoleClassName = modelRoleClassName;
|
|
27
29
|
this.map = map;
|
|
30
|
+
this.scope = scope;
|
|
28
31
|
// this.permissionQuery = getPermissionModelQuery(this.permissionClassName)
|
|
29
32
|
// this.permissionTable = this.permissionClassName.table
|
|
33
|
+
this.currentScope = this.scope.get();
|
|
30
34
|
this.roleQuery = getRoleModelQuery(this.roleClassName);
|
|
31
35
|
this.roleTable = this.roleClassName.table;
|
|
36
|
+
this.applyScopes(this.roleQuery, this.currentScope);
|
|
32
37
|
// this.modelPermissionQuery = getModelPermissionModelQuery(this.modelPermissionClassName)
|
|
33
38
|
this.modelPermissionTable = this.modelPermissionClassName.table;
|
|
34
39
|
this.modelRoleQuery = getModelRoleModelQuery(this.modelRoleClassName);
|
|
@@ -36,12 +41,14 @@ export default class RolesService extends BaseService {
|
|
|
36
41
|
}
|
|
37
42
|
modelRolesQuery(modelType, modelId) {
|
|
38
43
|
return this.roleQuery
|
|
39
|
-
.
|
|
44
|
+
.leftJoin(this.modelRoleTable + ' as mr', 'mr.role_id', '=', this.roleTable + '.id')
|
|
40
45
|
.where('mr.model_type', modelType)
|
|
41
46
|
.where('mr.model_id', modelId);
|
|
42
47
|
}
|
|
43
48
|
all(modelType, modelId) {
|
|
44
|
-
return this.modelRolesQuery(modelType, modelId)
|
|
49
|
+
return this.modelRolesQuery(modelType, modelId)
|
|
50
|
+
.distinct(this.roleTable + '.id')
|
|
51
|
+
.select(this.roleTable + '.*');
|
|
45
52
|
}
|
|
46
53
|
has(modelType, modelId, role) {
|
|
47
54
|
return this.hasAll(modelType, modelId, [role]);
|
|
@@ -74,29 +81,30 @@ export default class RolesService extends BaseService {
|
|
|
74
81
|
// @ts-ignore
|
|
75
82
|
return +r[0].$extras.total > 0;
|
|
76
83
|
}
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
if (!r.length) {
|
|
80
|
-
throw new Error('Role not found');
|
|
81
|
-
}
|
|
82
|
-
await this.modelRoleClassName.create({
|
|
83
|
-
modelType,
|
|
84
|
-
modelId,
|
|
85
|
-
roleId: r[0].id,
|
|
86
|
-
});
|
|
87
|
-
return true;
|
|
84
|
+
assign(role, modelType, modelId) {
|
|
85
|
+
return this.assignAll([role], modelType, modelId);
|
|
88
86
|
}
|
|
89
87
|
async assignAll(roles, modelType, modelId) {
|
|
90
88
|
const rs = await this.extractRoleModel(roles);
|
|
91
89
|
if (!rs.length) {
|
|
92
90
|
throw new Error('One or many roles not found');
|
|
93
91
|
}
|
|
92
|
+
let roleIds = rs.map((role) => role.id);
|
|
93
|
+
const modelRoles = await this.modelRoleQuery
|
|
94
|
+
.whereIn('role_id', roleIds)
|
|
95
|
+
.where('model_type', modelType)
|
|
96
|
+
.where('model_id', modelId)
|
|
97
|
+
.select('id');
|
|
98
|
+
const modelRoleIds = modelRoles.map((modelRole) => modelRole.id);
|
|
99
|
+
roleIds = roleIds.filter((roleId) => {
|
|
100
|
+
return !modelRoleIds.includes(roleId);
|
|
101
|
+
});
|
|
94
102
|
const data = [];
|
|
95
|
-
for (const
|
|
103
|
+
for (const id of roleIds) {
|
|
96
104
|
data.push({
|
|
97
105
|
modelType,
|
|
98
106
|
modelId,
|
|
99
|
-
roleId:
|
|
107
|
+
roleId: id,
|
|
100
108
|
});
|
|
101
109
|
}
|
|
102
110
|
await this.modelRoleClassName.createMany(data);
|
|
@@ -107,14 +115,15 @@ export default class RolesService extends BaseService {
|
|
|
107
115
|
}
|
|
108
116
|
async revokeAll(roles, model) {
|
|
109
117
|
const { slugs, ids } = this.formatListStringNumbers(roles);
|
|
110
|
-
|
|
118
|
+
const q = this.modelRoleQuery
|
|
111
119
|
.leftJoin(this.roleTable + ' as r', 'r.id', '=', this.modelRoleTable + '.role_id')
|
|
112
120
|
.where('model_type', this.map.getAlias(model))
|
|
113
121
|
.where('model_id', model.getModelId())
|
|
114
122
|
.where((query) => {
|
|
115
123
|
query.whereIn('r.id', ids).orWhereIn('r.slug', slugs);
|
|
116
|
-
})
|
|
117
|
-
|
|
124
|
+
});
|
|
125
|
+
this.applyModelRoleScopes(q, 'r', this.currentScope);
|
|
126
|
+
await q.delete();
|
|
118
127
|
return true;
|
|
119
128
|
}
|
|
120
129
|
async extractRoleModel(roles) {
|
|
@@ -139,4 +148,10 @@ export default class RolesService extends BaseService {
|
|
|
139
148
|
flush(modelType, modelId) {
|
|
140
149
|
return this.modelRoleQuery.where('model_type', modelType).where('model_id', modelId).delete();
|
|
141
150
|
}
|
|
151
|
+
applyScopes(q, scope) {
|
|
152
|
+
q.where(this.roleTable + '.scope', scope);
|
|
153
|
+
}
|
|
154
|
+
applyModelRoleScopes(q, table, scope) {
|
|
155
|
+
q.where(table + '.scope', scope);
|
|
156
|
+
}
|
|
142
157
|
}
|
package/build/src/types.d.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { LucidModel } from '@adonisjs/lucid/types/model';
|
|
2
2
|
import { DateTime } from 'luxon';
|
|
3
|
+
import { BaseModel } from '@adonisjs/lucid/orm';
|
|
4
|
+
import { Scope } from './scope.js';
|
|
3
5
|
export interface AclModelInterface {
|
|
4
6
|
getModelId(): number;
|
|
5
7
|
}
|
|
@@ -60,6 +62,7 @@ export interface ModelPermissionsQuery extends AclModelQuery {
|
|
|
60
62
|
directPermissions: boolean;
|
|
61
63
|
includeForbiddings: boolean;
|
|
62
64
|
entity: Entity;
|
|
65
|
+
throughRoles: boolean;
|
|
63
66
|
}
|
|
64
67
|
export interface MorphMapInterface {
|
|
65
68
|
[key: string]: any;
|
|
@@ -72,10 +75,28 @@ export interface MorphInterface {
|
|
|
72
75
|
getAlias(target: any): string;
|
|
73
76
|
}
|
|
74
77
|
export interface ModelManagerInterface {
|
|
75
|
-
[key: string]:
|
|
78
|
+
[key: string]: any;
|
|
76
79
|
}
|
|
77
80
|
export interface Permissions {
|
|
78
81
|
tables: Object;
|
|
79
82
|
morphMaps: Object;
|
|
80
83
|
}
|
|
84
|
+
export interface ScopeInterface {
|
|
85
|
+
set(scope: number): ScopeInterface;
|
|
86
|
+
get(): number;
|
|
87
|
+
default(): number;
|
|
88
|
+
}
|
|
89
|
+
export interface ModelManagerBindings {
|
|
90
|
+
scope: typeof Scope;
|
|
91
|
+
role: typeof BaseModel;
|
|
92
|
+
permission: typeof BaseModel;
|
|
93
|
+
modelRole: typeof BaseModel;
|
|
94
|
+
modelPermission: typeof BaseModel;
|
|
95
|
+
}
|
|
96
|
+
export interface AclMiddlewareOptions {
|
|
97
|
+
role: string;
|
|
98
|
+
permission: string;
|
|
99
|
+
scope: number;
|
|
100
|
+
method: string;
|
|
101
|
+
}
|
|
81
102
|
export {};
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
{{{
|
|
2
|
+
exports({ to: app.middlewarePath('', 'acl_middleware.ts') })
|
|
3
|
+
}}}
|
|
4
|
+
import type { HttpContext } from '@adonisjs/core/http'
|
|
5
|
+
import type { NextFn } from '@adonisjs/core/types/http'
|
|
6
|
+
import { AclManager, Scope } from '@holoyan/adonisjs-permissions'
|
|
7
|
+
|
|
8
|
+
declare module '@adonisjs/core/http' {
|
|
9
|
+
export interface HttpContext {
|
|
10
|
+
acl: AclManager
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export default class UserScopeMiddleware {
|
|
15
|
+
//@ts-ignore
|
|
16
|
+
async handle(ctx: HttpContext, next: NextFn) {
|
|
17
|
+
const scope = new Scope()
|
|
18
|
+
ctx.acl = new AclManager().scope(scope)
|
|
19
|
+
/**
|
|
20
|
+
* Call next method in the pipeline and return its output
|
|
21
|
+
*/
|
|
22
|
+
const output = await next()
|
|
23
|
+
return output
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|