@lenne.tech/nest-server 2.0.1 → 3.0.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 (126) hide show
  1. package/dist/config.env.js +4 -4
  2. package/dist/config.env.js.map +1 -1
  3. package/dist/core/common/args/filter.args.js +3 -3
  4. package/dist/core/common/args/filter.args.js.map +1 -1
  5. package/dist/core/common/args/pagination.args.js +13 -13
  6. package/dist/core/common/args/pagination.args.js.map +1 -1
  7. package/dist/core/common/decorators/graphql-user.decorator.js +1 -1
  8. package/dist/core/common/decorators/graphql-user.decorator.js.map +1 -1
  9. package/dist/core/common/decorators/rest-user.decorator.js +1 -1
  10. package/dist/core/common/decorators/rest-user.decorator.js.map +1 -1
  11. package/dist/core/common/decorators/restricted.decorator.js +3 -3
  12. package/dist/core/common/decorators/restricted.decorator.js.map +1 -1
  13. package/dist/core/common/decorators/roles.decorator.js +1 -1
  14. package/dist/core/common/decorators/roles.decorator.js.map +1 -1
  15. package/dist/core/common/enums/comparison-operator.enum.js +1 -1
  16. package/dist/core/common/enums/comparison-operator.enum.js.map +1 -1
  17. package/dist/core/common/enums/logical-operator.enum.js +1 -1
  18. package/dist/core/common/enums/logical-operator.enum.js.map +1 -1
  19. package/dist/core/common/enums/sort-order.emum.js +1 -1
  20. package/dist/core/common/enums/sort-order.emum.js.map +1 -1
  21. package/dist/core/common/helpers/file.helper.js +3 -3
  22. package/dist/core/common/helpers/file.helper.js.map +1 -1
  23. package/dist/core/common/helpers/input.helper.js +3 -3
  24. package/dist/core/common/helpers/input.helper.js.map +1 -1
  25. package/dist/core/common/helpers/service.helper.d.ts +1 -0
  26. package/dist/core/common/helpers/service.helper.js +18 -1
  27. package/dist/core/common/helpers/service.helper.js.map +1 -1
  28. package/dist/core/common/inputs/combined-filter.input.js +3 -3
  29. package/dist/core/common/inputs/combined-filter.input.js.map +1 -1
  30. package/dist/core/common/inputs/filter.input.js +3 -3
  31. package/dist/core/common/inputs/filter.input.js.map +1 -1
  32. package/dist/core/common/inputs/single-filter.input.js +6 -6
  33. package/dist/core/common/inputs/single-filter.input.js.map +1 -1
  34. package/dist/core/common/inputs/sort.input.js +3 -3
  35. package/dist/core/common/inputs/sort.input.js.map +1 -1
  36. package/dist/core/common/interceptors/check-response.interceptor.js +3 -3
  37. package/dist/core/common/interceptors/check-response.interceptor.js.map +1 -1
  38. package/dist/core/common/models/core-persistence.model.js +14 -14
  39. package/dist/core/common/models/core-persistence.model.js.map +1 -1
  40. package/dist/core/common/pipes/check-input.pipe.js +5 -5
  41. package/dist/core/common/pipes/check-input.pipe.js.map +1 -1
  42. package/dist/core/common/scalars/any.scalar.js +1 -1
  43. package/dist/core/common/scalars/any.scalar.js.map +1 -1
  44. package/dist/core/common/scalars/date.scalar.js +1 -1
  45. package/dist/core/common/scalars/date.scalar.js.map +1 -1
  46. package/dist/core/common/scalars/json.scalar.js +1 -1
  47. package/dist/core/common/scalars/json.scalar.js.map +1 -1
  48. package/dist/core/common/services/config.service.d.ts +1 -1
  49. package/dist/core/common/services/config.service.js +3 -3
  50. package/dist/core/common/services/config.service.js.map +1 -1
  51. package/dist/core/common/services/email.service.js +1 -1
  52. package/dist/core/common/services/email.service.js.map +1 -1
  53. package/dist/core/common/services/template.service.js +2 -2
  54. package/dist/core/common/services/template.service.js.map +1 -1
  55. package/dist/core/modules/auth/core-auth.model.js +2 -2
  56. package/dist/core/modules/auth/core-auth.model.js.map +1 -1
  57. package/dist/core/modules/auth/core-auth.module.js +6 -1
  58. package/dist/core/modules/auth/core-auth.module.js.map +1 -1
  59. package/dist/core/modules/auth/core-auth.resolver.js +4 -4
  60. package/dist/core/modules/auth/core-auth.resolver.js.map +1 -1
  61. package/dist/core/modules/auth/guards/auth.guard.js +10 -6
  62. package/dist/core/modules/auth/guards/auth.guard.js.map +1 -1
  63. package/dist/core/modules/auth/guards/roles.guard.js +2 -2
  64. package/dist/core/modules/auth/guards/roles.guard.js.map +1 -1
  65. package/dist/core/modules/auth/jwt.strategy.js +2 -2
  66. package/dist/core/modules/auth/jwt.strategy.js.map +1 -1
  67. package/dist/core/modules/auth/services/core-auth.service.js +1 -1
  68. package/dist/core/modules/auth/services/core-auth.service.js.map +1 -1
  69. package/dist/core/modules/user/core-basic-user.service.d.ts +1 -1
  70. package/dist/core/modules/user/core-user.model.js +18 -18
  71. package/dist/core/modules/user/core-user.model.js.map +1 -1
  72. package/dist/core/modules/user/core-user.service.d.ts +4 -3
  73. package/dist/core/modules/user/core-user.service.js +26 -1
  74. package/dist/core/modules/user/core-user.service.js.map +1 -1
  75. package/dist/core/modules/user/inputs/core-user-create.input.js +3 -3
  76. package/dist/core/modules/user/inputs/core-user-create.input.js.map +1 -1
  77. package/dist/core/modules/user/inputs/core-user.input.js +15 -15
  78. package/dist/core/modules/user/inputs/core-user.input.js.map +1 -1
  79. package/dist/core.module.js +9 -2
  80. package/dist/core.module.js.map +1 -1
  81. package/dist/server/common/models/persistence.model.js +5 -5
  82. package/dist/server/common/models/persistence.model.js.map +1 -1
  83. package/dist/server/modules/auth/auth.model.js +2 -2
  84. package/dist/server/modules/auth/auth.model.js.map +1 -1
  85. package/dist/server/modules/auth/auth.module.js +1 -1
  86. package/dist/server/modules/auth/auth.module.js.map +1 -1
  87. package/dist/server/modules/auth/auth.resolver.js +4 -4
  88. package/dist/server/modules/auth/auth.resolver.js.map +1 -1
  89. package/dist/server/modules/file/file.controller.js +7 -7
  90. package/dist/server/modules/file/file.controller.js.map +1 -1
  91. package/dist/server/modules/user/avatar.controller.js +6 -6
  92. package/dist/server/modules/user/avatar.controller.js.map +1 -1
  93. package/dist/server/modules/user/inputs/user-create.input.js +1 -1
  94. package/dist/server/modules/user/inputs/user-create.input.js.map +1 -1
  95. package/dist/server/modules/user/inputs/user.input.js +1 -1
  96. package/dist/server/modules/user/inputs/user.input.js.map +1 -1
  97. package/dist/server/modules/user/user.model.d.ts +1 -1
  98. package/dist/server/modules/user/user.model.js +8 -8
  99. package/dist/server/modules/user/user.model.js.map +1 -1
  100. package/dist/server/modules/user/user.module.js +11 -2
  101. package/dist/server/modules/user/user.module.js.map +1 -1
  102. package/dist/server/modules/user/user.resolver.d.ts +4 -2
  103. package/dist/server/modules/user/user.resolver.js +33 -30
  104. package/dist/server/modules/user/user.resolver.js.map +1 -1
  105. package/dist/server/modules/user/user.service.d.ts +3 -1
  106. package/dist/server/modules/user/user.service.js +9 -6
  107. package/dist/server/modules/user/user.service.js.map +1 -1
  108. package/dist/server/server.controller.js +5 -5
  109. package/dist/server/server.controller.js.map +1 -1
  110. package/dist/server/server.module.js +1 -1
  111. package/dist/server/server.module.js.map +1 -1
  112. package/dist/test/test.helper.js +1 -1
  113. package/dist/test/test.helper.js.map +1 -1
  114. package/dist/tsconfig.build.tsbuildinfo +1 -1
  115. package/package.json +44 -54
  116. package/src/core/common/helpers/service.helper.ts +21 -2
  117. package/src/core/common/models/core-persistence.model.ts +1 -1
  118. package/src/core/common/services/config.service.ts +7 -5
  119. package/src/core/modules/auth/core-auth.module.ts +5 -0
  120. package/src/core/modules/auth/guards/auth.guard.ts +5 -0
  121. package/src/core/modules/user/core-basic-user.service.ts +3 -3
  122. package/src/core/modules/user/core-user.service.ts +48 -8
  123. package/src/core.module.ts +8 -0
  124. package/src/server/modules/user/user.module.ts +10 -1
  125. package/src/server/modules/user/user.resolver.ts +7 -8
  126. package/src/server/modules/user/user.service.ts +5 -6
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lenne.tech/nest-server",
3
- "version": "2.0.1",
3
+ "version": "3.0.0",
4
4
  "description": "Modern, fast, powerful Node.js web framework in TypeScript based on Nest with a GraphQL API and a connection to MongoDB (or other databases).",
