@lenne.tech/nest-server 8.6.7 → 8.6.10

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 (109) hide show
  1. package/dist/core/common/decorators/graphql-user.decorator.js +2 -3
  2. package/dist/core/common/decorators/graphql-user.decorator.js.map +1 -1
  3. package/dist/core/common/decorators/restricted.decorator.js +14 -13
  4. package/dist/core/common/decorators/restricted.decorator.js.map +1 -1
  5. package/dist/core/common/helpers/context.helper.js +4 -5
  6. package/dist/core/common/helpers/context.helper.js.map +1 -1
  7. package/dist/core/common/helpers/db.helper.js +32 -21
  8. package/dist/core/common/helpers/db.helper.js.map +1 -1
  9. package/dist/core/common/helpers/file.helper.js +5 -1
  10. package/dist/core/common/helpers/file.helper.js.map +1 -1
  11. package/dist/core/common/helpers/filter.helper.js +16 -9
  12. package/dist/core/common/helpers/filter.helper.js.map +1 -1
  13. package/dist/core/common/helpers/graphql.helper.js +11 -8
  14. package/dist/core/common/helpers/graphql.helper.js.map +1 -1
  15. package/dist/core/common/helpers/input.helper.js +17 -11
  16. package/dist/core/common/helpers/input.helper.js.map +1 -1
  17. package/dist/core/common/helpers/model.helper.d.ts +2 -0
  18. package/dist/core/common/helpers/model.helper.js +125 -3
  19. package/dist/core/common/helpers/model.helper.js.map +1 -1
  20. package/dist/core/common/helpers/service.helper.js +27 -13
  21. package/dist/core/common/helpers/service.helper.js.map +1 -1
  22. package/dist/core/common/inputs/core-input.input.js +6 -1
  23. package/dist/core/common/inputs/core-input.input.js.map +1 -1
  24. package/dist/core/common/inputs/single-filter.input.d.ts +1 -0
  25. package/dist/core/common/inputs/single-filter.input.js +8 -0
  26. package/dist/core/common/inputs/single-filter.input.js.map +1 -1
  27. package/dist/core/common/models/core-model.model.js +14 -2
  28. package/dist/core/common/models/core-model.model.js.map +1 -1
  29. package/dist/core/common/pipes/check-input.pipe.js +1 -1
  30. package/dist/core/common/pipes/check-input.pipe.js.map +1 -1
  31. package/dist/core/common/pipes/map-and-validate.pipe.js +2 -2
  32. package/dist/core/common/pipes/map-and-validate.pipe.js.map +1 -1
  33. package/dist/core/common/services/crud.service.js +3 -5
  34. package/dist/core/common/services/crud.service.js.map +1 -1
  35. package/dist/core/common/services/email.service.js +5 -1
  36. package/dist/core/common/services/email.service.js.map +1 -1
  37. package/dist/core/common/services/mailjet.service.d.ts +1 -1
  38. package/dist/core/common/services/mailjet.service.js +10 -3
  39. package/dist/core/common/services/mailjet.service.js.map +1 -1
  40. package/dist/core/common/services/module.service.js +29 -7
  41. package/dist/core/common/services/module.service.js.map +1 -1
  42. package/dist/core/modules/auth/core-auth.module.js +2 -2
  43. package/dist/core/modules/auth/core-auth.module.js.map +1 -1
  44. package/dist/core/modules/auth/guards/auth.guard.js +4 -5
  45. package/dist/core/modules/auth/guards/auth.guard.js.map +1 -1
  46. package/dist/core/modules/auth/guards/roles.guard.js +1 -2
  47. package/dist/core/modules/auth/guards/roles.guard.js.map +1 -1
  48. package/dist/core/modules/file/core-file.service.d.ts +26 -0
  49. package/dist/core/modules/file/core-file.service.js +116 -0
  50. package/dist/core/modules/file/core-file.service.js.map +1 -0
  51. package/dist/core/modules/file/file-info.output.d.ts +10 -0
  52. package/dist/core/modules/file/file-info.output.js +49 -0
  53. package/dist/core/modules/file/file-info.output.js.map +1 -0
  54. package/dist/core/modules/file/interfaces/file-service-options.interface.d.ts +7 -0
  55. package/dist/core/modules/file/interfaces/file-service-options.interface.js +3 -0
  56. package/dist/core/modules/file/interfaces/file-service-options.interface.js.map +1 -0
  57. package/dist/core/modules/file/interfaces/file-upload.interface.d.ts +13 -0
  58. package/dist/core/modules/file/interfaces/file-upload.interface.js +3 -0
  59. package/dist/core/modules/file/interfaces/file-upload.interface.js.map +1 -0
  60. package/dist/core/modules/user/core-user.service.js +7 -3
  61. package/dist/core/modules/user/core-user.service.js.map +1 -1
  62. package/dist/core.module.js +34 -39
  63. package/dist/core.module.js.map +1 -1
  64. package/dist/index.d.ts +4 -0
  65. package/dist/index.js +4 -0
  66. package/dist/index.js.map +1 -1
  67. package/dist/server/modules/auth/auth.module.js +4 -1
  68. package/dist/server/modules/auth/auth.module.js.map +1 -1
  69. package/dist/server/modules/file/file.controller.d.ts +6 -1
  70. package/dist/server/modules/file/file.controller.js +34 -4
  71. package/dist/server/modules/file/file.controller.js.map +1 -1
  72. package/dist/server/modules/file/file.resolver.d.ts +8 -2
  73. package/dist/server/modules/file/file.resolver.js +47 -11
  74. package/dist/server/modules/file/file.resolver.js.map +1 -1
  75. package/dist/server/modules/file/file.service.d.ts +6 -0
  76. package/dist/server/modules/file/file.service.js +32 -0
  77. package/dist/server/modules/file/file.service.js.map +1 -0
  78. package/dist/server/modules/user/user.model.d.ts +1 -0
  79. package/dist/server/modules/user/user.model.js +5 -0
  80. package/dist/server/modules/user/user.model.js.map +1 -1
  81. package/dist/server/modules/user/user.resolver.js +1 -2
  82. package/dist/server/modules/user/user.resolver.js.map +1 -1
  83. package/dist/server/modules/user/user.service.js +2 -2
  84. package/dist/server/modules/user/user.service.js.map +1 -1
  85. package/dist/server/server.module.js +2 -1
  86. package/dist/server/server.module.js.map +1 -1
  87. package/dist/test/test.helper.d.ts +24 -1
  88. package/dist/test/test.helper.js +100 -13
  89. package/dist/test/test.helper.js.map +1 -1
  90. package/dist/tsconfig.build.tsbuildinfo +1 -1
  91. package/package.json +24 -23
  92. package/src/core/common/helpers/db.helper.ts +2 -0
  93. package/src/core/common/helpers/filter.helper.ts +7 -1
  94. package/src/core/common/helpers/model.helper.ts +152 -0
  95. package/src/core/common/inputs/single-filter.input.ts +10 -1
  96. package/src/core/common/services/mailjet.service.ts +1 -1
  97. package/src/core/common/services/module.service.ts +1 -1
  98. package/src/core/modules/file/core-file.service.ts +179 -0
  99. package/src/core/modules/file/file-info.output.ts +26 -0
  100. package/src/core/modules/file/interfaces/file-service-options.interface.ts +7 -0
  101. package/src/core/modules/file/interfaces/file-upload.interface.ts +38 -0
  102. package/src/core.module.ts +1 -1
  103. package/src/index.ts +9 -0
  104. package/src/server/modules/file/file.controller.ts +43 -4
  105. package/src/server/modules/file/file.resolver.ts +58 -33
  106. package/src/server/modules/file/file.service.ts +11 -0
  107. package/src/server/modules/user/user.model.ts +9 -0
  108. package/src/server/server.module.ts +2 -1
  109. package/src/test/test.helper.ts +125 -7
