mongodb-dynamic-api 2.2.1 → 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.
Files changed (52) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/package.json +3 -1
  3. package/src/decorators/api-endpoint-visibility.decorator.d.ts +3 -0
  4. package/src/decorators/api-endpoint-visibility.decorator.js +10 -0
  5. package/src/decorators/index.d.ts +1 -0
  6. package/src/decorators/index.js +1 -0
  7. package/src/dynamic-api.module.js +1 -4
  8. package/src/helpers/index.d.ts +2 -0
  9. package/src/helpers/index.js +2 -0
  10. package/src/interfaces/dynamic-api-service-callback.interface.d.ts +14 -27
  11. package/src/modules/auth/auth.helper.d.ts +3 -3
  12. package/src/modules/auth/auth.helper.js +4 -3
  13. package/src/modules/auth/auth.module.d.ts +1 -1
  14. package/src/modules/auth/auth.module.js +7 -3
  15. package/src/modules/auth/dtos/change-password.dto.d.ts +4 -0
  16. package/src/modules/auth/dtos/change-password.dto.js +29 -0
  17. package/src/modules/auth/dtos/reset-password.dto.d.ts +3 -0
  18. package/src/modules/auth/dtos/reset-password.dto.js +24 -0
  19. package/src/modules/auth/interfaces/auth-options.interface.d.ts +9 -2
  20. package/src/modules/auth/interfaces/auth-service.interface.d.ts +2 -1
  21. package/src/modules/auth/mixins/auth-controller.mixin.d.ts +2 -2
  22. package/src/modules/auth/mixins/auth-controller.mixin.js +28 -2
  23. package/src/modules/auth/services/base-auth.service.d.ts +6 -3
  24. package/src/modules/auth/services/base-auth.service.js +64 -6
  25. package/src/routes/create-many/base-create-many.service.js +1 -1
  26. package/src/routes/create-many/create-many-controller.mixin.js +1 -2
  27. package/src/routes/create-many/create-many.helper.js +1 -0
  28. package/src/routes/create-many/create-many.module.d.ts +1 -1
  29. package/src/routes/create-many/create-many.module.js +1 -1
  30. package/src/routes/create-one/base-create-one.service.js +1 -1
  31. package/src/routes/create-one/create-one-controller.mixin.js +1 -2
  32. package/src/routes/create-one/create-one.helper.js +1 -0
  33. package/src/routes/delete-many/delete-many-controller.mixin.js +1 -2
  34. package/src/routes/delete-one/delete-one-controller.mixin.js +1 -2
  35. package/src/routes/duplicate-many/base-duplicate-many.service.js +1 -1
  36. package/src/routes/duplicate-many/duplicate-many-controller.mixin.js +1 -2
  37. package/src/routes/duplicate-one/base-duplicate-one.service.js +1 -1
  38. package/src/routes/duplicate-one/duplicate-one-controller.mixin.js +1 -2
  39. package/src/routes/get-many/base-get-many.service.js +1 -1
  40. package/src/routes/get-many/get-many-controller.mixin.js +1 -2
  41. package/src/routes/get-one/base-get-one.service.js +1 -1
  42. package/src/routes/get-one/get-one-controller.mixin.js +1 -2
  43. package/src/routes/replace-one/base-replace-one.service.js +1 -1
  44. package/src/routes/replace-one/replace-one-controller.mixin.js +1 -2
  45. package/src/routes/update-many/base-update-many.service.js +1 -1
  46. package/src/routes/update-many/update-many-controller.mixin.js +1 -2
  47. package/src/routes/update-one/base-update-one.service.js +1 -1
  48. package/src/routes/update-one/update-one-controller.mixin.js +1 -2
  49. package/src/services/base/base.service.d.ts +6 -2
  50. package/src/services/base/base.service.js +20 -1
  51. package/src/version.json +1 -1
  52. package/tsconfig.tsbuildinfo +1 -1
package/CHANGELOG.md CHANGED
@@ -1,5 +1,12 @@
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
+
3
10
  ## [2.2.1](https://github.com/MikeDev75015/mongodb-dynamic-api/compare/v2.2.0...v2.2.1) (2024-04-30)
4
11
 
5
12
  ## [2.2.0](https://github.com/MikeDev75015/mongodb-dynamic-api/compare/v2.1.10...v2.2.0) (2024-04-30)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mongodb-dynamic-api",
3
- "version": "2.2.1",
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,3 @@
1
+ import { CustomDecorator } from '@nestjs/common';
2
+ declare function ApiEndpointVisibility(condition: boolean, decorator?: MethodDecorator | CustomDecorator): MethodDecorator | CustomDecorator;
3
+ export { ApiEndpointVisibility };
@@ -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;
@@ -1,3 +1,4 @@
1
+ export * from './api-endpoint-visibility.decorator';
1
2
  export * from './public.decorator';
2
3
  export * from './schema-options.decorator';
3
4
  export * from './validator-pipe.decorator';
