mongodb-dynamic-api 2.2.0 → 2.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +9 -0
- package/package.json +3 -1
- package/src/decorators/api-endpoint-visibility.decorator.d.ts +3 -0
- package/src/decorators/api-endpoint-visibility.decorator.js +10 -0
- package/src/decorators/index.d.ts +1 -0
- package/src/decorators/index.js +1 -0
- package/src/dynamic-api.module.js +1 -4
- package/src/helpers/format.helper.d.ts +2 -2
- package/src/helpers/format.helper.js +5 -2
- package/src/helpers/index.d.ts +2 -0
- package/src/helpers/index.js +2 -0
- package/src/interfaces/dynamic-api-service-callback.interface.d.ts +14 -27
- package/src/mixins/create-policies-guard.mixin.js +2 -2
- package/src/modules/auth/auth.helper.d.ts +3 -3
- package/src/modules/auth/auth.helper.js +4 -3
- package/src/modules/auth/auth.module.d.ts +1 -1
- package/src/modules/auth/auth.module.js +7 -3
- package/src/modules/auth/dtos/change-password.dto.d.ts +4 -0
- package/src/modules/auth/dtos/change-password.dto.js +29 -0
- package/src/modules/auth/dtos/reset-password.dto.d.ts +3 -0
- package/src/modules/auth/dtos/reset-password.dto.js +24 -0
- package/src/modules/auth/interfaces/auth-options.interface.d.ts +9 -2
- package/src/modules/auth/interfaces/auth-service.interface.d.ts +2 -1
- package/src/modules/auth/mixins/auth-controller.mixin.d.ts +2 -2
- package/src/modules/auth/mixins/auth-controller.mixin.js +28 -2
- package/src/modules/auth/services/base-auth.service.d.ts +6 -3
- package/src/modules/auth/services/base-auth.service.js +64 -6
- package/src/routes/create-many/base-create-many.service.js +1 -1
- package/src/routes/create-many/create-many-controller.mixin.js +1 -2
- package/src/routes/create-many/create-many.helper.js +5 -7
- package/src/routes/create-many/create-many.module.d.ts +1 -1
- package/src/routes/create-many/create-many.module.js +1 -1
- package/src/routes/create-one/base-create-one.service.js +1 -1
- package/src/routes/create-one/create-one-controller.mixin.js +1 -2
- package/src/routes/create-one/create-one.helper.js +5 -7
- package/src/routes/delete-many/delete-many-controller.mixin.js +1 -2
- package/src/routes/delete-many/delete-many.helper.js +4 -7
- package/src/routes/delete-one/delete-one-controller.mixin.js +1 -2
- package/src/routes/delete-one/delete-one.helper.js +4 -7
- package/src/routes/duplicate-many/base-duplicate-many.service.js +1 -1
- package/src/routes/duplicate-many/duplicate-many-controller.mixin.js +1 -2
- package/src/routes/duplicate-many/duplicate-many.helper.js +4 -7
- package/src/routes/duplicate-one/base-duplicate-one.service.js +1 -1
- package/src/routes/duplicate-one/duplicate-one-controller.mixin.js +1 -2
- package/src/routes/duplicate-one/duplicate-one.helper.js +4 -7
- package/src/routes/get-many/base-get-many.service.js +1 -1
- package/src/routes/get-many/get-many-controller.mixin.js +1 -2
- package/src/routes/get-many/get-many.helper.js +4 -7
- package/src/routes/get-one/base-get-one.service.js +1 -1
- package/src/routes/get-one/get-one-controller.mixin.js +1 -2
- package/src/routes/get-one/get-one.helper.js +4 -7
- package/src/routes/replace-one/base-replace-one.service.js +1 -1
- package/src/routes/replace-one/replace-one-controller.mixin.js +1 -2
- package/src/routes/replace-one/replace-one.helper.js +4 -7
- package/src/routes/update-many/base-update-many.service.js +1 -1
- package/src/routes/update-many/update-many-controller.mixin.js +1 -2
- package/src/routes/update-many/update-many.helper.js +4 -7
- package/src/routes/update-one/base-update-one.service.js +1 -1
- package/src/routes/update-one/update-one-controller.mixin.js +1 -2
- package/src/routes/update-one/update-one.helper.js +4 -7
- package/src/services/base/base.service.d.ts +6 -2
- package/src/services/base/base.service.js +20 -1
- package/src/version.json +1 -1
- package/tsconfig.tsbuildinfo +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,14 @@
|
|
|
1
1
|
Changelog
|
|
2
2
|
|
|
3
|
+
## [2.3.0](https://github.com/MikeDev75015/mongodb-dynamic-api/compare/v2.2.1...v2.3.0) (2024-05-02)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### api
|
|
7
|
+
|
|
8
|
+
* **api:** add reset password process with callbacks ([9e8bf56](https://github.com/MikeDev75015/mongodb-dynamic-api/commit/9e8bf562ee9717ea1c0fe387bb621e9f724955ac))
|
|
9
|
+
|
|
10
|
+
## [2.2.1](https://github.com/MikeDev75015/mongodb-dynamic-api/compare/v2.2.0...v2.2.1) (2024-04-30)
|
|
11
|
+
|
|
3
12
|
## [2.2.0](https://github.com/MikeDev75015/mongodb-dynamic-api/compare/v2.1.10...v2.2.0) (2024-04-30)
|
|
4
13
|
|
|
5
14
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mongodb-dynamic-api",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.3.0",
|
|
4
4
|
"description": "Auto generated CRUD API for MongoDB using NestJS",
|
|
5
5
|
"readmeFilename": "README.md",
|
|
6
6
|
"main": "index.js",
|
|
@@ -96,6 +96,8 @@
|
|
|
96
96
|
"typescript": "^5.3.3"
|
|
97
97
|
},
|
|
98
98
|
"jest": {
|
|
99
|
+
"clearMocks": true,
|
|
100
|
+
"resetMocks": true,
|
|
99
101
|
"moduleFileExtensions": [
|
|
100
102
|
"js",
|
|
101
103
|
"json",
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ApiEndpointVisibility = void 0;
|
|
4
|
+
const common_1 = require("@nestjs/common");
|
|
5
|
+
const swagger_1 = require("@nestjs/swagger");
|
|
6
|
+
function ApiEndpointVisibility(condition, decorator) {
|
|
7
|
+
const decoratorIfValid = decorator ?? ((_) => undefined);
|
|
8
|
+
return (0, common_1.applyDecorators)(!condition ? (0, swagger_1.ApiExcludeEndpoint)() : decoratorIfValid);
|
|
9
|
+
}
|
|
10
|
+
exports.ApiEndpointVisibility = ApiEndpointVisibility;
|
package/src/decorators/index.js
CHANGED
|
@@ -14,6 +14,7 @@ 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("./api-endpoint-visibility.decorator"), exports);
|
|
17
18
|
__exportStar(require("./public.decorator"), exports);
|
|
18
19
|
__exportStar(require("./schema-options.decorator"), exports);
|
|
19
20
|
__exportStar(require("./validator-pipe.decorator"), exports);
|
|
@@ -80,10 +80,6 @@ let DynamicApiModule = DynamicApiModule_1 = class DynamicApiModule {
|
|
|
80
80
|
...routes.map((routeConfig) => {
|
|
81
81
|
const { type, description: routeDescription, version: routeVersion, validationPipeOptions: routeValidationPipeOptions, } = routeConfig;
|
|
82
82
|
const module = moduleByRouteType.get(type);
|
|
83
|
-
if (!module) {
|
|
84
|
-
reject(new Error(`Route module for ${type} not found`));
|
|
85
|
-
return;
|
|
86
|
-
}
|
|
87
83
|
const description = routeDescription ?? (0, helpers_1.getDefaultRouteDescription)(type, entity.name);
|
|
88
84
|
const version = routeVersion ?? controllerVersion;
|
|
89
85
|
if (version && !(0, helpers_1.isValidVersion)(version)) {
|
|
@@ -162,6 +158,7 @@ let DynamicApiModule = DynamicApiModule_1 = class DynamicApiModule {
|
|
|
162
158
|
additionalFields: [],
|
|
163
159
|
},
|
|
164
160
|
login: useAuth.login ?? {},
|
|
161
|
+
resetPassword: useAuth.resetPassword ?? {},
|
|
165
162
|
};
|
|
166
163
|
}
|
|
167
164
|
static setDefaultRoutes(stateRoutesConfig, controllerRoutesConfig = {}, routes = []) {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { RouteType } from '../interfaces';
|
|
2
2
|
export declare function pascalCase(str?: string): string;
|
|
3
3
|
export declare function isValidVersion(version: string): boolean;
|
|
4
|
-
export declare function getFormattedApiTag
|
|
5
|
-
export declare function
|
|
4
|
+
export declare function getFormattedApiTag(apiTag: string | undefined, entityName: string): string;
|
|
5
|
+
export declare function provideName(routeType: RouteType, entityName: string, version: string | undefined, suffix: 'Service' | 'Controller' | 'PoliciesGuard'): string;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
3
|
+
exports.provideName = exports.getFormattedApiTag = exports.isValidVersion = exports.pascalCase = void 0;
|
|
4
4
|
const lodash_1 = require("lodash");
|
|
5
5
|
const versioning_config_helper_1 = require("./versioning-config.helper");
|
|
6
6
|
function pascalCase(str) {
|
|
@@ -18,4 +18,7 @@ exports.getFormattedApiTag = getFormattedApiTag;
|
|
|
18
18
|
function getNamePrefix(routeType, entityName, version) {
|
|
19
19
|
return `${routeType}${entityName}${(0, versioning_config_helper_1.addVersionSuffix)(version)}`;
|
|
20
20
|
}
|
|
21
|
-
|
|
21
|
+
function provideName(routeType, entityName, version, suffix) {
|
|
22
|
+
return `${getNamePrefix(routeType, entityName, version)}${suffix}`;
|
|
23
|
+
}
|
|
24
|
+
exports.provideName = provideName;
|
package/src/helpers/index.d.ts
CHANGED
package/src/helpers/index.js
CHANGED
|
@@ -14,6 +14,8 @@ 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("./controller-ability-predicates.helper"), exports);
|
|
18
|
+
__exportStar(require("./controller-mixin.helper"), exports);
|
|
17
19
|
__exportStar(require("./format.helper"), exports);
|
|
18
20
|
__exportStar(require("./route-decorators.helper"), exports);
|
|
19
21
|
__exportStar(require("./route-description.helper"), exports);
|
|
@@ -1,28 +1,15 @@
|
|
|
1
|
-
/// <reference types="mongoose/types/aggregate" />
|
|
2
|
-
/// <reference types="mongoose/types/callback" />
|
|
3
|
-
/// <reference types="mongoose/types/collection" />
|
|
4
|
-
/// <reference types="mongoose/types/connection" />
|
|
5
|
-
/// <reference types="mongoose/types/cursor" />
|
|
6
|
-
/// <reference types="mongoose/types/document" />
|
|
7
|
-
/// <reference types="mongoose/types/error" />
|
|
8
|
-
/// <reference types="mongoose/types/expressions" />
|
|
9
|
-
/// <reference types="mongoose/types/helpers" />
|
|
10
|
-
/// <reference types="mongoose/types/middlewares" />
|
|
11
|
-
/// <reference types="mongoose/types/indexes" />
|
|
12
|
-
/// <reference types="mongoose/types/models" />
|
|
13
|
-
/// <reference types="mongoose/types/mongooseoptions" />
|
|
14
|
-
/// <reference types="mongoose/types/pipelinestage" />
|
|
15
|
-
/// <reference types="mongoose/types/populate" />
|
|
16
|
-
/// <reference types="mongoose/types/query" />
|
|
17
|
-
/// <reference types="mongoose/types/schemaoptions" />
|
|
18
|
-
/// <reference types="mongoose/types/schematypes" />
|
|
19
|
-
/// <reference types="mongoose/types/session" />
|
|
20
|
-
/// <reference types="mongoose/types/types" />
|
|
21
|
-
/// <reference types="mongoose/types/utility" />
|
|
22
|
-
/// <reference types="mongoose/types/validation" />
|
|
23
|
-
/// <reference types="mongoose/types/virtuals" />
|
|
24
|
-
/// <reference types="mongoose/types/inferschematype" />
|
|
25
|
-
import { Model } from 'mongoose';
|
|
26
1
|
import { BaseEntity } from '../models';
|
|
27
|
-
type
|
|
28
|
-
|
|
2
|
+
type DynamicApiCallbackMethods<Entity extends BaseEntity> = {
|
|
3
|
+
findById: (id: string) => Promise<Entity | undefined>;
|
|
4
|
+
findAndUpdateById: (id: string, update: Partial<Entity>) => Promise<Entity>;
|
|
5
|
+
};
|
|
6
|
+
type DynamicApiServiceCallback<Entity extends BaseEntity> = (entity: Entity, methods: DynamicApiCallbackMethods<Entity>) => Promise<void>;
|
|
7
|
+
type DynamicApiResetPasswordCallbackMethods<Entity extends BaseEntity, UpdateBy = 'userId'> = {
|
|
8
|
+
findUserByEmail: (email: string) => Promise<Entity | undefined>;
|
|
9
|
+
updateUserByEmail: (email: string, update: Partial<Entity>) => Promise<Entity>;
|
|
10
|
+
};
|
|
11
|
+
type DynamicApiResetPasswordCallback<Entity extends BaseEntity> = (_: {
|
|
12
|
+
resetPasswordToken: string;
|
|
13
|
+
email: string;
|
|
14
|
+
}, methods: DynamicApiResetPasswordCallbackMethods<Entity>) => Promise<void>;
|
|
15
|
+
export type { DynamicApiServiceCallback, DynamicApiResetPasswordCallback, DynamicApiCallbackMethods, DynamicApiResetPasswordCallbackMethods, };
|
|
@@ -28,11 +28,11 @@ function CreatePoliciesGuardMixin(entity, routeType, version, abilityPredicate)
|
|
|
28
28
|
};
|
|
29
29
|
RoutePoliciesGuard = __decorate([
|
|
30
30
|
(0, common_1.Injectable)(),
|
|
31
|
-
__param(0, (0, common_1.Inject)(`${(0, helpers_1.
|
|
31
|
+
__param(0, (0, common_1.Inject)(`${(0, helpers_1.provideName)(routeType, entity.name, version, 'Service')}`)),
|
|
32
32
|
__metadata("design:paramtypes", [Object])
|
|
33
33
|
], RoutePoliciesGuard);
|
|
34
34
|
Object.defineProperty(RoutePoliciesGuard, 'name', {
|
|
35
|
-
value: `${(0, helpers_1.
|
|
35
|
+
value: `${(0, helpers_1.provideName)(routeType, entity.name, version, 'PoliciesGuard')}`,
|
|
36
36
|
writable: false,
|
|
37
37
|
});
|
|
38
38
|
return RoutePoliciesGuard;
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { Type, ValidationPipeOptions } from '@nestjs/common';
|
|
2
2
|
import { DynamicApiServiceCallback, DynamicAPIServiceProvider } from '../../interfaces';
|
|
3
3
|
import { BaseEntity } from '../../models';
|
|
4
|
-
import { AuthControllerConstructor, DynamicApiRegisterOptions } from './interfaces';
|
|
4
|
+
import { AuthControllerConstructor, DynamicApiRegisterOptions, DynamicApiResetPasswordOptions } from './interfaces';
|
|
5
5
|
declare const authServiceProviderName = "DynamicApiAuthService";
|
|
6
6
|
declare const localStrategyProviderName = "DynamicApiLocalStrategy";
|
|
7
7
|
declare function createLocalStrategyProvider<Entity extends BaseEntity>(loginField: keyof Entity, passwordField: keyof Entity): DynamicAPIServiceProvider;
|
|
8
|
-
declare function createAuthServiceProvider<Entity extends BaseEntity>(userEntity: Type<Entity>, loginField: keyof Entity, passwordField: keyof Entity, additionalFields: (keyof Entity)[] | undefined, registerCallback: DynamicApiServiceCallback<Entity> | undefined, loginCallback: DynamicApiServiceCallback<Entity> | undefined): DynamicAPIServiceProvider;
|
|
9
|
-
declare function createAuthController<Entity extends BaseEntity>(userEntity: Type<Entity>, loginField: keyof Entity, passwordField: keyof Entity, additionalRequestFields: (keyof Entity)[] | undefined, registerOptions: DynamicApiRegisterOptions<Entity> | undefined, validationPipeOptions: ValidationPipeOptions | undefined): AuthControllerConstructor<Entity>;
|
|
8
|
+
declare function createAuthServiceProvider<Entity extends BaseEntity>(userEntity: Type<Entity>, loginField: keyof Entity, passwordField: keyof Entity, additionalFields: (keyof Entity)[] | undefined, registerCallback: DynamicApiServiceCallback<Entity> | undefined, loginCallback: DynamicApiServiceCallback<Entity> | undefined, resetPasswordOptions: DynamicApiResetPasswordOptions<Entity> | undefined): DynamicAPIServiceProvider;
|
|
9
|
+
declare function createAuthController<Entity extends BaseEntity>(userEntity: Type<Entity>, loginField: keyof Entity, passwordField: keyof Entity, additionalRequestFields: (keyof Entity)[] | undefined, registerOptions: DynamicApiRegisterOptions<Entity> | undefined, validationPipeOptions: ValidationPipeOptions | undefined, resetPasswordOptions: DynamicApiResetPasswordOptions<Entity> | undefined): AuthControllerConstructor<Entity>;
|
|
10
10
|
export { authServiceProviderName, createAuthController, createAuthServiceProvider, createLocalStrategyProvider, localStrategyProviderName, };
|
|
@@ -56,7 +56,7 @@ function createLocalStrategyProvider(loginField, passwordField) {
|
|
|
56
56
|
};
|
|
57
57
|
}
|
|
58
58
|
exports.createLocalStrategyProvider = createLocalStrategyProvider;
|
|
59
|
-
function createAuthServiceProvider(userEntity, loginField, passwordField, additionalFields, registerCallback, loginCallback) {
|
|
59
|
+
function createAuthServiceProvider(userEntity, loginField, passwordField, additionalFields, registerCallback, loginCallback, resetPasswordOptions) {
|
|
60
60
|
let AuthService = class AuthService extends services_2.BaseAuthService {
|
|
61
61
|
constructor(model, jwtService, bcryptService) {
|
|
62
62
|
super(model, jwtService, bcryptService);
|
|
@@ -68,6 +68,7 @@ function createAuthServiceProvider(userEntity, loginField, passwordField, additi
|
|
|
68
68
|
this.passwordField = passwordField;
|
|
69
69
|
this.registerCallback = registerCallback;
|
|
70
70
|
this.loginCallback = loginCallback;
|
|
71
|
+
this.resetPasswordOptions = resetPasswordOptions;
|
|
71
72
|
}
|
|
72
73
|
};
|
|
73
74
|
AuthService = __decorate([
|
|
@@ -82,8 +83,8 @@ function createAuthServiceProvider(userEntity, loginField, passwordField, additi
|
|
|
82
83
|
};
|
|
83
84
|
}
|
|
84
85
|
exports.createAuthServiceProvider = createAuthServiceProvider;
|
|
85
|
-
function createAuthController(userEntity, loginField, passwordField, additionalRequestFields, registerOptions, validationPipeOptions) {
|
|
86
|
-
let AuthController = class AuthController extends (0, mixins_1.AuthControllerMixin)(userEntity, loginField, passwordField, additionalRequestFields, registerOptions ?? {}) {
|
|
86
|
+
function createAuthController(userEntity, loginField, passwordField, additionalRequestFields, registerOptions, validationPipeOptions, resetPasswordOptions) {
|
|
87
|
+
let AuthController = class AuthController extends (0, mixins_1.AuthControllerMixin)(userEntity, loginField, passwordField, additionalRequestFields, registerOptions ?? {}, resetPasswordOptions) {
|
|
87
88
|
constructor(service) {
|
|
88
89
|
super(service);
|
|
89
90
|
this.service = service;
|
|
@@ -3,7 +3,7 @@ import { BcryptService } from '../../services';
|
|
|
3
3
|
import { DynamicApiAuthOptions } from './interfaces';
|
|
4
4
|
import { JwtStrategy } from './strategies';
|
|
5
5
|
export declare class AuthModule {
|
|
6
|
-
static forRoot<Entity extends BaseEntity>({ user: { entity: userEntity, loginField, passwordField, requestAdditionalFields, }, jwt: { secret, expiresIn }, register, login, validationPipeOptions, }: DynamicApiAuthOptions<Entity>, extraImports?: any[]): {
|
|
6
|
+
static forRoot<Entity extends BaseEntity>({ user: { entity: userEntity, loginField, passwordField, requestAdditionalFields, }, jwt: { secret, expiresIn }, register, login, resetPassword, validationPipeOptions, }: DynamicApiAuthOptions<Entity>, extraImports?: any[]): {
|
|
7
7
|
module: typeof AuthModule;
|
|
8
8
|
imports: any[];
|
|
9
9
|
providers: (typeof BcryptService | import("../../interfaces/dynamic-api-service-provider.interface").DynamicAPIServiceProvider | typeof JwtStrategy)[];
|
|
@@ -18,9 +18,13 @@ const services_1 = require("../../services");
|
|
|
18
18
|
const auth_helper_1 = require("./auth.helper");
|
|
19
19
|
const strategies_1 = require("./strategies");
|
|
20
20
|
let AuthModule = AuthModule_1 = class AuthModule {
|
|
21
|
-
static forRoot({ user: { entity: userEntity, loginField, passwordField, requestAdditionalFields, }, jwt: { secret, expiresIn }, register, login, validationPipeOptions, }, extraImports = []) {
|
|
22
|
-
const
|
|
23
|
-
const
|
|
21
|
+
static forRoot({ user: { entity: userEntity, loginField, passwordField, requestAdditionalFields, }, jwt: { secret, expiresIn }, register, login, resetPassword, validationPipeOptions, }, extraImports = []) {
|
|
22
|
+
const { resetPasswordCallback, changePasswordCallback, emailField = 'email', expiresInMinutes = 10 } = resetPassword;
|
|
23
|
+
const resetPasswordOptions = resetPasswordCallback
|
|
24
|
+
? { resetPasswordCallback, changePasswordCallback, emailField, expiresInMinutes }
|
|
25
|
+
: undefined;
|
|
26
|
+
const AuthController = (0, auth_helper_1.createAuthController)(userEntity, loginField, passwordField, requestAdditionalFields, register, validationPipeOptions, resetPasswordOptions);
|
|
27
|
+
const AuthServiceProvider = (0, auth_helper_1.createAuthServiceProvider)(userEntity, loginField, passwordField, requestAdditionalFields, register.callback, login.callback, resetPasswordOptions);
|
|
24
28
|
const LocalStrategyProvider = (0, auth_helper_1.createLocalStrategyProvider)(loginField, passwordField);
|
|
25
29
|
return {
|
|
26
30
|
module: AuthModule_1,
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
3
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
4
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
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
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
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
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.ChangePasswordDto = void 0;
|
|
13
|
+
const swagger_1 = require("@nestjs/swagger");
|
|
14
|
+
const class_validator_1 = require("class-validator");
|
|
15
|
+
class ChangePasswordDto {
|
|
16
|
+
}
|
|
17
|
+
exports.ChangePasswordDto = ChangePasswordDto;
|
|
18
|
+
__decorate([
|
|
19
|
+
(0, class_validator_1.IsString)(),
|
|
20
|
+
(0, class_validator_1.IsNotEmpty)(),
|
|
21
|
+
(0, swagger_1.ApiProperty)(),
|
|
22
|
+
__metadata("design:type", String)
|
|
23
|
+
], ChangePasswordDto.prototype, "resetPasswordToken", void 0);
|
|
24
|
+
__decorate([
|
|
25
|
+
(0, class_validator_1.IsString)(),
|
|
26
|
+
(0, class_validator_1.IsNotEmpty)(),
|
|
27
|
+
(0, swagger_1.ApiProperty)(),
|
|
28
|
+
__metadata("design:type", String)
|
|
29
|
+
], ChangePasswordDto.prototype, "newPassword", void 0);
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
3
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
4
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
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
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
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
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.ResetPasswordDto = void 0;
|
|
13
|
+
const swagger_1 = require("@nestjs/swagger");
|
|
14
|
+
const class_validator_1 = require("class-validator");
|
|
15
|
+
class ResetPasswordDto {
|
|
16
|
+
}
|
|
17
|
+
exports.ResetPasswordDto = ResetPasswordDto;
|
|
18
|
+
__decorate([
|
|
19
|
+
(0, class_validator_1.IsString)(),
|
|
20
|
+
(0, class_validator_1.IsNotEmpty)(),
|
|
21
|
+
(0, class_validator_1.IsEmail)(),
|
|
22
|
+
(0, swagger_1.ApiProperty)(),
|
|
23
|
+
__metadata("design:type", String)
|
|
24
|
+
], ResetPasswordDto.prototype, "email", void 0);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Type, ValidationPipeOptions } from '@nestjs/common';
|
|
2
|
-
import { DynamicApiServiceCallback, RegisterAbilityPredicate } from '../../../interfaces';
|
|
2
|
+
import { DynamicApiResetPasswordCallback, DynamicApiServiceCallback, RegisterAbilityPredicate } from '../../../interfaces';
|
|
3
3
|
import { BaseEntity } from '../../../models';
|
|
4
4
|
type DynamicApiJWTOptions = {
|
|
5
5
|
secret: string;
|
|
@@ -23,11 +23,18 @@ type DynamicApiUserOptions<Entity extends BaseEntity = any> = {
|
|
|
23
23
|
passwordField?: keyof Entity;
|
|
24
24
|
requestAdditionalFields?: (keyof Entity)[];
|
|
25
25
|
};
|
|
26
|
+
type DynamicApiResetPasswordOptions<Entity extends BaseEntity = any> = {
|
|
27
|
+
resetPasswordCallback: DynamicApiResetPasswordCallback<Entity>;
|
|
28
|
+
changePasswordCallback: DynamicApiServiceCallback<Entity>;
|
|
29
|
+
emailField: keyof Entity | string;
|
|
30
|
+
expiresInMinutes: number;
|
|
31
|
+
};
|
|
26
32
|
type DynamicApiAuthOptions<Entity extends BaseEntity = any> = {
|
|
27
33
|
user: DynamicApiUserOptions<Entity>;
|
|
28
34
|
login?: DynamicApiLoginOptions<Entity>;
|
|
29
35
|
register?: DynamicApiRegisterOptions<Entity>;
|
|
30
36
|
jwt?: DynamicApiJWTOptions;
|
|
37
|
+
resetPassword?: Partial<DynamicApiResetPasswordOptions<Entity>>;
|
|
31
38
|
validationPipeOptions?: ValidationPipeOptions;
|
|
32
39
|
};
|
|
33
|
-
export type { DynamicApiAuthOptions, DynamicApiRegisterOptions, DynamicApiUserOptions, DynamicApiJWTOptions, DynamicApiLoginOptions, };
|
|
40
|
+
export type { DynamicApiAuthOptions, DynamicApiRegisterOptions, DynamicApiUserOptions, DynamicApiJWTOptions, DynamicApiLoginOptions, DynamicApiResetPasswordOptions, };
|
|
@@ -7,6 +7,7 @@ interface AuthService<Entity extends BaseEntity> {
|
|
|
7
7
|
login(user: Entity): Promise<LoginResponse>;
|
|
8
8
|
register(userToCreate: Partial<Entity>): Promise<LoginResponse>;
|
|
9
9
|
getAccount(user: Entity): Promise<Entity>;
|
|
10
|
-
|
|
10
|
+
resetPassword(email: string): Promise<void>;
|
|
11
|
+
changePassword(resetPasswordToken: string, newPassword: string): Promise<void>;
|
|
11
12
|
}
|
|
12
13
|
export type { AuthService, LoginResponse };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Type } from '@nestjs/common';
|
|
2
2
|
import { BaseEntity } from '../../../models';
|
|
3
|
-
import { AuthControllerConstructor, DynamicApiRegisterOptions } from '../interfaces';
|
|
4
|
-
declare function AuthControllerMixin<Entity extends BaseEntity>(userEntity: Type<Entity>, loginField: keyof Entity, passwordField: keyof Entity, additionalRequestFields?: (keyof Entity)[], { additionalFields: additionalRegisterFields, protected: registerProtected, abilityPredicate: registerAbilityPredicate, }?: DynamicApiRegisterOptions<Entity>): AuthControllerConstructor<Entity>;
|
|
3
|
+
import { AuthControllerConstructor, DynamicApiRegisterOptions, DynamicApiResetPasswordOptions } from '../interfaces';
|
|
4
|
+
declare function AuthControllerMixin<Entity extends BaseEntity>(userEntity: Type<Entity>, loginField: keyof Entity, passwordField: keyof Entity, additionalRequestFields?: (keyof Entity)[], { additionalFields: additionalRegisterFields, protected: registerProtected, abilityPredicate: registerAbilityPredicate, }?: DynamicApiRegisterOptions<Entity>, resetPasswordOptions?: DynamicApiResetPasswordOptions<Entity>): AuthControllerConstructor<Entity>;
|
|
5
5
|
export { AuthControllerMixin };
|
|
@@ -19,9 +19,11 @@ const class_validator_1 = require("class-validator");
|
|
|
19
19
|
const builders_1 = require("../../../builders");
|
|
20
20
|
const decorators_1 = require("../../../decorators");
|
|
21
21
|
const helpers_1 = require("../../../helpers");
|
|
22
|
+
const change_password_dto_1 = require("../dtos/change-password.dto");
|
|
23
|
+
const reset_password_dto_1 = require("../dtos/reset-password.dto");
|
|
22
24
|
const guards_1 = require("../guards");
|
|
23
25
|
const auth_register_policies_guard_mixin_1 = require("./auth-register-policies-guard.mixin");
|
|
24
|
-
function AuthControllerMixin(userEntity, loginField, passwordField, additionalRequestFields = [], { additionalFields: additionalRegisterFields, protected: registerProtected, abilityPredicate: registerAbilityPredicate, } = {}) {
|
|
26
|
+
function AuthControllerMixin(userEntity, loginField, passwordField, additionalRequestFields = [], { additionalFields: additionalRegisterFields, protected: registerProtected, abilityPredicate: registerAbilityPredicate, } = {}, resetPasswordOptions) {
|
|
25
27
|
var _a;
|
|
26
28
|
if (!loginField || !passwordField) {
|
|
27
29
|
throw new Error('Login and password fields are required');
|
|
@@ -77,12 +79,18 @@ function AuthControllerMixin(userEntity, loginField, passwordField, additionalRe
|
|
|
77
79
|
getAccount(req) {
|
|
78
80
|
return this.service.getAccount(req.user);
|
|
79
81
|
}
|
|
80
|
-
login(req,
|
|
82
|
+
login(req, _) {
|
|
81
83
|
return this.service.login(req.user);
|
|
82
84
|
}
|
|
83
85
|
register(body) {
|
|
84
86
|
return this.service.register(body);
|
|
85
87
|
}
|
|
88
|
+
resetPassword({ email }) {
|
|
89
|
+
return this.service.resetPassword(email);
|
|
90
|
+
}
|
|
91
|
+
changePassword({ resetPasswordToken, newPassword }) {
|
|
92
|
+
return this.service.changePassword(resetPasswordToken, newPassword);
|
|
93
|
+
}
|
|
86
94
|
}
|
|
87
95
|
__decorate([
|
|
88
96
|
(0, swagger_1.ApiBearerAuth)(),
|
|
@@ -118,6 +126,24 @@ function AuthControllerMixin(userEntity, loginField, passwordField, additionalRe
|
|
|
118
126
|
__metadata("design:paramtypes", [AuthRegisterDto]),
|
|
119
127
|
__metadata("design:returntype", void 0)
|
|
120
128
|
], BaseAuthController.prototype, "register", null);
|
|
129
|
+
__decorate([
|
|
130
|
+
(0, decorators_1.ApiEndpointVisibility)(!!resetPasswordOptions, (0, decorators_1.Public)()),
|
|
131
|
+
(0, common_1.HttpCode)(common_1.HttpStatus.NO_CONTENT),
|
|
132
|
+
(0, common_1.Post)('reset-password'),
|
|
133
|
+
__param(0, (0, common_1.Body)()),
|
|
134
|
+
__metadata("design:type", Function),
|
|
135
|
+
__metadata("design:paramtypes", [reset_password_dto_1.ResetPasswordDto]),
|
|
136
|
+
__metadata("design:returntype", void 0)
|
|
137
|
+
], BaseAuthController.prototype, "resetPassword", null);
|
|
138
|
+
__decorate([
|
|
139
|
+
(0, decorators_1.ApiEndpointVisibility)(!!resetPasswordOptions, (0, decorators_1.Public)()),
|
|
140
|
+
(0, common_1.HttpCode)(common_1.HttpStatus.NO_CONTENT),
|
|
141
|
+
(0, common_1.Patch)('change-password'),
|
|
142
|
+
__param(0, (0, common_1.Body)()),
|
|
143
|
+
__metadata("design:type", Function),
|
|
144
|
+
__metadata("design:paramtypes", [change_password_dto_1.ChangePasswordDto]),
|
|
145
|
+
__metadata("design:returntype", void 0)
|
|
146
|
+
], BaseAuthController.prototype, "changePassword", null);
|
|
121
147
|
return BaseAuthController;
|
|
122
148
|
}
|
|
123
149
|
exports.AuthControllerMixin = AuthControllerMixin;
|
|
@@ -27,6 +27,7 @@ import { Model } from 'mongoose';
|
|
|
27
27
|
import { DynamicApiServiceCallback } from '../../../interfaces';
|
|
28
28
|
import { BaseEntity } from '../../../models';
|
|
29
29
|
import { BaseService, BcryptService } from '../../../services';
|
|
30
|
+
import { DynamicApiResetPasswordOptions } from '../interfaces';
|
|
30
31
|
export declare abstract class BaseAuthService<Entity extends BaseEntity> extends BaseService<Entity> {
|
|
31
32
|
protected readonly model: Model<Entity>;
|
|
32
33
|
protected readonly jwtService: JwtService;
|
|
@@ -36,6 +37,9 @@ export declare abstract class BaseAuthService<Entity extends BaseEntity> extends
|
|
|
36
37
|
protected additionalRequestFields: (keyof Entity)[];
|
|
37
38
|
protected registerCallback: DynamicApiServiceCallback<Entity> | undefined;
|
|
38
39
|
protected loginCallback: DynamicApiServiceCallback<Entity> | undefined;
|
|
40
|
+
protected resetPasswordOptions: DynamicApiResetPasswordOptions<Entity> | undefined;
|
|
41
|
+
private resetPasswordCallbackMethods;
|
|
42
|
+
private readonly logger;
|
|
39
43
|
protected constructor(model: Model<Entity>, jwtService: JwtService, bcryptService: BcryptService);
|
|
40
44
|
protected validateUser(login: string, pass: string): Promise<Entity>;
|
|
41
45
|
protected login(user: Entity, fromMember?: boolean): Promise<{
|
|
@@ -45,8 +49,7 @@ export declare abstract class BaseAuthService<Entity extends BaseEntity> extends
|
|
|
45
49
|
accessToken: string;
|
|
46
50
|
}>;
|
|
47
51
|
protected getAccount({ id }: Entity): Promise<Entity>;
|
|
48
|
-
protected
|
|
49
|
-
|
|
50
|
-
}>;
|
|
52
|
+
protected resetPassword(email: string): Promise<void>;
|
|
53
|
+
protected changePassword(resetPasswordToken: string, newPassword: string): Promise<void>;
|
|
51
54
|
private buildUserFields;
|
|
52
55
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.BaseAuthService = void 0;
|
|
4
|
+
const common_1 = require("@nestjs/common");
|
|
4
5
|
const services_1 = require("../../../services");
|
|
5
6
|
class BaseAuthService extends services_1.BaseService {
|
|
6
7
|
constructor(model, jwtService, bcryptService) {
|
|
@@ -11,6 +12,7 @@ class BaseAuthService extends services_1.BaseService {
|
|
|
11
12
|
this.loginField = 'email';
|
|
12
13
|
this.passwordField = 'password';
|
|
13
14
|
this.additionalRequestFields = [];
|
|
15
|
+
this.logger = new common_1.Logger('AuthService');
|
|
14
16
|
}
|
|
15
17
|
async validateUser(login, pass) {
|
|
16
18
|
const user = (await this.model.findOne({ [this.loginField]: login }).lean().exec());
|
|
@@ -33,7 +35,7 @@ class BaseAuthService extends services_1.BaseService {
|
|
|
33
35
|
];
|
|
34
36
|
const payload = this.buildUserFields(user, fieldsToBuild);
|
|
35
37
|
if (!fromMember && this.loginCallback) {
|
|
36
|
-
await this.loginCallback(payload, this.
|
|
38
|
+
await this.loginCallback(payload, this.callbackMethods);
|
|
37
39
|
}
|
|
38
40
|
return {
|
|
39
41
|
accessToken: this.jwtService.sign(payload),
|
|
@@ -45,7 +47,7 @@ class BaseAuthService extends services_1.BaseService {
|
|
|
45
47
|
const { _id } = await this.model.create({ ...userToCreate, [this.passwordField]: hashedPassword });
|
|
46
48
|
const user = await this.findOneDocument(_id);
|
|
47
49
|
if (this.registerCallback) {
|
|
48
|
-
await this.registerCallback(user, this.
|
|
50
|
+
await this.registerCallback(user, this.callbackMethods);
|
|
49
51
|
}
|
|
50
52
|
return this.login(user, true);
|
|
51
53
|
}
|
|
@@ -62,11 +64,67 @@ class BaseAuthService extends services_1.BaseService {
|
|
|
62
64
|
];
|
|
63
65
|
return this.buildUserFields(user, fieldsToBuild);
|
|
64
66
|
}
|
|
65
|
-
async
|
|
67
|
+
async resetPassword(email) {
|
|
68
|
+
if (!this.resetPasswordOptions) {
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
this.resetPasswordCallbackMethods = {
|
|
72
|
+
findUserByEmail: async (email) => {
|
|
73
|
+
const user = await this.model.findOne({ [this.resetPasswordOptions.emailField]: email })
|
|
74
|
+
.lean()
|
|
75
|
+
.exec();
|
|
76
|
+
if (!user) {
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
return this.buildInstance(user);
|
|
80
|
+
},
|
|
81
|
+
updateUserByEmail: async (email, data) => {
|
|
82
|
+
const user = await this.model.findOneAndUpdate({ [this.resetPasswordOptions.emailField]: email }, data, { new: true }).lean().exec();
|
|
83
|
+
if (!user) {
|
|
84
|
+
this.handleDocumentNotFound();
|
|
85
|
+
}
|
|
86
|
+
return this.buildInstance(user);
|
|
87
|
+
},
|
|
88
|
+
};
|
|
89
|
+
const { resetPasswordCallback, expiresInMinutes } = this.resetPasswordOptions;
|
|
90
|
+
const resetPasswordToken = this.jwtService.sign({ email }, { expiresIn: expiresInMinutes * 60 });
|
|
91
|
+
await resetPasswordCallback({ resetPasswordToken, email }, this.resetPasswordCallbackMethods);
|
|
92
|
+
}
|
|
93
|
+
async changePassword(resetPasswordToken, newPassword) {
|
|
94
|
+
let email;
|
|
95
|
+
let exp;
|
|
96
|
+
try {
|
|
97
|
+
const decoded = this.jwtService.decode(resetPasswordToken);
|
|
98
|
+
email = decoded.email;
|
|
99
|
+
exp = decoded.exp;
|
|
100
|
+
}
|
|
101
|
+
catch (error) {
|
|
102
|
+
this.logger.warn('Invalid reset password token');
|
|
103
|
+
}
|
|
104
|
+
if (!email || !exp) {
|
|
105
|
+
throw new common_1.BadRequestException('Invalid reset password token. Please redo the reset password process.');
|
|
106
|
+
}
|
|
107
|
+
const now = Math.round(Date.now() / 1000);
|
|
108
|
+
if (exp <= now) {
|
|
109
|
+
throw new common_1.UnauthorizedException('Time to reset password has expired. Please redo the reset password process.');
|
|
110
|
+
}
|
|
111
|
+
let userId;
|
|
112
|
+
try {
|
|
113
|
+
const { _id } = await this.findOneDocument(undefined, { [this.resetPasswordOptions.emailField]: email });
|
|
114
|
+
userId = _id.toString();
|
|
115
|
+
}
|
|
116
|
+
catch (error) {
|
|
117
|
+
this.logger.warn('Invalid email, user not found');
|
|
118
|
+
}
|
|
119
|
+
if (!userId) {
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
66
122
|
const hashedPassword = await this.bcryptService.hashPassword(newPassword);
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
123
|
+
await this.model.updateOne({ _id: userId }, { [this.passwordField]: hashedPassword });
|
|
124
|
+
if (this.resetPasswordOptions?.changePasswordCallback) {
|
|
125
|
+
const user = await this.findOneDocument(userId);
|
|
126
|
+
await this.resetPasswordOptions.changePasswordCallback(this.buildInstance(user), this.callbackMethods);
|
|
127
|
+
}
|
|
70
128
|
}
|
|
71
129
|
buildUserFields(user, fieldsToBuild) {
|
|
72
130
|
return this.buildInstance(fieldsToBuild.reduce((acc, field) => (user[field] !== undefined ? { ...acc, [field]: user[field] } : acc), {}));
|
|
@@ -15,7 +15,7 @@ class BaseCreateManyService extends services_1.BaseService {
|
|
|
15
15
|
.lean()
|
|
16
16
|
.exec();
|
|
17
17
|
if (this.callback && documents.length) {
|
|
18
|
-
await Promise.all(documents.map((document) => this.callback(document, this.
|
|
18
|
+
await Promise.all(documents.map((document) => this.callback(document, this.callbackMethods)));
|
|
19
19
|
}
|
|
20
20
|
return documents.map((d) => this.buildInstance(d));
|
|
21
21
|
}
|
|
@@ -16,11 +16,10 @@ exports.CreateManyControllerMixin = void 0;
|
|
|
16
16
|
const common_1 = require("@nestjs/common");
|
|
17
17
|
const builders_1 = require("../../builders");
|
|
18
18
|
const helpers_1 = require("../../helpers");
|
|
19
|
-
const controller_mixin_helper_1 = require("../../helpers/controller-mixin.helper");
|
|
20
19
|
const mixins_1 = require("../../mixins");
|
|
21
20
|
function CreateManyControllerMixin(entity, controllerOptions, routeConfig, version) {
|
|
22
21
|
var _a;
|
|
23
|
-
const { routeType, description, isPublic, RouteBody, RoutePresenter, abilityPredicate, } = (0,
|
|
22
|
+
const { routeType, description, isPublic, RouteBody, RoutePresenter, abilityPredicate, } = (0, helpers_1.getControllerMixinData)(entity, controllerOptions, routeConfig, version);
|
|
24
23
|
const routeDecoratorsBuilder = new builders_1.RouteDecoratorsBuilder(routeType, entity, version, description, isPublic, {
|
|
25
24
|
body: RouteBody,
|
|
26
25
|
presenter: RoutePresenter,
|