@@ -1,55 +1,80 @@
1
- import { Args, Mutation, Resolver } from '@nestjs/graphql';
1
+ import { Args, Mutation, Query, Resolver } from '@nestjs/graphql';
2
2
  import { createWriteStream } from 'fs';
3
- import { FileUpload, GraphQLUpload } from 'graphql-upload';
3
+ import * as GraphQLUpload from 'graphql-upload/GraphQLUpload.js';
4
+ import { Roles } from '../../../core/common/decorators/roles.decorator';
5
+ import { RoleEnum } from '../../../core/common/enums/role.enum';
6
+ import { FileInfo } from '../../../core/modules/file/file-info.output';
7
+ import { FileUpload } from '../../../core/modules/file/interfaces/file-upload.interface';
8
+ import { FileService } from './file.service';
4
9
 
5
10
  /**
6
11
  * File resolver
7
12
  */
8
13
  @Resolver()
9
14
  export class FileResolver {
15
+ /**
16
+ * Integrate services
17
+ */
18
+ constructor(protected readonly fileService: FileService) {}
19
+
20
+ // ===========================================================================
21
+ // Queries
22
+ // ===========================================================================
23
+
24
+ /**
25
+ * Get file info
26
+ */
27
+ @Roles(RoleEnum.ADMIN)
28
+ @Query(() => FileInfo, { nullable: true })
29
+ async getFileInfo(@Args({ name: 'filename', type: () => String }) filename: string) {
30
+ return await this.fileService.getFileInfoByName(filename);
31
+ }
32
+
33
+ // ===========================================================================
34
+ // Mutations
35
+ // ===========================================================================
36
+
37
+ /**
38
+ * Delete file
39
+ */
40
+ @Roles(RoleEnum.ADMIN)
41
+ @Mutation(() => FileInfo)
42
+ async deleteFile(@Args({ name: 'filename', type: () => String }) filename: string) {
43
+ return await this.fileService.deleteFileByName(filename);
44
+ }
45
+
10
46
  /**
11
47
  * Upload file
12
48
  */
13
- @Mutation(() => Boolean)
14
- async uploadFile(
15
- @Args({ name: 'file', type: () => GraphQLUpload })
16
- file: FileUpload
17
- ) {
18
- console.log(JSON.stringify(file, null, 2));
19
- /*
20
- const {filename, mimetype, encoding, createReadStream} = file;
21
- await new Promise((resolve, reject) =>
22
- createReadStream()
23
- .pipe(createWriteStream(`./uploads/${filename}`))
24
- .on('finish', () => resolve(true))
25
- .on('error', (error) => reject(error))
26
- );
27
- */
28
- return true;
49
+ @Roles(RoleEnum.ADMIN)
50
+ @Mutation(() => FileInfo)
51
+ async uploadFile(@Args({ name: 'file', type: () => GraphQLUpload }) file: FileUpload) {
52
+ const { filename, mimetype, encoding, createReadStream } = file;
53
+
54
+ // Save file in DB
55
+ return await this.fileService.createFile(file);
29
56
  }
30
57
 
31
58
  /**
32
59
  * Upload files
33
60
  */
61
+ @Roles(RoleEnum.ADMIN)
34
62
  @Mutation(() => Boolean)
35
- async uploadFiles(
36
- @Args({ name: 'files', type: () => [GraphQLUpload] })
37
- files: FileUpload[]
38
- ) {
63
+ async uploadFiles(@Args({ name: 'files', type: () => [GraphQLUpload] }) files: FileUpload[]) {
64
+ // Save files in filesystem
39
65
  const promises: Promise<any>[] = [];
40
66
  for (const file of files) {
41
- console.log(JSON.stringify(await file, null, 2));
42
- /*
43
- const {filename, mimetype, encoding, createReadStream} = await file
44
- promises.push(new Promise((resolve, reject) =>
45
- createReadStream()
46
- .pipe(createWriteStream(`./uploads/${filename}`))
47
- .on('finish', () => resolve(true))
48
- .on('error', (error) => reject(error))
49
- ));
50
- */
67
+ const { filename, mimetype, encoding, createReadStream } = await file;
68
+ promises.push(
69
+ new Promise((resolve, reject) =>
70
+ createReadStream()
71
+ .pipe(createWriteStream(`./uploads/${filename}`))
72
+ .on('finish', () => resolve(true))
73
+ .on('error', (error) => reject(error))
74
+ )
75
+ );
51
76
  }
52
- await Promise.all(promises);
77
+ await Promise.allSettled(promises);
53
78
  return true;
54
79
  }
55
80
  }
@@ -0,0 +1,11 @@
1
+ import { Injectable } from '@nestjs/common';
2
+ import { InjectConnection } from '@nestjs/mongoose';
3
+ import { Connection } from 'mongoose';
4
+ import { CoreFileService } from '../../../core/modules/file/core-file.service';
5
+
6
+ @Injectable()
7
+ export class FileService extends CoreFileService {
8
+ constructor(@InjectConnection() protected readonly connection: Connection) {
9
+ super(connection, 'File');
10
+ }
11
+ }
@@ -1,6 +1,7 @@
1
1
  import { Field, ObjectType } from '@nestjs/graphql';
2
2
  import { Prop, Schema as MongooseSchema, SchemaFactory } from '@nestjs/mongoose';
3
3
  import { Document, Schema } from 'mongoose';
4
+ import { mapClasses } from '../../../core/common/helpers/model.helper';
4
5
  import { CoreUserModel } from '../../../core/modules/user/core-user.model';
5
6
  import { PersistenceModel } from '../../common/models/persistence.model';
6
7
 
@@ -59,6 +60,14 @@ export class User extends CoreUserModel implements PersistenceModel {
59
60
  // Nothing more to initialize yet
60
61
  return this;
61
62
  }
63
+
64
+ /**
65
+ * Map input
66
+ */
67
+ map(input) {
68
+ super.map(input);
69
+ return mapClasses(input, { createdBy: User, updatedBy: User }, this);
70
+ }
62
71
  }
63
72
 
64
73
  export const UserSchema = SchemaFactory.createForClass(User);
@@ -5,6 +5,7 @@ import { CoreAuthService } from '../core/modules/auth/services/core-auth.service
5
5
  import { AuthModule } from './modules/auth/auth.module';
6
6
  import { FileController } from './modules/file/file.controller';
7
7
  import { FileResolver } from './modules/file/file.resolver';
8
+ import { FileService } from './modules/file/file.service';
8
9
  import { ServerController } from './server.controller';
9
10
 
10
11
  /**
@@ -28,7 +29,7 @@ import { ServerController } from './server.controller';
28
29
  controllers: [FileController, ServerController],
29
30
 
30
31
  // Include resolvers, services and other providers
31
- providers: [FileResolver],
32
+ providers: [FileService, FileResolver],
32
33
 
33
34
  // Export modules for reuse in other modules
34
35
  exports: [CoreModule, AuthModule],
@@ -1,7 +1,10 @@
1
1
  import { INestApplication } from '@nestjs/common';
2
+ import { Blob } from 'buffer';
3
+ import * as fs from 'fs';
2
4
  import { createClient } from 'graphql-ws';
3
5
  import { jsonToGraphQLQuery } from 'json-to-graphql-query';
4
6
  import * as LightMyRequest from 'light-my-request';
7
+ import * as superagent from 'superagent';
5
8
  import * as supertest from 'supertest';
6
9
  import * as util from 'util';
7
10
  import * as ws from 'ws';
@@ -53,6 +56,21 @@ export interface TestGraphQLConfig {
53
56
  * https://graphql.org/learn/queries
54
57
  */
55
58
  type?: TestGraphQLType;
59
+
60
+ /**
61
+ * GraphQL variables with variable name as key and Type as value
62
+ */
63
+ variables?: Record<string, string>;
64
+ }
65
+
66
+ export interface TestGraphQLAttachment {
67
+ file: Blob | Buffer | fs.ReadStream | string | boolean | number;
68
+ options?: string | { filename?: string | undefined; contentType?: string | undefined };
69
+ }
70
+
71
+ export interface TestGraphQLVariable {
72
+ value: string | string[] | TestGraphQLAttachment | TestGraphQLAttachment[] | any;
73
+ type: 'field' | 'attachment';
56
74
  }