5
5
  "keywords": [
6
6
  "node",
@@ -49,82 +49,72 @@
49
49
  "url": "https://github.com/lenneTech/nest-server/issues"
50
50
  },
51
51
  "engines": {
52
- "node": ">= 14.17.0"
53
- },
54
- "peerDependencies": {
55
- "@nestjs/testing": "8.0.6",
56
- "@nestjs/core": "8.0.6",
57
- "@nestjs/common": "8.0.6",
58
- "@nestjs/graphql": "9.0.2",
59
- "@nestjs/jwt": "8.0.0",
60
- "@nestjs/mongoose": "8.0.1",
61
- "@nestjs/passport": "8.0.1",
62
- "@nestjs/platform-express": "8.0.6"
52
+ "node": ">= 16.13.0"
63
53
  },
64
54
  "dependencies": {
65
- "@apollo/federation": "0.29.0",
66
- "@apollo/gateway": "0.38.0",
67
- "@nestjs/testing": "8.0.6",
68
- "@nestjs/core": "8.0.6",
69
- "@nestjs/common": "8.0.6",
70
- "@nestjs/graphql": "9.0.2",
55
+ "@apollo/federation": "0.33.9",
56
+ "@apollo/gateway": "0.42.3",
57
+ "@nestjs/common": "8.2.6",
58
+ "@nestjs/core": "8.2.6",
59
+ "@nestjs/graphql": "9.1.2",
71
60
  "@nestjs/jwt": "8.0.0",
72
- "@nestjs/mongoose": "8.0.1",
73
- "@nestjs/passport": "8.0.1",
74
- "@nestjs/platform-express": "8.0.6",
61
+ "@nestjs/mongoose": "9.0.2",
62
+ "@nestjs/passport": "8.1.0",
63
+ "@nestjs/platform-express": "8.2.6",
64
+ "@nestjs/testing": "8.2.6",
75
65
  "@types/ejs": "3.1.0",
76
- "@types/jest": "27.0.1",
77
- "@types/lodash": "4.14.172",
66
+ "@types/jest": "27.4.0",
67
+ "@types/lodash": "4.14.178",
78
68
  "@types/multer": "1.4.7",
79
- "@types/node": "14.14.37",
69
+ "@types/node": "16.11.21",
80
70
  "@types/nodemailer": "6.4.4",
81
71
  "@types/passport": "1.0.7",
82
72
  "@types/supertest": "2.0.11",
83
- "@typescript-eslint/eslint-plugin": "4.29.2",
84
- "@typescript-eslint/parser": "4.29.2",
85
- "apollo-server-core": "3.1.2",
86
- "apollo-server-express": "3.1.2",
73
+ "@typescript-eslint/eslint-plugin": "5.10.0",
74
+ "@typescript-eslint/parser": "5.10.0",
75
+ "apollo-server-core": "3.6.2",
76
+ "apollo-server-express": "3.6.2",
87
77
  "bcrypt": "5.0.1",
88
- "class-transformer": "0.4.0",
89
- "class-validator": "0.13.1",
90
- "coffeescript": "2.5.1",
78
+ "class-transformer": "0.5.1",
79
+ "class-validator": "0.13.2",
80
+ "coffeescript": "2.6.1",
91
81
  "ejs": "3.1.6",
92
- "fastify": "3.20.2",
93
- "graphql": "15.5.1",
94
- "graphql-subscriptions": "1.2.1",
82
+ "fastify": "3.27.0",
83
+ "graphql": "15.8.0",
84
+ "graphql-subscriptions": "2.0.0",
95
85
  "grunt": "1.4.1",
96
86
  "grunt-bg-shell": "2.3.3",
97
87
  "grunt-contrib-clean": "2.0.0",
98
88
  "grunt-contrib-watch": "1.1.0",
99
89
  "grunt-sync": "0.8.2",
100
- "husky": "7.0.0",
101
- "jest": "27.0.6",
102
- "json-to-graphql-query": "2.1.0",
103
- "light-my-request": "4.4.4",
90
+ "husky": "7.0.4",
91
+ "jest": "27.4.7",
92
+ "json-to-graphql-query": "2.2.0",
93
+ "light-my-request": "4.7.0",
104
94
  "lodash": "4.17.21",
105
- "mongoose": "5.13.8",
106
- "multer": "1.4.3",
107
- "nodemailer": "6.6.3",
108
- "nodemon": "2.0.12",
109
- "passport": "0.4.1",
95
+ "mongoose": "6.1.7",
96
+ "multer": "1.4.4",
97
+ "nodemailer": "6.7.2",
98
+ "nodemon": "2.0.15",
99
+ "passport": "0.5.2",
110
100
  "passport-jwt": "4.0.0",
111
101
  "reflect-metadata": "0.1.13",
112
102
  "rimraf": "3.0.2",
113
- "rxjs": "7.3.0",
114
- "supertest": "6.1.6",
115
- "ts-morph": "11.0.3",
116
- "ts-node": "9.1.1",
117
- "tsconfig-paths": "3.10.1"
103
+ "rxjs": "7.5.2",
104
+ "supertest": "6.2.2",
105
+ "ts-morph": "13.0.3",
106
+ "ts-node": "10.4.0",
107
+ "tsconfig-paths": "3.12.0"
118
108
  },
