mongodb-dynamic-api 2.1.5 → 2.1.7
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/CHANGELOG.md +4 -0
- package/package.json +2 -2
- package/src/builders/index.d.ts +0 -1
- package/src/builders/index.js +0 -1
- package/src/builders/route-decorators/route-decorators.builder.d.ts +0 -1
- package/src/decorators/index.d.ts +0 -1
- package/src/decorators/index.js +0 -1
- package/src/dynamic-api.module.d.ts +2 -0
- package/src/dynamic-api.module.js +39 -29
- package/src/guards/base-policies.guard.d.ts +7 -8
- package/src/guards/base-policies.guard.js +17 -22
- package/src/helpers/controller-ability-predicates.helper.d.ts +2 -2
- package/src/helpers/controller-mixin.helper.d.ts +4 -28
- package/src/helpers/controller-mixin.helper.js +6 -16
- package/src/helpers/format.helper.d.ts +2 -0
- package/src/helpers/format.helper.js +6 -1
- package/src/interfaces/dynamic-api-ability.interface.d.ts +9 -0
- package/src/interfaces/dynamic-api-ability.interface.js +2 -0
- package/src/interfaces/dynamic-api-controller-options.interface.d.ts +1 -1
- package/src/interfaces/dynamic-api-policy-handler.interface.d.ts +4 -10
- package/src/interfaces/dynamic-api-route-config.interface.d.ts +2 -2
- package/src/interfaces/index.d.ts +1 -1
- package/src/interfaces/index.js +1 -1
- package/src/mixins/create-policies-guard.mixin.d.ts +3 -2
- package/src/mixins/create-policies-guard.mixin.js +9 -6
- package/src/modules/auth/mixins/auth-controller.mixin.js +6 -1
- package/src/modules/auth/mixins/auth-register-policies-guard.mixin.d.ts +2 -3
- package/src/modules/auth/mixins/auth-register-policies-guard.mixin.js +6 -35
- package/src/modules/auth/services/base-auth.service.d.ts +0 -1
- package/src/modules/auth/services/base-auth.service.js +3 -6
- package/src/routes/create-many/create-many-controller.mixin.js +0 -2
- package/src/routes/create-many/create-many.helper.js +2 -2
- package/src/routes/create-one/create-one-controller.mixin.js +0 -2
- package/src/routes/create-one/create-one.helper.js +2 -2
- package/src/routes/delete-many/delete-many-controller.mixin.js +0 -2
- package/src/routes/delete-many/delete-many.helper.js +2 -2
- package/src/routes/delete-one/delete-one-controller.mixin.js +0 -2
- package/src/routes/delete-one/delete-one.helper.js +2 -2
- package/src/routes/duplicate-many/duplicate-many-controller.mixin.js +0 -2
- package/src/routes/duplicate-many/duplicate-many.helper.js +2 -2
- package/src/routes/duplicate-one/duplicate-one-controller.mixin.js +0 -2
- package/src/routes/duplicate-one/duplicate-one.helper.js +2 -2
- package/src/routes/get-many/get-many-controller.mixin.js +9 -6
- package/src/routes/get-many/get-many.helper.js +2 -2
- package/src/routes/get-one/get-one-controller.mixin.js +1 -4
- package/src/routes/get-one/get-one.helper.js +2 -2
- package/src/routes/replace-one/replace-one-controller.mixin.js +1 -3
- package/src/routes/replace-one/replace-one.helper.js +2 -2
- package/src/routes/update-many/update-many-controller.mixin.js +1 -3
- package/src/routes/update-many/update-many.helper.js +2 -2
- package/src/routes/update-one/update-one-controller.mixin.js +1 -3
- package/src/routes/update-one/update-one.helper.js +2 -2
- package/src/services/base/base.service.d.ts +7 -1
- package/src/services/base/base.service.js +32 -0
- package/src/version.json +1 -1
- package/tsconfig.tsbuildinfo +1 -1
- package/src/builders/casl/casl-ability.builder.d.ts +0 -5
- package/src/builders/casl/casl-ability.builder.js +0 -17
- package/src/decorators/check-policies.decorator.d.ts +0 -5
- package/src/decorators/check-policies.decorator.js +0 -8
- package/src/interfaces/dynamic-api-casl-ability.interface.d.ts +0 -12
- package/src/interfaces/dynamic-api-casl-ability.interface.js +0 -5
- package/src/routes/delete-many/delete-many.presenter.d.ts +0 -3
- package/src/routes/delete-many/delete-many.presenter.js +0 -20
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
Changelog
|
|
2
2
|
|
|
3
|
+
## [2.1.7](https://github.com/MikeDev75015/mongodb-dynamic-api/compare/v2.1.6...v2.1.7) (2024-04-01)
|
|
4
|
+
|
|
5
|
+
## [2.1.6](https://github.com/MikeDev75015/mongodb-dynamic-api/compare/v2.1.5...v2.1.6) (2024-03-31)
|
|
6
|
+
|
|
3
7
|
## [2.1.5](https://github.com/MikeDev75015/mongodb-dynamic-api/compare/v2.1.4...v2.1.5) (2024-03-29)
|
|
4
8
|
|
|
5
9
|
## [2.1.4](https://github.com/MikeDev75015/mongodb-dynamic-api/compare/v2.1.3...v2.1.4) (2024-03-29)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mongodb-dynamic-api",
|
|
3
|
-
"version": "2.1.
|
|
3
|
+
"version": "2.1.7",
|
|
4
4
|
"description": "Auto generated CRUD API for MongoDB using NestJS",
|
|
5
5
|
"readmeFilename": "README.md",
|
|
6
6
|
"main": "index.js",
|
|
@@ -38,7 +38,6 @@
|
|
|
38
38
|
},
|
|
39
39
|
"homepage": "https://mikedev75015.github.io",
|
|
40
40
|
"dependencies": {
|
|
41
|
-
"@casl/ability": "^6.7.0",
|
|
42
41
|
"@nestjs/cache-manager": "^2.2.1",
|
|
43
42
|
"@nestjs/common": "^10.3.2",
|
|
44
43
|
"@nestjs/core": "^10.3.2",
|
|
@@ -84,6 +83,7 @@
|
|
|
84
83
|
"eslint-plugin-prettier": "^5.1.3",
|
|
85
84
|
"jest": "^29.7.0",
|
|
86
85
|
"jest-junit": "^16.0.0",
|
|
86
|
+
"jest-mock-extended": "^3.0.5",
|
|
87
87
|
"jest-sonar-reporter": "^2.0.0",
|
|
88
88
|
"prettier": "^3.2.5",
|
|
89
89
|
"release-it": "^17.1.1",
|
package/src/builders/index.d.ts
CHANGED
package/src/builders/index.js
CHANGED
|
@@ -14,6 +14,5 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
14
14
|
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
15
|
};
|
|
16
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
-
__exportStar(require("./casl/casl-ability.builder"), exports);
|
|
18
17
|
__exportStar(require("./route-decorators/auth-decorators.builder"), exports);
|
|
19
18
|
__exportStar(require("./route-decorators/route-decorators.builder"), exports);
|
|
@@ -12,7 +12,6 @@ declare class RouteDecoratorsBuilder<Entity extends BaseEntity> implements Dynam
|
|
|
12
12
|
private readonly bodyRouteTypeIsOptional;
|
|
13
13
|
constructor(routeType: RouteType, entity: Type<Entity>, version: string | undefined, description: string | undefined, isPublic: boolean | undefined, dTOs?: {
|
|
14
14
|
param?: Type;
|
|
15
|
-
query?: Type;
|
|
16
15
|
body?: Type;
|
|
17
16
|
presenter?: Type;
|
|
18
17
|
});
|
package/src/decorators/index.js
CHANGED
|
@@ -14,6 +14,5 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
14
14
|
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
15
|
};
|
|
16
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
-
__exportStar(require("./check-policies.decorator"), exports);
|
|
18
17
|
__exportStar(require("./public.decorator"), exports);
|
|
19
18
|
__exportStar(require("./schema-options.decorator"), exports);
|
|
@@ -6,5 +6,7 @@ export declare class DynamicApiModule {
|
|
|
6
6
|
static readonly state: DynamicApiGlobalStateService;
|
|
7
7
|
static forRoot(uri: string, { useGlobalCache, cacheOptions, useAuth, }?: DynamicApiForRootOptions): DynamicModule;
|
|
8
8
|
static forFeature<Entity extends BaseEntity>({ entity, controllerOptions, routes, }: DynamicApiForFeatureOptions<Entity>): Promise<DynamicModule>;
|
|
9
|
+
private static buildStateFromOptions;
|
|
10
|
+
private static initializeAuthOptions;
|
|
9
11
|
private static setDefaultRoutesIfNotConfigured;
|
|
10
12
|
}
|
|
@@ -27,19 +27,8 @@ let DynamicApiModule = DynamicApiModule_1 = class DynamicApiModule {
|
|
|
27
27
|
throw new Error('You must provide a valid mongodb uri in the forRoot method to use MongoDB Dynamic API');
|
|
28
28
|
}
|
|
29
29
|
this.state.set([
|
|
30
|
-
'partial',
|
|
31
|
-
|
|
32
|
-
isGlobalCacheEnabled: useGlobalCache,
|
|
33
|
-
...(cacheOptions?.excludePaths ? { cacheExcludedPaths: cacheOptions?.excludePaths } : {}),
|
|
34
|
-
...(useAuth?.user ? {
|
|
35
|
-
isAuthEnabled: true,
|
|
36
|
-
credentials: {
|
|
37
|
-
loginField: !useAuth.user.loginField ? 'email' : String(useAuth.user.loginField),
|
|
38
|
-
passwordField: !useAuth.user.passwordField ? 'password' : String(useAuth.user.passwordField),
|
|
39
|
-
},
|
|
40
|
-
jwtSecret: useAuth.jwt?.secret ?? 'dynamic-api-jwt-secret',
|
|
41
|
-
} : {}),
|
|
42
|
-
},
|
|
30
|
+
'partial',
|
|
31
|
+
this.buildStateFromOptions(useGlobalCache, cacheOptions, useAuth),
|
|
43
32
|
]);
|
|
44
33
|
return {
|
|
45
34
|
module: DynamicApiModule_1,
|
|
@@ -48,22 +37,7 @@ let DynamicApiModule = DynamicApiModule_1 = class DynamicApiModule {
|
|
|
48
37
|
cache_manager_1.CacheModule.register({ isGlobal: true, ...cacheOptions }),
|
|
49
38
|
mongoose_1.MongooseModule.forRoot(uri, { connectionName: this.state.get('connectionName') }),
|
|
50
39
|
...(useAuth?.user ? [
|
|
51
|
-
modules_1.AuthModule.forRoot(
|
|
52
|
-
user: {
|
|
53
|
-
entity: useAuth.user.entity,
|
|
54
|
-
loginField: useAuth.user.loginField ?? 'email',
|
|
55
|
-
passwordField: useAuth.user.passwordField ?? 'password',
|
|
56
|
-
requestAdditionalFields: useAuth.user.requestAdditionalFields ?? [],
|
|
57
|
-
},
|
|
58
|
-
jwt: {
|
|
59
|
-
secret: useAuth.jwt?.secret ?? 'dynamic-api-jwt-secret',
|
|
60
|
-
expiresIn: useAuth.jwt?.expiresIn ?? '1d',
|
|
61
|
-
},
|
|
62
|
-
register: useAuth.register ?? {
|
|
63
|
-
protected: false,
|
|
64
|
-
additionalFields: [],
|
|
65
|
-
},
|
|
66
|
-
}),
|
|
40
|
+
modules_1.AuthModule.forRoot(this.initializeAuthOptions(useAuth)),
|
|
67
41
|
] : []),
|
|
68
42
|
],
|
|
69
43
|
exports: [modules_1.DynamicApiConfigModule],
|
|
@@ -144,6 +118,42 @@ let DynamicApiModule = DynamicApiModule_1 = class DynamicApiModule {
|
|
|
144
118
|
}, 5000);
|
|
145
119
|
});
|
|
146
120
|
}
|
|
121
|
+
static buildStateFromOptions(useGlobalCache, cacheOptions, useAuth) {
|
|
122
|
+
return {
|
|
123
|
+
initialized: true,
|
|
124
|
+
isGlobalCacheEnabled: useGlobalCache,
|
|
125
|
+
...(cacheOptions?.excludePaths ? { cacheExcludedPaths: cacheOptions?.excludePaths } : {}),
|
|
126
|
+
...(useAuth?.user ? {
|
|
127
|
+
isAuthEnabled: true,
|
|
128
|
+
credentials: {
|
|
129
|
+
loginField: !useAuth.user.loginField ? 'email' : String(useAuth.user.loginField),
|
|
130
|
+
passwordField: !useAuth.user.passwordField ? 'password' : String(useAuth.user.passwordField),
|
|
131
|
+
},
|
|
132
|
+
jwtSecret: useAuth.jwt?.secret ?? 'dynamic-api-jwt-secret',
|
|
133
|
+
} : {}),
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
static initializeAuthOptions(useAuth) {
|
|
137
|
+
return {
|
|
138
|
+
user: {
|
|
139
|
+
entity: useAuth.user.entity,
|
|
140
|
+
loginField: useAuth.user.loginField ?? 'email',
|
|
141
|
+
passwordField: useAuth.user.passwordField ?? 'password',
|
|
142
|
+
requestAdditionalFields: useAuth.user.requestAdditionalFields ?? [],
|
|
143
|
+
},
|
|
144
|
+
jwt: {
|
|
145
|
+
secret: useAuth.jwt?.secret ?? 'dynamic-api-jwt-secret',
|
|
146
|
+
expiresIn: useAuth.jwt?.expiresIn ?? '1d',
|
|
147
|
+
},
|
|
148
|
+
register: useAuth.register ? {
|
|
149
|
+
...useAuth.register,
|
|
150
|
+
protected: useAuth.register.protected ?? !!useAuth.register.abilityPredicate,
|
|
151
|
+
} : {
|
|
152
|
+
protected: false,
|
|
153
|
+
additionalFields: [],
|
|
154
|
+
},
|
|
155
|
+
};
|
|
156
|
+
}
|
|
147
157
|
static setDefaultRoutesIfNotConfigured(routes) {
|
|
148
158
|
if (!routes.length) {
|
|
149
159
|
return [
|
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
import { CanActivate, ExecutionContext, Type } from '@nestjs/common';
|
|
2
|
-
import {
|
|
3
|
-
import { RouteAbilityPredicate, RouteType } from '../interfaces';
|
|
2
|
+
import { AbilityPredicate, RouteType } from '../interfaces';
|
|
4
3
|
import { BaseEntity } from '../models';
|
|
5
|
-
|
|
6
|
-
|
|
4
|
+
import { BaseService } from '../services';
|
|
5
|
+
export declare abstract class BasePoliciesGuard<Entity extends BaseEntity, Service extends BaseService<Entity>> implements CanActivate {
|
|
6
|
+
protected readonly service: Service;
|
|
7
7
|
protected routeType: RouteType;
|
|
8
8
|
protected entity: Type<Entity>;
|
|
9
|
-
protected abilityPredicate:
|
|
10
|
-
protected constructor(
|
|
11
|
-
canActivate(context: ExecutionContext): boolean
|
|
12
|
-
private execPolicyHandler;
|
|
9
|
+
protected abilityPredicate: AbilityPredicate<Entity> | undefined;
|
|
10
|
+
protected constructor(service: Service);
|
|
11
|
+
canActivate(context: ExecutionContext): Promise<boolean>;
|
|
13
12
|
}
|
|
@@ -2,31 +2,26 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.BasePoliciesGuard = void 0;
|
|
4
4
|
const common_1 = require("@nestjs/common");
|
|
5
|
-
const builders_1 = require("../builders");
|
|
6
|
-
const decorators_1 = require("../decorators");
|
|
7
5
|
class BasePoliciesGuard {
|
|
8
|
-
constructor(
|
|
9
|
-
this.
|
|
6
|
+
constructor(service) {
|
|
7
|
+
this.service = service;
|
|
10
8
|
}
|
|
11
|
-
canActivate(context) {
|
|
12
|
-
|
|
13
|
-
if (
|
|
14
|
-
|
|
9
|
+
async canActivate(context) {
|
|
10
|
+
let { user, query, params } = context.switchToHttp().getRequest();
|
|
11
|
+
if (this.abilityPredicate) {
|
|
12
|
+
if (!user) {
|
|
13
|
+
throw new common_1.ForbiddenException('Access Denied');
|
|
14
|
+
}
|
|
15
|
+
this.service.abilityPredicate = this.abilityPredicate;
|
|
16
|
+
this.service.user = user;
|
|
17
|
+
if (params?.id) {
|
|
18
|
+
await this.service.findOneDocument(params.id, query);
|
|
19
|
+
}
|
|
20
|
+
else {
|
|
21
|
+
await this.service.findManyDocuments(query);
|
|
22
|
+
}
|
|
15
23
|
}
|
|
16
|
-
|
|
17
|
-
if (!user) {
|
|
18
|
-
throw new common_1.ForbiddenException('Forbidden resource');
|
|
19
|
-
}
|
|
20
|
-
const ability = (0, builders_1.CaslAbilityBuilder)(this.entity, this.routeType, this.abilityPredicate, user);
|
|
21
|
-
return policyHandlers.every((handler) => {
|
|
22
|
-
return this.execPolicyHandler(handler, ability);
|
|
23
|
-
});
|
|
24
|
-
}
|
|
25
|
-
execPolicyHandler(handler, ability) {
|
|
26
|
-
if (typeof handler === 'function') {
|
|
27
|
-
return handler(ability);
|
|
28
|
-
}
|
|
29
|
-
return handler.handle(ability);
|
|
24
|
+
return true;
|
|
30
25
|
}
|
|
31
26
|
}
|
|
32
27
|
exports.BasePoliciesGuard = BasePoliciesGuard;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ControllerAbilityPredicate,
|
|
1
|
+
import { ControllerAbilityPredicate, AbilityPredicate, RouteType } from '../interfaces';
|
|
2
2
|
import { BaseEntity } from '../models';
|
|
3
|
-
declare function getPredicateFromControllerAbilityPredicates<Entity extends BaseEntity>(controllerAbilityPredicates: ControllerAbilityPredicate<Entity>[], route: RouteType):
|
|
3
|
+
declare function getPredicateFromControllerAbilityPredicates<Entity extends BaseEntity>(controllerAbilityPredicates: ControllerAbilityPredicate<Entity>[], route: RouteType): AbilityPredicate<Entity>;
|
|
4
4
|
export { getPredicateFromControllerAbilityPredicates };
|
|
@@ -7,60 +7,36 @@ declare function getControllerMixinData<Entity extends BaseEntity>(entity: Type<
|
|
|
7
7
|
displayedName: string;
|
|
8
8
|
description: string;
|
|
9
9
|
isPublic: boolean;
|
|
10
|
-
abilityPredicate: import("../interfaces/dynamic-api-
|
|
10
|
+
abilityPredicate: import("../interfaces/dynamic-api-ability.interface").AbilityPredicate<Entity>;
|
|
11
11
|
RouteBody: Type<any>;
|
|
12
12
|
RoutePresenter: Type<any>;
|
|
13
13
|
EntityParam?: undefined;
|
|
14
|
-
RouteQuery?: undefined;
|
|
15
14
|
} | {
|
|
16
15
|
routeType: import("../interfaces/dynamic-api-route-type.type").RouteType;
|
|
17
16
|
displayedName: string;
|
|
18
17
|
description: string;
|
|
19
18
|
isPublic: boolean;
|
|
20
|
-
abilityPredicate: import("../interfaces/dynamic-api-
|
|
19
|
+
abilityPredicate: import("../interfaces/dynamic-api-ability.interface").AbilityPredicate<Entity>;
|
|
21
20
|
RoutePresenter: Type<any>;
|
|
22
21
|
RouteBody?: undefined;
|
|
23
22
|
EntityParam?: undefined;
|
|
24
|
-
RouteQuery?: undefined;
|
|
25
23
|
} | {
|
|
26
24
|
routeType: import("../interfaces/dynamic-api-route-type.type").RouteType;
|
|
27
25
|
displayedName: string;
|
|
28
26
|
description: string;
|
|
29
27
|
isPublic: boolean;
|
|
30
|
-
abilityPredicate: import("../interfaces/dynamic-api-
|
|
28
|
+
abilityPredicate: import("../interfaces/dynamic-api-ability.interface").AbilityPredicate<Entity>;
|
|
31
29
|
EntityParam: typeof EntityParam;
|
|
32
30
|
RoutePresenter: Type<any>;
|
|
33
31
|
RouteBody?: undefined;
|
|
34
|
-
RouteQuery?: undefined;
|
|
35
32
|
} | {
|
|
36
33
|
routeType: import("../interfaces/dynamic-api-route-type.type").RouteType;
|
|
37
34
|
displayedName: string;
|
|
38
35
|
description: string;
|
|
39
36
|
isPublic: boolean;
|
|
40
|
-
abilityPredicate: import("../interfaces/dynamic-api-
|
|
37
|
+
abilityPredicate: import("../interfaces/dynamic-api-ability.interface").AbilityPredicate<Entity>;
|
|
41
38
|
RouteBody: Type<any>;
|
|
42
39
|
RoutePresenter: Type<any>;
|
|
43
40
|
EntityParam: typeof EntityParam;
|
|
44
|
-
RouteQuery?: undefined;
|
|
45
|
-
} | {
|
|
46
|
-
routeType: import("../interfaces/dynamic-api-route-type.type").RouteType;
|
|
47
|
-
displayedName: string;
|
|
48
|
-
description: string;
|
|
49
|
-
isPublic: boolean;
|
|
50
|
-
abilityPredicate: import("../interfaces/dynamic-api-casl-ability.interface").RouteAbilityPredicate<Entity>;
|
|
51
|
-
RouteQuery: Type<any>;
|
|
52
|
-
RoutePresenter: Type<any>;
|
|
53
|
-
RouteBody?: undefined;
|
|
54
|
-
EntityParam?: undefined;
|
|
55
|
-
} | {
|
|
56
|
-
routeType: import("../interfaces/dynamic-api-route-type.type").RouteType;
|
|
57
|
-
displayedName: string;
|
|
58
|
-
description: string;
|
|
59
|
-
isPublic: boolean;
|
|
60
|
-
abilityPredicate: import("../interfaces/dynamic-api-casl-ability.interface").RouteAbilityPredicate<Entity>;
|
|
61
|
-
EntityParam: typeof EntityParam;
|
|
62
|
-
RouteQuery: Type<any>;
|
|
63
|
-
RoutePresenter: Type<any>;
|
|
64
|
-
RouteBody?: undefined;
|
|
65
41
|
};
|
|
66
42
|
export { getControllerMixinData };
|
|
@@ -47,26 +47,17 @@ function buildDeletePresenterDTO(displayedName, version, CustomPresenter) {
|
|
|
47
47
|
class RoutePresenter extends (CustomPresenter ?? dtos_1.DeletePresenter) {
|
|
48
48
|
}
|
|
49
49
|
Object.defineProperty(RoutePresenter, 'name', {
|
|
50
|
-
value:
|
|
50
|
+
value: `Delete${displayedName}${(0, versioning_config_helper_1.addVersionSuffix)(version)}Presenter`,
|
|
51
51
|
writable: false,
|
|
52
52
|
});
|
|
53
53
|
return RoutePresenter;
|
|
54
54
|
}
|
|
55
|
-
function buildDefaultRouteQuery(entity, routeType, displayedName, version, CustomQuery) {
|
|
56
|
-
class RouteQuery extends (CustomQuery ?? dtos_1.EntityQuery) {
|
|
57
|
-
}
|
|
58
|
-
Object.defineProperty(RouteQuery, 'name', {
|
|
59
|
-
value: CustomQuery ? CustomQuery.name : `${routeType}${displayedName}${(0, versioning_config_helper_1.addVersionSuffix)(version)}Query`,
|
|
60
|
-
writable: false,
|
|
61
|
-
});
|
|
62
|
-
return RouteQuery;
|
|
63
|
-
}
|
|
64
55
|
function buildDefaultRouteBody(entity, routeType, displayedName, version, CustomBody) {
|
|
65
56
|
const optionalBody = routeType !== 'CreateOne' && routeType !== 'ReplaceOne';
|
|
66
57
|
class RouteBody extends (CustomBody ?? (0, mixins_1.EntityBodyMixin)(entity, optionalBody)) {
|
|
67
58
|
}
|
|
68
59
|
Object.defineProperty(RouteBody, 'name', {
|
|
69
|
-
value:
|
|
60
|
+
value: `${routeType}${displayedName}${(0, versioning_config_helper_1.addVersionSuffix)(version)}Dto`,
|
|
70
61
|
writable: false,
|
|
71
62
|
});
|
|
72
63
|
return RouteBody;
|
|
@@ -75,18 +66,19 @@ function buildDefaultRoutePresenter(entity, routeType, displayedName, version, C
|
|
|
75
66
|
class RoutePresenter extends (CustomPresenter ?? (0, mixins_1.EntityPresenterMixin)(entity)) {
|
|
76
67
|
}
|
|
77
68
|
Object.defineProperty(RoutePresenter, 'name', {
|
|
78
|
-
value: CustomPresenter
|
|
69
|
+
value: CustomPresenter
|
|
70
|
+
? `${routeType}${displayedName}${(0, versioning_config_helper_1.addVersionSuffix)(version)}Presenter`
|
|
71
|
+
: `${displayedName}${(0, versioning_config_helper_1.addVersionSuffix)(version)}Presenter`,
|
|
79
72
|
writable: false,
|
|
80
73
|
});
|
|
81
74
|
return RoutePresenter;
|
|
82
75
|
}
|
|
83
76
|
function getDTOsByRouteType(entity, routeType, displayedName, version, dTOs) {
|
|
84
|
-
const {
|
|
77
|
+
const { body: CustomBody, presenter: CustomPresenter, } = dTOs ?? {};
|
|
85
78
|
Object.defineProperty(dtos_1.EntityParam, 'name', {
|
|
86
79
|
value: `${displayedName}${(0, versioning_config_helper_1.addVersionSuffix)(version)}Param`,
|
|
87
80
|
writable: false,
|
|
88
81
|
});
|
|
89
|
-
const RouteQuery = buildDefaultRouteQuery(entity, routeType, displayedName, version, CustomQuery);
|
|
90
82
|
const RouteBody = buildDefaultRouteBody(entity, routeType, displayedName, version, CustomBody);
|
|
91
83
|
const RoutePresenter = buildDefaultRoutePresenter(entity, routeType, displayedName, version, CustomPresenter);
|
|
92
84
|
switch (routeType) {
|
|
@@ -121,13 +113,11 @@ function getDTOsByRouteType(entity, routeType, displayedName, version, dTOs) {
|
|
|
121
113
|
};
|
|
122
114
|
case 'GetMany':
|
|
123
115
|
return {
|
|
124
|
-
RouteQuery,
|
|
125
116
|
RoutePresenter,
|
|
126
117
|
};
|
|
127
118
|
case 'GetOne':
|
|
128
119
|
return {
|
|
129
120
|
EntityParam: dtos_1.EntityParam,
|
|
130
|
-
RouteQuery,
|
|
131
121
|
RoutePresenter,
|
|
132
122
|
};
|
|
133
123
|
default:
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { RouteType } from '../interfaces';
|
|
1
2
|
export declare function pascalCase(str?: string): string;
|
|
2
3
|
export declare function isValidVersion(version: string): boolean;
|
|
3
4
|
export declare function getFormattedApiTag<Entity>(apiTag: string | undefined, entityName: string): string;
|
|
5
|
+
export declare function getNamePrefix(routeType: RouteType, entityName: string, version: string | undefined): string;
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.getFormattedApiTag = exports.isValidVersion = exports.pascalCase = void 0;
|
|
3
|
+
exports.getNamePrefix = exports.getFormattedApiTag = exports.isValidVersion = exports.pascalCase = void 0;
|
|
4
4
|
const lodash_1 = require("lodash");
|
|
5
|
+
const versioning_config_helper_1 = require("./versioning-config.helper");
|
|
5
6
|
function pascalCase(str) {
|
|
6
7
|
return str ? (0, lodash_1.upperFirst)((0, lodash_1.camelCase)(str)) : undefined;
|
|
7
8
|
}
|
|
@@ -14,3 +15,7 @@ function getFormattedApiTag(apiTag, entityName) {
|
|
|
14
15
|
return pascalCase(apiTag) ?? entityName;
|
|
15
16
|
}
|
|
16
17
|
exports.getFormattedApiTag = getFormattedApiTag;
|
|
18
|
+
function getNamePrefix(routeType, entityName, version) {
|
|
19
|
+
return `${routeType}${entityName}${(0, versioning_config_helper_1.addVersionSuffix)(version)}`;
|
|
20
|
+
}
|
|
21
|
+
exports.getNamePrefix = getNamePrefix;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { BaseEntity } from '../models';
|
|
2
|
+
import { RouteType } from './dynamic-api-route-type.type';
|
|
3
|
+
type AbilityPredicate<Entity extends BaseEntity, User = any> = (entity: Entity, user: User) => boolean;
|
|
4
|
+
type RegisterAbilityPredicate<User = any> = (user: User) => boolean;
|
|
5
|
+
type ControllerAbilityPredicate<Entity extends BaseEntity> = {
|
|
6
|
+
targets: RouteType[];
|
|
7
|
+
predicate: AbilityPredicate<Entity>;
|
|
8
|
+
};
|
|
9
|
+
export { ControllerAbilityPredicate, RegisterAbilityPredicate, AbilityPredicate, };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { ValidationPipeOptions } from '@nestjs/common';
|
|
2
2
|
import { BaseEntity } from '../models';
|
|
3
|
-
import { ControllerAbilityPredicate } from './dynamic-api-
|
|
3
|
+
import { ControllerAbilityPredicate } from './dynamic-api-ability.interface';
|
|
4
4
|
interface DynamicApiControllerOptions<Entity extends BaseEntity> {
|
|
5
5
|
path: string;
|
|
6
6
|
apiTag?: string;
|
|
@@ -1,14 +1,8 @@
|
|
|
1
1
|
import { ExecutionContext } from '@nestjs/common';
|
|
2
|
-
import { Reflector } from '@nestjs/core';
|
|
3
2
|
import { BaseEntity } from '../models';
|
|
4
|
-
import {
|
|
5
|
-
interface IPolicyHandler<Entity extends BaseEntity> {
|
|
6
|
-
handle(ability: AppAbility<Entity>): boolean;
|
|
7
|
-
}
|
|
8
|
-
type PolicyHandlerCallback<Entity extends BaseEntity> = (ability: AppAbility<Entity>) => boolean;
|
|
9
|
-
type PolicyHandler<Entity extends BaseEntity> = IPolicyHandler<Entity> | PolicyHandlerCallback<Entity>;
|
|
3
|
+
import { BaseService } from '../services';
|
|
10
4
|
interface PoliciesGuard<Entity extends BaseEntity> {
|
|
11
|
-
canActivate(context: ExecutionContext): boolean
|
|
5
|
+
canActivate(context: ExecutionContext): boolean | Promise<boolean>;
|
|
12
6
|
}
|
|
13
|
-
type PoliciesGuardConstructor<Entity extends BaseEntity> = new (
|
|
14
|
-
export {
|
|
7
|
+
type PoliciesGuardConstructor<Entity extends BaseEntity> = new (service: BaseService<Entity>) => PoliciesGuard<Entity>;
|
|
8
|
+
export { PoliciesGuardConstructor, PoliciesGuard };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { ValidationPipeOptions } from '@nestjs/common';
|
|
2
2
|
import { BaseEntity } from '../models';
|
|
3
|
-
import {
|
|
3
|
+
import { AbilityPredicate } from './dynamic-api-ability.interface';
|
|
4
4
|
import { DTOsBundle } from './dynamic-api-route-dtos-bundle.type';
|
|
5
5
|
import { RouteType } from './dynamic-api-route-type.type';
|
|
6
6
|
interface DynamicAPIRouteConfig<Entity extends BaseEntity> {
|
|
@@ -10,6 +10,6 @@ interface DynamicAPIRouteConfig<Entity extends BaseEntity> {
|
|
|
10
10
|
version?: string;
|
|
11
11
|
dTOs?: DTOsBundle;
|
|
12
12
|
validationPipeOptions?: ValidationPipeOptions;
|
|
13
|
-
abilityPredicate?:
|
|
13
|
+
abilityPredicate?: AbilityPredicate<Entity>;
|
|
14
14
|
}
|
|
15
15
|
export { DynamicAPIRouteConfig };
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export * from './dynamic-api-controller-options.interface';
|
|
2
2
|
export * from './dynamic-api-decorator-builder.interface';
|
|
3
3
|
export * from './dynamic-api-cache-options.interface';
|
|
4
|
-
export * from './dynamic-api-
|
|
4
|
+
export * from './dynamic-api-ability.interface';
|
|
5
5
|
export * from './dynamic-api-entity-mappers.interface';
|
|
6
6
|
export * from './dynamic-api-global-state.interface';
|
|
7
7
|
export * from './dynamic-api-options.interface';
|
package/src/interfaces/index.js
CHANGED
|
@@ -17,7 +17,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
17
17
|
__exportStar(require("./dynamic-api-controller-options.interface"), exports);
|
|
18
18
|
__exportStar(require("./dynamic-api-decorator-builder.interface"), exports);
|
|
19
19
|
__exportStar(require("./dynamic-api-cache-options.interface"), exports);
|
|
20
|
-
__exportStar(require("./dynamic-api-
|
|
20
|
+
__exportStar(require("./dynamic-api-ability.interface"), exports);
|
|
21
21
|
__exportStar(require("./dynamic-api-entity-mappers.interface"), exports);
|
|
22
22
|
__exportStar(require("./dynamic-api-global-state.interface"), exports);
|
|
23
23
|
__exportStar(require("./dynamic-api-options.interface"), exports);
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { Type } from '@nestjs/common';
|
|
2
|
-
import {
|
|
2
|
+
import { AbilityPredicate, PoliciesGuardConstructor, RouteType } from '../interfaces';
|
|
3
3
|
import { BaseEntity } from '../models';
|
|
4
|
-
|
|
4
|
+
import { BaseService } from '../services';
|
|
5
|
+
declare function CreatePoliciesGuardMixin<Entity extends BaseEntity, Service extends BaseService<Entity>>(entity: Type<Entity>, routeType: RouteType, version: string | undefined, abilityPredicate: AbilityPredicate<Entity> | undefined): PoliciesGuardConstructor<Entity>;
|
|
5
6
|
export { CreatePoliciesGuardMixin };
|
|
@@ -8,17 +8,19 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
|
|
|
8
8
|
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
9
9
|
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
10
10
|
};
|
|
11
|
+
var __param = (this && this.__param) || function (paramIndex, decorator) {
|
|
12
|
+
return function (target, key) { decorator(target, key, paramIndex); }
|
|
13
|
+
};
|
|
11
14
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
15
|
exports.CreatePoliciesGuardMixin = void 0;
|
|
13
16
|
const common_1 = require("@nestjs/common");
|
|
14
|
-
const core_1 = require("@nestjs/core");
|
|
15
17
|
const guards_1 = require("../guards");
|
|
16
18
|
const helpers_1 = require("../helpers");
|
|
17
19
|
function CreatePoliciesGuardMixin(entity, routeType, version, abilityPredicate) {
|
|
18
20
|
let RoutePoliciesGuard = class RoutePoliciesGuard extends guards_1.BasePoliciesGuard {
|
|
19
|
-
constructor(
|
|
20
|
-
super(
|
|
21
|
-
this.
|
|
21
|
+
constructor(service) {
|
|
22
|
+
super(service);
|
|
23
|
+
this.service = service;
|
|
22
24
|
this.routeType = routeType;
|
|
23
25
|
this.entity = entity;
|
|
24
26
|
this.abilityPredicate = abilityPredicate;
|
|
@@ -26,10 +28,11 @@ function CreatePoliciesGuardMixin(entity, routeType, version, abilityPredicate)
|
|
|
26
28
|
};
|
|
27
29
|
RoutePoliciesGuard = __decorate([
|
|
28
30
|
(0, common_1.Injectable)(),
|
|
29
|
-
|
|
31
|
+
__param(0, (0, common_1.Inject)(`${(0, helpers_1.getNamePrefix)(routeType, entity.name, version)}Service`)),
|
|
32
|
+
__metadata("design:paramtypes", [Object])
|
|
30
33
|
], RoutePoliciesGuard);
|
|
31
34
|
Object.defineProperty(RoutePoliciesGuard, 'name', {
|
|
32
|
-
value: `${
|
|
35
|
+
value: `${(0, helpers_1.getNamePrefix)(routeType, entity.name, version)}PoliciesGuard`,
|
|
33
36
|
writable: false,
|
|
34
37
|
});
|
|
35
38
|
return RoutePoliciesGuard;
|
|
@@ -23,6 +23,9 @@ const guards_1 = require("../guards");
|
|
|
23
23
|
const auth_register_policies_guard_mixin_1 = require("./auth-register-policies-guard.mixin");
|
|
24
24
|
function AuthControllerMixin(userEntity, loginField, passwordField, additionalRequestFields = [], { additionalFields: additionalRegisterFields, protected: registerProtected, abilityPredicate: registerAbilityPredicate, } = {}) {
|
|
25
25
|
var _a;
|
|
26
|
+
if (!loginField || !passwordField) {
|
|
27
|
+
throw new Error('Login and password fields are required');
|
|
28
|
+
}
|
|
26
29
|
class AuthBodyPasswordFieldDto {
|
|
27
30
|
}
|
|
28
31
|
_a = passwordField;
|
|
@@ -36,6 +39,9 @@ function AuthControllerMixin(userEntity, loginField, passwordField, additionalRe
|
|
|
36
39
|
}
|
|
37
40
|
const additionalMandatoryFields = [];
|
|
38
41
|
const additionalOptionalFields = [];
|
|
42
|
+
if (!additionalRegisterFields) {
|
|
43
|
+
additionalRegisterFields = [];
|
|
44
|
+
}
|
|
39
45
|
additionalRegisterFields.forEach((field) => {
|
|
40
46
|
if (typeof field === 'string') {
|
|
41
47
|
additionalOptionalFields.push(field);
|
|
@@ -107,7 +113,6 @@ function AuthControllerMixin(userEntity, loginField, passwordField, additionalRe
|
|
|
107
113
|
(0, swagger_1.ApiOkResponse)({ type: AuthPresenter }),
|
|
108
114
|
(0, common_1.Post)('register'),
|
|
109
115
|
(0, common_1.UseGuards)(AuthRegisterPoliciesGuard),
|
|
110
|
-
(0, decorators_1.CheckPolicies)((ability) => ability.can(auth_register_policies_guard_mixin_1.registerRouteType, userEntity)),
|
|
111
116
|
__param(0, (0, common_1.Body)()),
|
|
112
117
|
__metadata("design:type", Function),
|
|
113
118
|
__metadata("design:paramtypes", [AuthRegisterDto]),
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { Type } from '@nestjs/common';
|
|
2
|
-
import {
|
|
2
|
+
import { PoliciesGuardConstructor, RegisterAbilityPredicate } from '../../../interfaces';
|
|
3
3
|
import { BaseEntity } from '../../../models';
|
|
4
|
-
declare const registerRouteType: RouteType;
|
|
5
4
|
declare function AuthRegisterPoliciesGuardMixin<Entity extends BaseEntity>(entity: Type<Entity>, abilityPredicate: RegisterAbilityPredicate | undefined): PoliciesGuardConstructor<Entity>;
|
|
6
|
-
export { AuthRegisterPoliciesGuardMixin
|
|
5
|
+
export { AuthRegisterPoliciesGuardMixin };
|
|
@@ -5,54 +5,25 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
|
|
|
5
5
|
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
6
6
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
7
7
|
};
|
|
8
|
-
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
9
|
-
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
10
|
-
};
|
|
11
8
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
-
exports.
|
|
13
|
-
const ability_1 = require("@casl/ability");
|
|
9
|
+
exports.AuthRegisterPoliciesGuardMixin = void 0;
|
|
14
10
|
const common_1 = require("@nestjs/common");
|
|
15
|
-
const core_1 = require("@nestjs/core");
|
|
16
|
-
const decorators_1 = require("../../../decorators");
|
|
17
|
-
const registerRouteType = 'register';
|
|
18
|
-
exports.registerRouteType = registerRouteType;
|
|
19
11
|
function AuthRegisterPoliciesGuardMixin(entity, abilityPredicate) {
|
|
20
12
|
let BaseAuthRegisterPoliciesGuard = class BaseAuthRegisterPoliciesGuard {
|
|
21
|
-
constructor(
|
|
22
|
-
this.reflector = reflector;
|
|
13
|
+
constructor() {
|
|
23
14
|
this.entity = entity;
|
|
24
15
|
this.abilityPredicate = abilityPredicate;
|
|
25
16
|
}
|
|
26
17
|
canActivate(context) {
|
|
27
|
-
const policyHandlers = this.reflector.get(decorators_1.CHECK_POLICIES_KEY, context.getHandler());
|
|
28
|
-
if (!policyHandlers || !this.abilityPredicate) {
|
|
29
|
-
return true;
|
|
30
|
-
}
|
|
31
18
|
let { user } = context.switchToHttp().getRequest();
|
|
32
|
-
if (!user) {
|
|
33
|
-
throw new common_1.ForbiddenException('
|
|
34
|
-
}
|
|
35
|
-
const { can, build } = new ability_1.AbilityBuilder(ability_1.createMongoAbility);
|
|
36
|
-
if (abilityPredicate(user)) {
|
|
37
|
-
can(registerRouteType, entity);
|
|
38
|
-
}
|
|
39
|
-
const ability = build({
|
|
40
|
-
detectSubjectType: (object) => object.constructor,
|
|
41
|
-
});
|
|
42
|
-
return policyHandlers.every((handler) => {
|
|
43
|
-
return this.execPolicyHandler(handler, ability);
|
|
44
|
-
});
|
|
45
|
-
}
|
|
46
|
-
execPolicyHandler(handler, ability) {
|
|
47
|
-
if (typeof handler === 'function') {
|
|
48
|
-
return handler(ability);
|
|
19
|
+
if (this.abilityPredicate && (!user || !this.abilityPredicate(user))) {
|
|
20
|
+
throw new common_1.ForbiddenException('Access denied');
|
|
49
21
|
}
|
|
50
|
-
return
|
|
22
|
+
return true;
|
|
51
23
|
}
|
|
52
24
|
};
|
|
53
25
|
BaseAuthRegisterPoliciesGuard = __decorate([
|
|
54
|
-
(0, common_1.Injectable)()
|
|
55
|
-
__metadata("design:paramtypes", [core_1.Reflector])
|
|
26
|
+
(0, common_1.Injectable)()
|
|
56
27
|
], BaseAuthRegisterPoliciesGuard);
|
|
57
28
|
return BaseAuthRegisterPoliciesGuard;
|
|
58
29
|
}
|