57
75
 
58
76
  /**
@@ -89,6 +107,11 @@ export interface TestGraphQLOptions {
89
107
  * Token of user who is logged in
90
108
  */
91
109
  token?: string;
110
+
111
+ /**
112
+ * GraphQL variables
113
+ */
114
+ variables?: Record<string, TestGraphQLVariable>;
92
115
  }
93
116
 
94
117
  /**
@@ -122,6 +145,36 @@ export class TestHelper {
122
145
  this.subscriptionUrl = subscriptionUrl;
123
146
  }
124
147
 
148
+ /**
149
+ * Download file from URL
150
+ * @return Superagent response with additional data field containing the content of the file
151
+ */
152
+ download(url: string, token?: string): Promise<superagent.Response & { data: string }> {
153
+ return new Promise((resolve, reject) => {
154
+ const request = supertest((this.app as INestApplication).getHttpServer()).get(url);
155
+ if (token) {
156
+ request.set('Authorization', 'bearer ' + token);
157
+ }
158
+ let data = '';
159
+ request
160
+ .buffer()
161
+ .parse((res: any, callback) => {
162
+ res.setEncoding('binary');
163
+ res.on('data', (chunk) => {
164
+ data += chunk;
165
+ });
166
+ res.on('error', reject);
167
+ res.on('end', (err) => {
168
+ err ? reject(err) : callback(null, null);
169
+ });
170
+ })
171
+ .end((err, res: superagent.Response) => {
172
+ (res as superagent.Response & { data: string }).data = new Buffer(data, 'binary').toString();
173
+ err ? reject(err) : resolve(res as superagent.Response & { data: string });
174
+ });
175
+ });
176
+ }
177
+
125
178
  /**
126
179
  * GraphQL request
127
180
  */
