@lenne.tech/nest-server 8.4.0 → 8.6.1

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 (68) hide show
  1. package/dist/core/common/decorators/restricted.decorator.d.ts +3 -2
  2. package/dist/core/common/decorators/restricted.decorator.js +29 -8
  3. package/dist/core/common/decorators/restricted.decorator.js.map +1 -1
  4. package/dist/core/common/helpers/db.helper.d.ts +1 -1
  5. package/dist/core/common/helpers/db.helper.js +29 -5
  6. package/dist/core/common/helpers/db.helper.js.map +1 -1
  7. package/dist/core/common/helpers/service.helper.d.ts +12 -0
  8. package/dist/core/common/helpers/service.helper.js +42 -3
  9. package/dist/core/common/helpers/service.helper.js.map +1 -1
  10. package/dist/core/common/interfaces/prepare-input-options.interface.d.ts +8 -0
  11. package/dist/core/common/interfaces/prepare-input-options.interface.js +3 -0
  12. package/dist/core/common/interfaces/prepare-input-options.interface.js.map +1 -0
  13. package/dist/core/common/interfaces/prepare-output-options.interface.d.ts +7 -0
  14. package/dist/core/common/interfaces/prepare-output-options.interface.js +3 -0
  15. package/dist/core/common/interfaces/prepare-output-options.interface.js.map +1 -0
  16. package/dist/core/common/interfaces/service-options.interface.d.ts +5 -15
  17. package/dist/core/common/services/module.service.d.ts +1 -1
  18. package/dist/core/common/services/module.service.js +14 -8
  19. package/dist/core/common/services/module.service.js.map +1 -1
  20. package/dist/core/modules/auth/inputs/core-auth-sign-in.input.d.ts +5 -0
  21. package/dist/core/modules/auth/inputs/core-auth-sign-in.input.js +34 -0
  22. package/dist/core/modules/auth/inputs/core-auth-sign-in.input.js.map +1 -0
  23. package/dist/core/modules/auth/inputs/core-auth-sign-up.input.d.ts +5 -0
  24. package/dist/core/modules/auth/inputs/core-auth-sign-up.input.js +34 -0
  25. package/dist/core/modules/auth/inputs/core-auth-sign-up.input.js.map +1 -0
  26. package/dist/index.d.ts +4 -0
  27. package/dist/index.js +4 -0
  28. package/dist/index.js.map +1 -1
  29. package/dist/server/modules/auth/auth.model.js +2 -2
  30. package/dist/server/modules/auth/auth.model.js.map +1 -1
  31. package/dist/server/modules/auth/auth.module.js +7 -2
  32. package/dist/server/modules/auth/auth.module.js.map +1 -1
  33. package/dist/server/modules/auth/auth.resolver.d.ts +8 -3
  34. package/dist/server/modules/auth/auth.resolver.js +33 -10
  35. package/dist/server/modules/auth/auth.resolver.js.map +1 -1
  36. package/dist/server/modules/auth/auth.service.d.ts +15 -0
  37. package/dist/server/modules/auth/auth.service.js +71 -0
  38. package/dist/server/modules/auth/auth.service.js.map +1 -0
  39. package/dist/server/modules/auth/inputs/auth-sign-in.input.d.ts +3 -0
  40. package/dist/server/modules/auth/inputs/auth-sign-in.input.js +18 -0
  41. package/dist/server/modules/auth/inputs/auth-sign-in.input.js.map +1 -0
  42. package/dist/server/modules/auth/inputs/auth-sign-up.input.d.ts +5 -0
  43. package/dist/server/modules/auth/inputs/auth-sign-up.input.js +34 -0
  44. package/dist/server/modules/auth/inputs/auth-sign-up.input.js.map +1 -0
  45. package/dist/server/modules/user/user.resolver.js +12 -11
  46. package/dist/server/modules/user/user.resolver.js.map +1 -1
  47. package/dist/server/modules/user/user.service.js +0 -4
  48. package/dist/server/modules/user/user.service.js.map +1 -1
  49. package/dist/tsconfig.build.tsbuildinfo +1 -1
  50. package/package.json +2 -2
  51. package/src/core/common/decorators/restricted.decorator.ts +50 -14
  52. package/src/core/common/helpers/db.helper.ts +27 -5
  53. package/src/core/common/helpers/service.helper.ts +72 -2
  54. package/src/core/common/interfaces/prepare-input-options.interface.ts +11 -0
  55. package/src/core/common/interfaces/prepare-output-options.interface.ts +10 -0
  56. package/src/core/common/interfaces/service-options.interface.ts +7 -17
  57. package/src/core/common/services/module.service.ts +17 -9
  58. package/src/core/modules/auth/inputs/core-auth-sign-in.input.ts +18 -0
  59. package/src/core/modules/auth/inputs/core-auth-sign-up.input.ts +18 -0
  60. package/src/index.ts +4 -0
  61. package/src/server/modules/auth/auth.model.ts +5 -5
  62. package/src/server/modules/auth/auth.module.ts +13 -2
  63. package/src/server/modules/auth/auth.resolver.ts +30 -12
  64. package/src/server/modules/auth/auth.service.ts +83 -0
  65. package/src/server/modules/auth/inputs/auth-sign-in.input.ts +10 -0
  66. package/src/server/modules/auth/inputs/auth-sign-up.input.ts +18 -0
  67. package/src/server/modules/user/user.resolver.ts +12 -11
  68. package/src/server/modules/user/user.service.ts +0 -8
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lenne.tech/nest-server",
3
- "version": "8.4.0",
3
+ "version": "8.6.1",
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",
@@ -112,7 +112,7 @@
112
112
  "prettier": "2.6.2",