@@ -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,3 +1,5 @@
1
+ export * from './controller-ability-predicates.helper';
2
+ export * from './controller-mixin.helper';
1
3
  export * from './format.helper';
2
4
  export * from './route-decorators.helper';
3
5
  export * from './route-description.helper';
@@ -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 DynamicApiServiceCallback<Entity extends BaseEntity> = (entity: Partial<Entity>, model: Model<Entity>) => Promise<void>;
28
- export type { DynamicApiServiceCallback };
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, };
@@ -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 AuthController = (0, auth_helper_1.createAuthController)(userEntity, loginField, passwordField, requestAdditionalFields, register, validationPipeOptions);
23
- const AuthServiceProvider = (0, auth_helper_1.createAuthServiceProvider)(userEntity, loginField, passwordField, requestAdditionalFields, register.callback, login.callback);
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,4 @@
1
+ export declare class ChangePasswordDto {
2
+ resetPasswordToken: string;
3
+ newPassword: string;
4
+ }
@@ -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,3 @@
1
+ export declare class ResetPasswordDto {
2
+ email: string;
3
+ }
@@ -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
- changePassword(userId: string, newPassword: string): Promise<LoginResponse>;
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, body) {
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 changePassword(userId: string, newPassword: string): Promise<{
49
- accessToken: string;
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.model);
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.model);
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 changePassword(userId, newPassword) {
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
- const { _id } = await this.model.findOneAndUpdate({ _id: userId }, { [this.passwordField]: hashedPassword }, { new: true });
68
- const user = await this.findOneDocument(_id);
69
- return this.login(user, true);
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.model)));
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, controller_mixin_helper_1.getControllerMixinData)(entity, controllerOptions, routeConfig, version);
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,
@@ -28,6 +28,7 @@ function createCreateManyServiceProvider(entity, version, callback) {
28
28
  super(model);
29
29
  this.model = model;
30
30
  this.entity = entity;
31
+ this.callback = callback;
31
32
  }
32
33
  };
33
34
  CreateManyService = __decorate([
@@ -2,5 +2,5 @@ import { DynamicModule, Type, ValidationPipeOptions } from '@nestjs/common';
2
2
  import { DynamicApiControllerOptions, DynamicAPIRouteConfig } from '../../interfaces';
3
3
  import { BaseEntity } from '../../models';
4
4
  export declare class CreateManyModule {
5
- static forFeature<Entity extends BaseEntity>(databaseModule: DynamicModule, entity: Type<Entity>, controllerOptions: DynamicApiControllerOptions<Entity>, routeConfig: DynamicAPIRouteConfig<Entity>, version?: string, validationPipeOptions?: ValidationPipeOptions): Promise<DynamicModule>;
5
+ static forFeature<Entity extends BaseEntity>(databaseModule: DynamicModule, entity: Type<Entity>, controllerOptions: DynamicApiControllerOptions<Entity>, routeConfig: DynamicAPIRouteConfig<Entity>, version?: string, validationPipeOptions?: ValidationPipeOptions): DynamicModule;
6
6
  }
@@ -11,7 +11,7 @@ exports.CreateManyModule = void 0;
11
11
  const common_1 = require("@nestjs/common");
12
12
  const create_many_helper_1 = require("./create-many.helper");
13
13
  let CreateManyModule = CreateManyModule_1 = class CreateManyModule {
14
- static async forFeature(databaseModule, entity, controllerOptions, routeConfig, version, validationPipeOptions) {
14
+ static forFeature(databaseModule, entity, controllerOptions, routeConfig, version, validationPipeOptions) {
15
15
  const controller = (0, create_many_helper_1.createCreateManyController)(entity, controllerOptions, routeConfig, version, validationPipeOptions);
16
16
  const ServiceProvider = (0, create_many_helper_1.createCreateManyServiceProvider)(entity, version, routeConfig.callback);
17
17
  return {
@@ -12,7 +12,7 @@ class BaseCreateOneService extends services_1.BaseService {
12
12
  const { _id } = await this.model.create(partial);
13
13
  const document = await this.model.findOne({ _id }).lean().exec();
14
14
  if (this.callback) {
15
- await this.callback(document, this.model);
15
+ await this.callback(document, this.callbackMethods);
16
16
  }
17
17
  return this.buildInstance(document);
18
18
  }
@@ -16,11 +16,10 @@ exports.CreateOneControllerMixin = 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 CreateOneControllerMixin(entity, controllerOptions, routeConfig, version) {
22
21
  var _a;
23
- const { routeType, description, isPublic, RouteBody, RoutePresenter, abilityPredicate, } = (0, controller_mixin_helper_1.getControllerMixinData)(entity, controllerOptions, routeConfig, version);
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,
@@ -28,6 +28,7 @@ function createCreateOneServiceProvider(entity, version, callback) {
28
28
  super(model);
29
29
  this.model = model;
30
30
  this.entity = entity;
31
+ this.callback = callback;
31
32
  }
32
33
  };
33
34
  CreateOneService = __decorate([