119
109
  "devDependencies": {
120
- "eslint": "7.32.0",
110
+ "eslint": "8.7.0",
121
111
  "eslint-config-prettier": "8.3.0",
122
112
  "find-file-up": "2.0.1",
123
- "pm2": "5.1.0",
124
- "prettier": "2.3.2",
125
- "pretty-quick": "3.1.1",
126
- "ts-jest": "27.0.5",
127
- "typescript": "4.3.5"
113
+ "pm2": "5.1.2",
114
+ "prettier": "2.5.1",
115
+ "pretty-quick": "3.1.3",
116
+ "ts-jest": "27.1.3",
117
+ "typescript": "4.5.5"
128
118
  },
129
119
  "jest": {
130
120
  "collectCoverage": true,
@@ -1,4 +1,7 @@
1
+ import { UnauthorizedException } from '@nestjs/common';
1
2
  import * as bcrypt from 'bcrypt';
3
+ import * as _ from 'lodash';
4
+ import { RoleEnum } from '../enums/role.enum';
2
5
 
3
6
  /**
4
7
  * Helper class for services
@@ -9,13 +12,15 @@ export class ServiceHelper {
9
12
  */
10
13
  static async prepareInput(
11
14
  input: { [key: string]: any },
12
- currentUser: { id: string },
15
+ currentUser: { [key: string]: any; id: string },
13
16
  options: { [key: string]: any; create?: boolean; clone?: boolean } = {},
14
17
  ...args: any[]
15
18
  ) {
16
19
  // Configuration
17
20
  const config = {
21
+ checkRoles: true,
18
22
  clone: false,
23
+ create: false,
19
24
  ...options,
20
25
  };
21
26
 
@@ -24,7 +29,21 @@ export class ServiceHelper {
24
29
  input = JSON.parse(JSON.stringify(input));
25
30
  }
26
31
 
27
- // Has password
32
+ // Process roles
33
+ if (input.roles && config.checkRoles && (!currentUser?.hasRole || !currentUser.hasRole(RoleEnum.ADMIN))) {
34
+ if (!(currentUser as any)?.roles) {
35
+ throw new UnauthorizedException('Missing roles of current user');
36
+ } else {
37
+ const allowedRoles = _.intersection(input.roles, (currentUser as any).roles);
38
+ if (allowedRoles.length !== input.roles.length) {
39
+ const missingRoles = _.difference(input.roles, (currentUser as any).roles);
40
+ throw new UnauthorizedException('Current user not allowed setting roles: ' + missingRoles);
41
+ }
42
+ input.roles = allowedRoles;
43
+ }
44
+ }
45
+
46
+ // Hash password
28
47
  if (input.password) {
29
48
  input.password = await bcrypt.hash((input as any).password, 10);
30
49
  }
@@ -19,7 +19,7 @@ export abstract class CorePersistenceModel {
19
19
  // Getter
20
20
  // ===========================================================================
21
21
  get _id() {
22
- return mongoose.Types.ObjectId(this.id);
22
+ return new mongoose.Types.ObjectId(this.id);
23
23
  }
24
24
 
25
25
  // ===========================================================================
@@ -14,20 +14,22 @@ export class ConfigService {
14
14
  * Create config service
15
15
  */
16
16
  constructor(config: { [key: string]: any } & Partial<IServerOptions>) {
17
- this._config = config;
17
+ this._config = config || {};
18
18
  }
19
19
 
20
20
  /**
21
- * Get config
21
+ * Get config (deep cloned to avoid unwanted side effects)
22
22
  */
23
23
  get config() {
24
24
  return _.cloneDeep(this._config);
25
25
  }
26
26
 
27
27
  /**
28
- * Get data from config
28
+ * Get data from config (deep cloned to avoid unwanted side effects)
29
+ * @param key Property name of config object, which is to be returned
30
+ * @param defaultValue Default value which is to be returned if property doesn't exist
29
31
  */
30
- get(key: string) {
31
- return _.cloneDeep(_.get(this._config, key, undefined));
32
+ get(key: string, defaultValue: any = undefined) {
33
+ return _.cloneDeep(_.get(this._config, key, defaultValue));
32
34
  }
33
35
  }
@@ -6,6 +6,7 @@ import { RolesGuard } from './guards/roles.guard';
6
6
  import { JwtStrategy } from './jwt.strategy';
7
7
  import { CoreAuthUserService } from './services/core-auth-user.service';
8
8
  import { CoreAuthService } from './services/core-auth.service';
9
+ import { PubSub } from 'graphql-subscriptions';
9
10
 
10
11
  /**
11
12
  * CoreAuthModule to handle user authentication and enables Roles
@@ -34,6 +35,10 @@ export class CoreAuthModule {
34
35
  provide: CoreAuthUserService,
35
36
  useClass: UserService,
36
37
  },
38
+ {
39
+ provide: 'PUB_SUB',
40
+ useValue: new PubSub(),
41
+ },
37
42
 
38
43
  // Standard services
39
44
  CoreAuthService,
@@ -58,6 +58,11 @@ function createAuthGuard(type?: string): Type<CanActivate> {
58
58
  * Integrate options
59
59
  */
60
60
  async canActivate(context: ExecutionContext): Promise<boolean> {
61
+ const args = context.getArgs();
62
+ if (args.length > 0 && args[args.length - 1]?.operation?.operation === 'subscription') {
63
+ return true;
64
+ }
65
+
61
66
  const options = { ...defaultOptions, ...this.options };
62
67
  const response = context?.switchToHttp()?.getResponse();
63
68
  let request = this.getRequest(context);
@@ -16,9 +16,9 @@ const pubSub = new PubSub();
16
16
  * User service
17
17
  */
18
18
  export abstract class CoreBasicUserService<
19
- TUser = CoreUserModel,
20
- TUserInput = CoreUserInput,
21
- TUserCreateInput = CoreUserCreateInput
19
+ TUser extends CoreUserModel,
20
+ TUserInput extends CoreUserInput,
21
+ TUserCreateInput extends CoreUserCreateInput
22
22
  > {
23
23
  protected readonly model: ICorePersistenceModel;
24
24
 
@@ -1,13 +1,20 @@
1
- import { NotFoundException, UnprocessableEntityException } from '@nestjs/common';
1
+ import {
2
+ BadRequestException,
3
+ NotFoundException,
4
+ UnauthorizedException,
5
+ UnprocessableEntityException,
6
+ } from '@nestjs/common';
2
7
  import * as bcrypt from 'bcrypt';
3
8
  import { PubSub } from 'graphql-subscriptions';
4
9
  import { FilterArgs } from '../../common/args/filter.args';
10
+ import { RoleEnum } from '../../common/enums/role.enum';
5
11
  import { Filter } from '../../common/helpers/filter.helper';
6
12
  import { CoreBasicUserService } from './core-basic-user.service';
7
13
  import { CoreUserModel } from './core-user.model';
8
14
  import { CoreUserCreateInput } from './inputs/core-user-create.input';
9
15
  import { CoreUserInput } from './inputs/core-user.input';
10
16
  import { Model } from 'mongoose';
17
+ import * as _ from 'lodash';
11
18
 
12
19
  // Subscription
13
20
  const pubSub = new PubSub();
@@ -16,9 +23,9 @@ const pubSub = new PubSub();
16
23
  * User service
17
24
  */
18
25
  export abstract class CoreUserService<
19
- TUser = CoreUserModel,
20
- TUserInput = CoreUserInput,
21
- TUserCreateInput = CoreUserCreateInput
26
+ TUser extends CoreUserModel,
27
+ TUserInput extends CoreUserInput,
28
+ TUserCreateInput extends CoreUserCreateInput
22
29
  > extends CoreBasicUserService<TUser, TUserInput, TUserCreateInput> {
23
30
  protected constructor(protected readonly userModel: Model<any>) {
24
31
  super(userModel);
@@ -108,6 +115,24 @@ export abstract class CoreUserService<
108
115
  );
109
116
  }
110
117
 
118
+ /**
119
+ * Set roles for specified user
120
+ */
121
+ async setRoles(userId: string, roles: string[]): Promise<TUser> {
122
+ // Check roles
123
+ if (!Array.isArray(roles)) {
124
+ throw new BadRequestException('Missing roles');
125
+ }
126
+
127
+ // Check roles values
128
+ if (roles.some((role) => typeof role !== 'string')) {
129
+ throw new BadRequestException('roles contains invalid values');
130
+ }
131
+
132
+ // Update and return user
133
+ return this.userModel.findByIdAndUpdate(userId, { roles }).exec();
134
+ }
135
+
111
136
  /**
112
137
  * Update user via ID
113
138
  */
@@ -144,22 +169,37 @@ export abstract class CoreUserService<
144
169
  */
145
170
  protected async prepareInput(
146
171
  input: { [key: string]: any },
147
- currentUser: TUser,
148
- options: { [key: string]: any; create?: boolean; clone?: boolean } = {},
172
+ currentUser?: TUser,
173
+ options: { [key: string]: any; checkRoles?: boolean; clone?: boolean } = {},
149
174
  ...args: any[]
150
175
  ) {
151
176
  // Configuration
152
177
  const config = {
178
+ checkRoles: true,
153
179
  clone: false,
154
180
  ...options,
155
181
  };
156
182
 
157
- // Clone output
183
+ // Clone input
158
184
  if (config.clone) {
159
185
  input = JSON.parse(JSON.stringify(input));
160
186
  }
161
187
 
162
- // Has password
188
+ // Process roles
189
+ if (input.roles && config.checkRoles && (!currentUser?.hasRole || !currentUser.hasRole(RoleEnum.ADMIN))) {
190
+ if (!(currentUser as any)?.roles) {
191
+ throw new UnauthorizedException('Missing roles of current user');
192
+ } else {
193
+ const allowedRoles = _.intersection(input.roles, (currentUser as any).roles);
194
+ if (allowedRoles.length !== input.roles.length) {
195
+ const missingRoles = _.difference(input.roles, (currentUser as any).roles);
196
+ throw new UnauthorizedException('Current user not allowed setting roles: ' + missingRoles);
197
+ }
198
+ input.roles = allowedRoles;
199
+ }
200
+ }
201
+
202
+ // Hash password
163
203
  if (input.password) {
164
204
  input.password = await bcrypt.hash((input as any).password, 10);
165
205
  }
@@ -41,6 +41,14 @@ export class CoreModule {
41
41
  autoSchemaFile: 'schema.gql',
42
42
  context: ({ req }) => ({ req }),
43
43
  installSubscriptionHandlers: true,
44
+ subscriptions: {
45
+ 'subscriptions-transport-ws': {
46
+ onConnect: (connectionParams) => {
47
+ // TODO: Handle Authorization
48
+ const authToken = connectionParams.Authorization;
49
+ },
50
+ },
51
+ },
44
52
  },
45
53
  port: 3000,
46
54
  mongoose: {
@@ -5,6 +5,7 @@ import { User, UserSchema } from './user.model';
5
5
  import { UserResolver } from './user.resolver';
6
6
  import { UserService } from './user.service';
7
7
  import { MongooseModule } from '@nestjs/mongoose';
8
+ import { PubSub } from 'graphql-subscriptions';
8
9
 
9
10
  /**
10
11
  * User module
@@ -12,7 +13,15 @@ import { MongooseModule } from '@nestjs/mongoose';
12
13
  @Module({
13
14
  imports: [MongooseModule.forFeature([{ name: User.name, schema: UserSchema }])],
14
15
  controllers: [AvatarController],
15
- providers: [JSON, UserResolver, UserService],
16
+ providers: [
17
+ JSON,
18
+ UserResolver,
19
+ UserService,
20
+ {
21
+ provide: 'PUB_SUB',
22
+ useValue: new PubSub(),
23
+ },
24
+ ],
16
25
  exports: [MongooseModule, UserResolver, UserService],
17
26
  })
18
27
  export class UserModule {}
@@ -10,9 +10,7 @@ import { UserCreateInput } from './inputs/user-create.input';
10
10
  import { UserInput } from './inputs/user.input';
11
11
  import { User } from './user.model';
12
12
  import { UserService } from './user.service';
13
-
14
- // Subscription
15
- const pubSub = new PubSub();
13
+ import { Inject } from '@nestjs/common';
16
14
 
17
15
  /**
18
16
  * Resolver to process with user data
@@ -22,7 +20,7 @@ export class UserResolver {
22
20
  /**
23
21
  * Import services
24
22
  */
25
- constructor(protected readonly usersService: UserService) {}
23
+ constructor(protected readonly usersService: UserService, @Inject('PUB_SUB') protected readonly pubSub: PubSub) {}
26
24
 
27
25
  // ===========================================================================
28
26
  // Queries
@@ -96,9 +94,10 @@ export class UserResolver {
96
94
  /**
97
95
  * Subscritption for create user
98
96
  */
99
- @Roles(RoleEnum.ADMIN)
100
- @Subscription((returns) => User)
101
- userCreated() {
102
- return pubSub.asyncIterator('userCreated');
97
+ @Subscription((returns) => User, {
98
+ resolve: (value) => value,
99
+ })
100
+ async userCreated() {
101
+ return this.pubSub.asyncIterator('userCreated');
103
102
  }
104
103
  }
@@ -1,7 +1,6 @@
1
- import { Injectable, UnauthorizedException, UnprocessableEntityException } from '@nestjs/common';
1
+ import { Inject, Injectable, UnauthorizedException, UnprocessableEntityException } from '@nestjs/common';
2
2
  import * as fs from 'fs';
3
3
  import { GraphQLResolveInfo } from 'graphql';
4
- import { PubSub } from 'graphql-subscriptions';
5
4
  import envConfig from '../../../config.env';
6
5
  import { FilterArgs } from '../../../core/common/args/filter.args';
7
6
  import { Filter } from '../../../core/common/helpers/filter.helper';
@@ -15,9 +14,7 @@ import { User } from './user.model';
15
14
  import { InjectModel } from '@nestjs/mongoose';
16
15
  import { Model } from 'mongoose';
17
16
  import { ICorePersistenceModel } from '../../../core/common/interfaces/core-persistence-model.interface';
18
-
19
- // Subscription
20
- const pubSub = new PubSub();
17
+ import { PubSub } from 'graphql-subscriptions';
21
18
 
22
19
  /**
23
20
  * User service
@@ -42,7 +39,8 @@ export class UserService extends CoreUserService<User, UserInput, UserCreateInpu
42
39
  constructor(
43
40
  protected readonly configService: ConfigService,
44
41
  protected readonly emailService: EmailService,
45
- @InjectModel('User') protected readonly userModel: Model<User>
42
+ @InjectModel('User') protected readonly userModel: Model<User>,
43
+ @Inject('PUB_SUB') protected readonly pubSub: PubSub
46
44
  ) {
47
45
  super(userModel);
48
46
  this.model = User;
@@ -58,6 +56,7 @@ export class UserService extends CoreUserService<User, UserInput, UserCreateInpu
58
56
  async create(input: UserCreateInput, currentUser?: User, ...args: any[]): Promise<User> {
59
57
  const user = await super.create(input, currentUser);
60
58
  const text = `Welcome ${user.firstName}, this is plain text from server.`;
59
+ await this.pubSub.publish('userCreated', User.map(user));
61
60
  await this.emailService.sendMail(user.email, 'Welcome', {
62
61
  htmlTemplate: 'welcome',
63
62
  templateData: user,