113
113
  "pretty-quick": "3.1.3",
114
114
  "supertest": "6.2.3",
115
- "ts-jest": "28.0.1",
115
+ "ts-jest": "28.0.2",
116
116
  "ts-morph": "14.0.0",
117
117
  "ts-node": "10.7.0",
118
118
  "tsconfig-paths": "4.0.0",
@@ -9,6 +9,10 @@ import { RequireAtLeastOne } from '../types/required-at-least-one.type';
9
9
  * Restricted meta key
10
10
  */
11
11
  const restrictedMetaKey = Symbol('restricted');
12
+
13
+ /**
14
+ * Restricted type
15
+ */
12
16
  export type RestrictedType = (
13
17
  | string
14
18
  | RequireAtLeastOne<
@@ -31,14 +35,17 @@ export type RestrictedType = (
31
35
  * properties of the processed item, which is specified by the value of `memberOf`
32
36
  * Via processType the restriction can be set for input or output only
33
37
  */
34
- export const Restricted = (...rolesOrMember: RestrictedType): PropertyDecorator => {
38
+ export const Restricted = (...rolesOrMember: RestrictedType): ClassDecorator & PropertyDecorator => {
35
39
  return Reflect.metadata(restrictedMetaKey, rolesOrMember);
36
40
  };
37
41
 
38
42
  /**
39
- * Get restricted
43
+ * Get restricted data for (property of) object
40
44
  */
41
- export const getRestricted = (object: unknown, propertyKey: string): RestrictedType => {
45
+ export const getRestricted = (object: unknown, propertyKey?: string): RestrictedType => {
46
+ if (!propertyKey) {
47
+ return Reflect.getMetadata(restrictedMetaKey, object);
48
+ }
42
49
  return Reflect.getMetadata(restrictedMetaKey, object, propertyKey);
43
50
  };
44
51
 
@@ -49,11 +56,18 @@ export const getRestricted = (object: unknown, propertyKey: string): RestrictedT
49
56
  export const checkRestricted = (
50
57
  data: any,
51
58
  user: { id: any; hasRole: (roles: string[]) => boolean },
52
- options: { dbObject?: any; ignoreUndefined?: boolean; processType?: ProcessType; throwError?: boolean } = {},
59
+ options: {
60
+ dbObject?: any;
61
+ ignoreUndefined?: boolean;
62
+ processType?: ProcessType;
63
+ removeUndefinedFromResultArray?: boolean;
64
+ throwError?: boolean;
65
+ } = {},
53
66
  processedObjects: any[] = []
54
67
  ) => {
55
68
  const config = {
56
69
  ignoreUndefined: true,
70
+ removeUndefinedFromResultArray: true,
57
71
  throwError: true,
58
72
  ...options,
59
73
  };
@@ -72,18 +86,15 @@ export const checkRestricted = (
72
86
  // Array
73
87
  if (Array.isArray(data)) {
74
88
  // Check array items
75
- return data.map((item) => checkRestricted(item, user, config, processedObjects));
76
- }
77
-
78
- // Object
79
- for (const propertyKey of Object.keys(data)) {
80
- // Check undefined
81
- if (data[propertyKey] === undefined && config.ignoreUndefined) {
82
- continue;
89
+ let result = data.map((item) => checkRestricted(item, user, config, processedObjects));
90
+ if (!config.throwError && config.removeUndefinedFromResultArray) {
91
+ result = result.filter((item) => item !== undefined);
83
92
  }
93
+ return result;
94
+ }
84
95
 
85
- // Check restricted
86
- const restricted = getRestricted(data, propertyKey);
96
+ // Check function
97
+ const validateRestricted = (restricted) => {
87
98
  let valid = true;
88
99
  if (restricted?.length) {
89
100
  valid = false;
@@ -110,6 +121,7 @@ export const checkRestricted = (
110
121
  // Check roles
111
122
  if (
112
123
  user?.hasRole(roles) ||
124
+ (user?.id && roles.includes(RoleEnum.S_USER)) ||
113
125
  (roles.includes(RoleEnum.S_CREATOR) && getIncludedIds(config.dbObject?.createdBy, user))
114
126
  ) {
115
127
  valid = true;
@@ -161,6 +173,30 @@ export const checkRestricted = (
161
173
  }
162
174
  }
163
175
  }
176
+ return valid;
177
+ };
178
+
179
+ // Check object
180
+ const objectRestrictions = getRestricted(data.constructor);
181
+ const objectIsValid = validateRestricted(objectRestrictions);
182
+ if (!objectIsValid) {
183
+ // Throw error
184
+ if (config.throwError) {
185
+ throw new UnauthorizedException('The current user has no access rights for ' + data.constructor?.name);
186
+ }
187
+ return null;
188
+ }
189
+
190
+ // Check properties of object
191
+ for (const propertyKey of Object.keys(data)) {
192
+ // Check undefined
193
+ if (data[propertyKey] === undefined && config.ignoreUndefined) {
194
+ continue;
195
+ }
196
+
197
+ // Check restricted
198
+ const restricted = getRestricted(data, propertyKey);
199
+ const valid = validateRestricted(restricted);
164
200
 
165
201
  // Check rights
166
202
  if (valid) {
@@ -275,19 +275,41 @@ export function getElementsViaIds<T = any>(
275
275
  /**
276
276
  * Get populate options from GraphQL resolve info
277
277
  */
278
- export function getPopulateOptions(info: GraphQLResolveInfo, select?: string): PopulateOptions[] {
278
+ export function getPopulateOptions(info: GraphQLResolveInfo, dotSeparatedSelect?: string): PopulateOptions[] {
279
279
  const result = [];
280
280
 
281
281
  if (!info?.fieldNodes?.length) {
282
282
  return result;
283
283
  }
284
284
 
285
- for (const fieldNode of info.fieldNodes) {
286
- if ((select || fieldNode?.name?.value === select) && fieldNode?.selectionSet?.selections?.length) {
287
- return getPopulatOptionsFromSelections(fieldNode.selectionSet.selections);
285
+ if (dotSeparatedSelect?.length) {
286
+ for (const fieldNode of info.fieldNodes) {
287
+ const selects = dotSeparatedSelect.split('.');
288
+ const fieldNodeName = selects.shift();
289
+ if (fieldNode?.name?.value === fieldNodeName && fieldNode?.selectionSet?.selections?.length) {
290
+ if (!selects.length) {
291
+ return getPopulatOptionsFromSelections(fieldNode.selectionSet.selections);
292
+ } else {
293
+ let selections = fieldNode.selectionSet.selections;
294
+ do {
295
+ if (!selections?.length) {
296
+ break;
297
+ }
298
+ const select = selects.shift();
299
+ for (const selection of selections) {
300
+ if ((selection as FieldNode)?.name?.value === select) {
301
+ selections = (selection as FieldNode)?.selectionSet?.selections;
302
+ if (!selects.length) {
303
+ return getPopulatOptionsFromSelections(selections);
304
+ }
305
+ break;
306
+ }
307
+ }
308
+ } while (selects.length);
309
+ }
310
+ }
288
311
  }
289
312
  }
290
-
291
313
  return result;
292
314
  }
293
315
 
@@ -1,7 +1,12 @@
1
1
  import { UnauthorizedException } from '@nestjs/common';
2
2
  import * as bcrypt from 'bcrypt';
3
+ import { plainToInstance } from 'class-transformer';
3
4
  import * as _ from 'lodash';
4
5
  import { RoleEnum } from '../enums/role.enum';
6
+ import { PrepareInputOptions } from '../interfaces/prepare-input-options.interface';
7
+ import { PrepareOutputOptions } from '../interfaces/prepare-output-options.interface';
8
+ import { ResolveSelector } from '../interfaces/resolve-selector.interface';
9
+ import { ServiceOptions } from '../interfaces/service-options.interface';
5
10
 
6
11
  /**
7
12
  * Helper class for services
@@ -54,6 +59,7 @@ export async function prepareInput<T = any>(
54
59
  clone?: boolean;
55
60
  getNewArray?: boolean;
56
61
  removeUndefined?: boolean;
62
+ targetModel?: new (...args: any[]) => T;
57
63
  } = {}
58
64
  ): Promise<T> {
59
65
  // Configuration
@@ -86,6 +92,15 @@ export async function prepareInput<T = any>(
86
92
  }
87
93
  }
88
94
 
95
+ // Map input if target model exist
96
+ if (config.targetModel && !(input instanceof config.targetModel)) {
97
+ if ((config.targetModel as any)?.map) {
98
+ input = await (config.targetModel as any).map(input);
99
+ } else {
100
+ input = plainToInstance(config.targetModel, input);
101
+ }
102
+ }
103
+
89
104
  // Remove undefined properties to avoid unwanted overwrites
90
105
  if (config.removeUndefined) {
91
106
  Object.keys(input).forEach((key) => input[key] === undefined && delete input[key]);
@@ -171,8 +186,12 @@ export async function prepareOutput<T = { [key: string]: any; map: (...args: any
171
186
  }
172
187
 
173
188
  // Map output if target model exist
174
- if (config.targetModel) {
175
- output = await (config.targetModel as any).map(output);
189
+ if (config.targetModel && !(output instanceof config.targetModel)) {
190
+ if ((config.targetModel as any)?.map) {
191
+ output = await (config.targetModel as any).map(output);
192
+ } else {
193
+ output = plainToInstance(config.targetModel, output);
194
+ }
176
195
  }
177
196
 
178
197
  // Remove password if exists
@@ -198,3 +217,54 @@ export async function prepareOutput<T = { [key: string]: any; map: (...args: any
198
217
  // Return prepared output
199
218
  return output;
200
219
  }
220
+
221
+ /**
222
+ * Prepare service options
223
+ */
224
+ export function prepareServiceOptions(
225
+ serviceOptions: ServiceOptions,
226
+ options?: {
227
+ clone?: boolean;
228
+ inputType?: any;
229
+ outputType?: any;
230
+ subFieldSelection?: string;
231
+ prepareInput?: PrepareInputOptions;
232
+ prepareOutput?: PrepareOutputOptions;
233
+ }
234
+ ): ServiceOptions {
235
+ // Set default values
236
+ const config = {
237
+ clone: true,
238
+ ...options,
239
+ };
240
+
241
+ // Clone
242
+ if (serviceOptions && config.clone) {
243
+ serviceOptions = _.cloneDeep(serviceOptions);
244
+ }
245
+
246
+ // Init if not exists
247
+ serviceOptions = serviceOptions || {};
248
+
249
+ // Set properties
250
+ serviceOptions.inputType = serviceOptions.inputType || options?.inputType;
251
+ serviceOptions.outputType = serviceOptions.outputType || options?.outputType;
252
+
253
+ // Set properties which can deactivate handling when falsy
254
+ if (!serviceOptions.prepareInput && 'prepareInput' in config) {
255
+ serviceOptions.prepareInput = config.prepareInput;
256
+ }
257
+ if (!serviceOptions.prepareOutput && 'prepareOutput' in config) {
258
+ serviceOptions.prepareOutput = config.prepareOutput;
259
+ }
260
+
261
+ // Set subfield selection
262
+ if (config.subFieldSelection) {
263
+ if ((serviceOptions.fieldSelection as ResolveSelector)?.select) {
264
+ (serviceOptions.fieldSelection as ResolveSelector).select += '.' + config.subFieldSelection;
265
+ }
266
+ }
267
+
268
+ // Return (cloned and) prepared service options
269
+ return serviceOptions;
270
+ }
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Interface for prepare input options
3
+ */
4
+ export interface PrepareInputOptions {
5
+ [key: string]: any;
6
+ create?: boolean;
7
+ clone?: boolean;
8
+ getNewArray?: boolean;
9
+ removeUndefined?: boolean;
10
+ targetModel?: new (...args: any[]) => any;
11
+ }
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Interface for prepare output options
3
+ */
4
+ export interface PrepareOutputOptions {
5
+ [key: string]: any;
6
+ clone?: boolean;
7
+ getNewArray?: boolean;
8
+ removeUndefined?: boolean;
9
+ targetModel?: new (...args: any[]) => any;
10
+ }
@@ -1,5 +1,7 @@
1
1
  import { Model } from 'mongoose';
2
2
  import { FieldSelection } from '../types/field-selection.type';
3
+ import { PrepareInputOptions } from './prepare-input-options.interface';
4
+ import { PrepareOutputOptions } from './prepare-output-options.interface';
3
5
 
4
6
  /**
5
7
  * General service options
@@ -26,6 +28,9 @@ export interface ServiceOptions {
26
28
  // Overwrites type of input (array items)
27
29
  inputType?: new (...params: any[]) => any;
28
30
 
31
+ // Overwrites type of output (array items)
32
+ outputType?: new (...params: any[]) => any;
33
+
29
34
  // Process field selection
30
35
  // If {} or not set, then the field selection runs with defaults
31
36
  // If falsy, then the field selection will not be automatically executed
@@ -37,31 +42,16 @@ export interface ServiceOptions {
37
42
  // Prepare input configuration:
38
43
  // If {} or not set, then the prepareInput function will run with defaults
39
44
  // If falsy, then the prepareInput function is not executed
40
- prepareInput?: {
41
- [key: string]: any;
42
- create?: boolean;
43
- clone?: boolean;
44
- getNewArray?: boolean;
45
- removeUndefined?: boolean;
46
- };
45
+ prepareInput?: PrepareInputOptions;
47
46
 
48
47
  // Prepare output configuration:
49
48
  // If {} or not set, then the prepareInput function will run with defaults
50
49
  // If falsy, then the prepareInput function is not executed
51
- prepareOutput?: {
52
- [key: string]: any;
53
- clone?: boolean;
54
- getNewArray?: boolean;
55
- removeUndefined?: boolean;
56
- targetModel?: new (...args: any[]) => any;
57
- };
50
+ prepareOutput?: PrepareOutputOptions;
58
51
 
59
52
  // Whether to publish action via GraphQL subscription
60
53
  pubSub?: boolean;
61
54
 
62
- // Overwrites type of result (array items)
63
- resultType?: new (...params: any[]) => any;
64
-
65
55
  // Roles (as string) to check
66
56
  roles?: string | string[];
67
57
  }
@@ -84,7 +84,11 @@ export abstract class ModuleService<T extends CoreModel = any> {
84
84
 
85
85
  // Prepare input
86
86
  if (config.prepareInput && this.prepareInput) {
87
- await this.prepareInput(config.input, config.prepareInput);
87
+ const opts = config.prepareInput;
88
+ if (!opts.targetModel && config.inputType) {
89
+ opts.targetModel = config.inputType;
90
+ }
91
+ await this.prepareInput(config.input, opts);
88
92
  }
89
93
 
90
94
  // Get DB object
@@ -101,7 +105,7 @@ export abstract class ModuleService<T extends CoreModel = any> {
101
105
  if (config.input && config.checkRights && this.checkRights) {
102
106
  const opts: any = { dbObject: config.dbObject, processType: ProcessType.INPUT, roles: config.roles };
103
107
  if (config.inputType) {
104
- opts.metatype = config.resultType;
108
+ opts.metatype = config.inputType;
105
109
  }
106
110
  config.input = await this.checkRights(config.input, config.currentUser as any, opts);
107
111
  }
@@ -116,11 +120,11 @@ export abstract class ModuleService<T extends CoreModel = any> {
116
120
 
117
121
  // Prepare output
118
122
  if (config.prepareOutput && this.prepareOutput) {
119
- // Check if mapping is already done by processFieldSelection
120
- if (config.processFieldSelection && config.fieldSelection && this.processFieldSelection) {
121
- config.prepareOutput.targetModel = null;
123
+ const opts = config.prepareOutput;
124
+ if (!opts.targetModel && config.outputType) {
125
+ opts.targetModel = config.outputType;
122
126
  }
123
- result = await this.prepareOutput(result, config.prepareOutput);
127
+ result = await this.prepareOutput(result, opts);
124
128
  }
125
129
 
126
130
  // Check output rights
@@ -131,8 +135,8 @@ export abstract class ModuleService<T extends CoreModel = any> {
131
135
  roles: config.roles,
132
136
  throwError: false,
133
137
  };
134
- if (config.resultType) {
135
- opts.metatype = config.resultType;
138
+ if (config.outputType) {
139
+ opts.metatype = config.outputType;
136
140
  }
137
141
  result = await this.checkRights(result, config.currentUser as any, opts);
138
142
  }
@@ -145,7 +149,11 @@ export abstract class ModuleService<T extends CoreModel = any> {
145
149
  * Prepare input before save
146
150
  */
147
151
  async prepareInput(input: Record<string, any>, options: ServiceOptions = {}) {
148
- return prepareInput(input, options.currentUser, options.prepareInput);
152
+ const config = {
153
+ targetModel: this.mainModelConstructor,
154
+ ...options?.prepareInput,
155
+ };
156
+ return prepareInput(input, options.currentUser, config);
149
157
  }
150
158
 
151
159
  /**
@@ -0,0 +1,18 @@
1
+ import { Field, InputType } from '@nestjs/graphql';
2
+ import { CoreInput } from '../../../common/inputs/core-input.input';
3
+
4
+ /**
5
+ * SignIn input
6
+ */
7
+ @InputType({ description: 'Sign-in input' })
8
+ export class CoreAuthSignInInput extends CoreInput {
9
+ // ===================================================================================================================
10
+ // Properties
11
+ // ===================================================================================================================
12
+
13
+ @Field({ description: 'Email', nullable: false })
14
+ email: string = undefined;
15
+
16
+ @Field({ description: 'Password', nullable: false })
17
+ password: string = undefined;
18
+ }
@@ -0,0 +1,18 @@
1
+ import { Field, InputType } from '@nestjs/graphql';
2
+ import { CoreInput } from '../../../common/inputs/core-input.input';
3
+
4
+ /**
5
+ * SignUp input
6
+ */
7
+ @InputType({ description: 'Sign-up input' })
8
+ export class CoreAuthSignUpInput extends CoreInput {
9
+ // ===================================================================================================================
10
+ // Properties
11
+ // ===================================================================================================================
12
+
13
+ @Field({ description: 'Email', nullable: false })
14
+ email: string = undefined;
15
+
16
+ @Field({ description: 'Password', nullable: false })
17
+ password: string = undefined;
18
+ }
package/src/index.ts CHANGED
@@ -35,6 +35,8 @@ export * from './core/common/inputs/sort.input';
35
35
  export * from './core/common/interceptors/check-response.interceptor';
36
36
  export * from './core/common/interfaces/core-persistence-model.interface';
37
37
  export * from './core/common/interfaces/mailjet-options.interface';
38
+ export * from './core/common/interfaces/prepare-input-options.interface';
39
+ export * from './core/common/interfaces/prepare-output-options.interface';
38
40
  export * from './core/common/interfaces/resolve-selector.interface';
39
41
  export * from './core/common/interfaces/server-options.interface';
40
42
  export * from './core/common/interfaces/service-options.interface';
@@ -65,6 +67,8 @@ export * from './core/common/types/string-or-object-id.type';
65
67
 
66
68
  export * from './core/modules/auth/guards/auth.guard';
67
69
  export * from './core/modules/auth/guards/roles.guard';
70
+ export * from './core/modules/auth/inputs/core-auth-sign-in.input';
71
+ export * from './core/modules/auth/inputs/core-auth-sign-up.input';
68
72
  export * from './core/modules/auth/interfaces/core-auth-user.interface';
69
73
  export * from './core/modules/auth/interfaces/jwt-payload.interface';
70
74
  export * from './core/modules/auth/services/core-auth.service';
@@ -3,22 +3,22 @@ import { CoreAuthModel } from '../../../core/modules/auth/core-auth.model';
3
3
  import { User } from '../user/user.model';
4
4
 
5
5
  /**
6
- * CoreAuthModel model for the response after the sign in
6
+ * Authentication data
7
7
  */
8
- @ObjectType({ description: 'Auth' })
8
+ @ObjectType({ description: 'Authentication data' })
9
9
  export class Auth extends CoreAuthModel {
10
10
  // ===================================================================================================================
11
11
  // Properties
12
12
  // ===================================================================================================================
13
13
 
14
14
  /**
15
- * Signed in user
15
+ * Signed-in user
16
16
  */
17
- @Field((type) => User, { description: 'User who signed in' })
17
+ @Field(() => User, { description: 'User who signed in' })
18
18
  user: User = undefined;
19
19
 
20
20
  // ===================================================================================================================
21
- // Properties
21
+ // Methods
22
22
  // ===================================================================================================================
23
23
 
24
24
  /**
@@ -1,9 +1,11 @@
1
1
  import { DynamicModule, Module } from '@nestjs/common';
2
2
  import { JwtModuleOptions } from '@nestjs/jwt';
3
+ import { EmailService } from '../../../core/common/services/email.service';
3
4
  import { CoreAuthModule } from '../../../core/modules/auth/core-auth.module';
4
5
  import { UserModule } from '../user/user.module';
5
6
  import { UserService } from '../user/user.service';
6
7
  import { AuthResolver } from './auth.resolver';
8
+ import { AuthService } from './auth.service';
7
9
 
8
10
  /**
9
11
  * CoreAuthModule to handle user authentication
@@ -17,8 +19,17 @@ export class AuthModule {
17
19
  static forRoot(options: JwtModuleOptions): DynamicModule {
18
20
  return {
19
21
  module: AuthModule,
20
- imports: [CoreAuthModule.forRoot(UserModule, UserService, options)],
21
- providers: [AuthResolver],
22
+ imports: [
23
+ CoreAuthModule.forRoot(UserModule, UserService, {
24
+ ...options,
25
+ ...{
26
+ // imports: [], // Integrate additional Services here to resolve dependencies
27
+ // providers: [] // Integrate additional Providers here to resolve dependencies
28
+ },
29
+ }),
30
+ EmailService,
31
+ ],
32
+ providers: [AuthResolver, AuthService],
22
33
  exports: [AuthResolver, CoreAuthModule],
23
34
  };
24
35
  }
@@ -1,22 +1,40 @@
1
- import { Args, Info, Query, Resolver } from '@nestjs/graphql';
1
+ import { Args, Info, Mutation, Query, Resolver } from '@nestjs/graphql';
2
2
  import { GraphQLResolveInfo } from 'graphql';
3
- import { CoreAuthResolver } from '../../../core/modules/auth/core-auth.resolver';
4
3
  import { Auth } from './auth.model';
4
+ import { AuthService } from './auth.service';
5
+ import { AuthSignInInput } from './inputs/auth-sign-in.input';
6
+ import { AuthSignUpInput } from './inputs/auth-sign-up.input';
5
7
 
6
8
  /**
7
9
  * Authentication resolver for the sign in
8
10
  */
9
- @Resolver((of) => Auth)
10
- export class AuthResolver extends CoreAuthResolver {
11
+ @Resolver(() => Auth)
12
+ export class AuthResolver {
11
13
  /**
12
- * Get user via ID
14
+ * Integrate services
13
15
  */
14
- @Query((returns) => Auth, { description: 'Get JWT token' })
15
- async signIn(
16
- @Args('email') email: string,
17
- @Args('password') password: string,
18
- @Info() info: GraphQLResolveInfo
19
- ): Promise<Auth> {
20
- return (await this.authService.signIn(email, password, { fieldSelection: { info, select: 'signIn' } })) as Auth;
16
+ constructor(private readonly authService: AuthService) {}
17
+
18
+ /**
19
+ * SignIn for User
20
+ */
21
+ @Query(() => Auth, { description: 'Sign in and get JWT token' })
22
+ async signIn(@Info() info: GraphQLResolveInfo, @Args('input') input: AuthSignInInput): Promise<Auth> {
23
+ return this.authService.signIn(input, {
24
+ fieldSelection: { info, select: 'signIn' },
25
+ inputType: AuthSignInInput,
26
+ });
27
+ }
28
+
29
+ /**
30
+ * Sign up for user
31
+ */
32
+ @Mutation(() => Auth, {
33
+ description: 'Sign up user and get JWT token',
34
+ })
35
+ async signUp(@Info() info: GraphQLResolveInfo, @Args('input') input: AuthSignUpInput): Promise<Auth> {
36
+ return this.authService.signUp(input, {
37
+ fieldSelection: { info, select: 'signUp' },
38
+ });
21
39
  }
22
40
  }