@@ -138,7 +191,7 @@ export class TestHelper {
138
191
  };
139
192
 
140
193
  // Init vars
141
- const { token, statusCode, log, logError } = config;
194
+ const { token, statusCode, log, logError, variables } = config;
142
195
 
143
196
  // Init
144
197
  let query = '';
@@ -170,6 +223,11 @@ export class TestHelper {
170
223
  // Set request type
171
224
  queryObj[graphql.type] = {};
172
225
 
226
+ // Set variables
227
+ if (graphql.variables) {
228
+ queryObj[graphql.type]['__variables'] = graphql.variables;
229
+ }
230
+
173
231
  // Set request name and fields
174
232
  queryObj[graphql.type][graphql.name] = this.prepareFields(graphql.fields) || {};
175
233
 
@@ -212,7 +270,7 @@ export class TestHelper {
212
270
  }
213
271
 
214
272
  // Get response
215
- const response = await this.getResponse(token, requestConfig, statusCode, log, logError);
273
+ const response = await this.getResponse(token, requestConfig, statusCode, log, logError, variables);
216
274
 
217
275
  // Response of fastify
218
276
  // if ((this.app as FastifyInstance).inject) {
@@ -325,7 +383,8 @@ export class TestHelper {
325
383
  requestConfig: LightMyRequest.InjectOptions,
326
384
  statusCode: number,
327
385
  log: boolean,
328
- logError: boolean
386
+ logError: boolean,
387
+ variables?: Record<string, TestGraphQLVariable>
329
388
  ): Promise<any> {
330
389
  // Token
331
390
  if (token) {
@@ -356,15 +415,74 @@ export class TestHelper {
356
415
  const method: string = requestConfig.method.toLowerCase();
357
416
  let request = supertest((this.app as INestApplication).getHttpServer())[method](requestConfig.url as string);
358
417
  if (token) {
359
- request = request.set('Authorization', 'bearer ' + token);
418
+ request.set('Authorization', 'bearer ' + token);
419
+ }
420
+
421
+ // Process variables
422
+ if (variables) {
423
+ request = this.processVariables(request, variables, (requestConfig.payload as any)?.query);
360
424
  }
361
425
 
362
426
  // Response
363
- const response = await request.send(requestConfig.payload);
427
+ const response = await (variables ? request : request.send(requestConfig.payload));
428
+ return this.processResponse(response, statusCode, log, logError);
429
+ }
430
+
431
+ /**
432
+ * Process GraphQL variables
433
+ */
434
+ processVariables(request: any, variables: Record<string, TestGraphQLVariable>, query: string | object) {
435
+ // Check and optimize parameters
436
+ if (!variables) {
437
+ return request;
438
+ }
439
+ if (typeof query === 'object') {
440
+ query = JSON.stringify(query).replace(/"/g, '');
441
+ }
442
+
443
+ // Create map
444
+ const mapArray: { key: string; type: 'attachment' | 'field'; value: any; index?: number }[] = [];
445
+ for (const [key, item] of Object.entries(variables)) {
446
+ if (item.type === 'attachment' && Array.isArray(item.value)) {
447
+ item.value.forEach((element, index) => {
448
+ mapArray.push({ key, type: 'attachment', value: element, index });
449
+ });
450
+ } else {
451
+ mapArray.push({ key, type: item.type, value: item.value });
452
+ }
453
+ }
454
+ const map = {};
455
+ mapArray.forEach((item, index) => {
456
+ map[index] = ['variables.' + item.key + ('index' in item ? '.' + item.index : '')];
457
+ });
364
458
 
459
+ // Add operations
460
+ request.field('operations', JSON.stringify({ query })).field('map', JSON.stringify(map));
461
+
462
+ // Add variables as attachment or field
463
+ mapArray.forEach((variable, i) => {
464
+ if (variable.type === 'attachment') {
465
+ if (typeof variable.value === 'object' && variable.value.file) {
466
+ request.attach(`${i}`, variable.value.file, variable.value.options);
467
+ } else {
468
+ request.attach(`${i}`, variable.value);
469
+ }
470
+ } else {
471
+ request.field(`${i}`, variable.value);
472
+ }
473
+ });
474
+
475
+ // Return processed request
476
+ return request;
477
+ }
478
+
479
+ /**
480
+ * Process GraphQL response
481
+ */
482
+ processResponse(response, statusCode, log, logError) {
365
483
  // Log response
366
484
  if (log) {
367
- console.log(JSON.stringify(response, null, 2));
485
+ console.log('Response', JSON.stringify(response, null, 2));
368
486
  }
369
487
 
370
488
  // Log error
@@ -372,7 +490,7 @@ export class TestHelper {
372
490
  if (response && response.error && response.error.text) {
373
491
  const errors = JSON.parse(response.error.text).errors;
374
492
  for (const error of errors) {
375
- console.log(util.inspect(error, false, null, true));
493
+ console.error(util.inspect(error, false, null, true));
376
494
  }
377
495
  }
378
496
  }