@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.
Files changed (31) hide show
  1. package/README.md +277 -97
  2. package/build/configure.js +9 -0
  3. package/build/index.d.ts +2 -1
  4. package/build/index.js +2 -1
  5. package/build/providers/role_permission_provider.js +5 -3
  6. package/build/src/acl.d.ts +14 -6
  7. package/build/src/acl.js +33 -12
  8. package/build/src/mixins/has_permissions.d.ts +1 -2
  9. package/build/src/mixins/has_permissions.js +0 -3
  10. package/build/src/model_manager.d.ts +3 -3
  11. package/build/src/scope.d.ts +7 -0
  12. package/build/src/scope.js +14 -0
  13. package/build/src/services/model_has_role_permissions.d.ts +12 -3
  14. package/build/src/services/model_has_role_permissions.js +29 -2
  15. package/build/src/services/permissions/empty_permission.d.ts +5 -1
  16. package/build/src/services/permissions/empty_permission.js +10 -1
  17. package/build/src/services/permissions/permission_has_model_roles.d.ts +5 -2
  18. package/build/src/services/permissions/permission_has_model_roles.js +10 -1
  19. package/build/src/services/permissions/permissions_service.d.ts +11 -3
  20. package/build/src/services/permissions/permissions_service.js +58 -13
  21. package/build/src/services/query_helper.d.ts +4 -4
  22. package/build/src/services/query_helper.js +8 -8
  23. package/build/src/services/roles/empty_roles.d.ts +5 -1
  24. package/build/src/services/roles/empty_roles.js +10 -1
  25. package/build/src/services/roles/role_has_model_permissions.d.ts +7 -6
  26. package/build/src/services/roles/role_has_model_permissions.js +16 -6
  27. package/build/src/services/roles/roles_service.d.ts +10 -5
  28. package/build/src/services/roles/roles_service.js +34 -19
  29. package/build/src/types.d.ts +22 -1
  30. package/build/stubs/middlewares/acl_middleware.stub +26 -0
  31. 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
- permissionQuery;
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.permissionQuery = getPermissionModelQuery(this.permissionClassName);
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
- .whereNotNull(this.permissionTable + '.entity_id')
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>(permissionClassName: typeof BaseModel): ModelQueryBuilderContract<T, PermissionModel<T>>;
5
- export declare function getRoleModelQuery<T extends LucidModel>(permissionClassName: typeof BaseModel): ModelQueryBuilderContract<T, RoleModel<T>>;
6
- export declare function getModelPermissionModelQuery<T extends LucidModel>(permissionClassName: typeof BaseModel): ModelQueryBuilderContract<T, ModelPermissionModel<T>>;
7
- export declare function getModelRoleModelQuery<T extends LucidModel>(permissionClassName: typeof BaseModel): ModelQueryBuilderContract<T, ModelRoleModel<T>>;
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(permissionClassName) {
2
- return permissionClassName.query();
1
+ export function getPermissionModelQuery(className) {
2
+ return className.query();
3
3
  }
4
- export function getRoleModelQuery(permissionClassName) {
5
- return permissionClassName.query();
4
+ export function getRoleModelQuery(className) {
5
+ return className.query();
6
6
  }
7
- export function getModelPermissionModelQuery(permissionClassName) {
8
- return permissionClassName.query();
7
+ export function getModelPermissionModelQuery(className) {
8
+ return className.query();
9
9
  }
10
- export function getModelRoleModelQuery(permissionClassName) {
11
- return permissionClassName.query();
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
- constructor(role: RoleInterface, permissionService: PermissionsService, modelService: ModelService, map: MorphInterface);
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
- constructor(role, permissionService, modelService, map) {
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
- constructor(roleClassName: typeof BaseModel, modelPermissionClassName: typeof BaseModel, modelRoleClassName: typeof BaseModel, map: MorphInterface);
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): import("@adonisjs/lucid/types/model").ModelQueryBuilderContract<import("@adonisjs/lucid/types/model").LucidModel, import("../../types.js").RoleModel<import("@adonisjs/lucid/types/model").LucidModel>>;
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): import("@adonisjs/lucid/types/model").ModelQueryBuilderContract<import("@adonisjs/lucid/types/model").LucidModel, import("../../types.js").RoleModel<import("@adonisjs/lucid/types/model").LucidModel>>;
26
- flush(modelType: string, modelId: number): import("@adonisjs/lucid/types/model").ModelQueryBuilderContract<import("@adonisjs/lucid/types/model").LucidModel, any>;
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
- .join(this.modelRoleTable + ' as mr', 'mr.role_id', '=', this.roleTable + '.id')
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).select(this.roleTable + '.*');
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
- async assign(role, modelType, modelId) {
78
- const r = await this.extractRoleModel([role]);
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 r of rs) {
103
+ for (const id of roleIds) {
96
104
  data.push({
97
105
  modelType,
98
106
  modelId,
99
- roleId: r.id,
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
- await this.modelRoleQuery
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
- .delete();
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
  }
@@ -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]: LucidModel;
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
+
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@holoyan/adonisjs-permissions",
3
3
  "description": "Adonisjs roles and permissions system",
4
- "version": "0.5.0",
4
+ "version": "0.6.4",
5
5
  "engines": {
6
6
  "node": ">=18.16.0"
7
7
  },