@lenne.tech/nest-server 9.2.4 → 9.2.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/core/common/helpers/input.helper.d.ts +2 -0
- package/dist/core/common/helpers/input.helper.js +9 -3
- package/dist/core/common/helpers/input.helper.js.map +1 -1
- package/dist/core/common/interceptors/check-security.interceptor.js +4 -1
- package/dist/core/common/interceptors/check-security.interceptor.js.map +1 -1
- package/dist/core/common/models/core-model.model.js.map +1 -1
- package/dist/core/common/services/crud.service.d.ts +32 -30
- package/dist/core/common/services/crud.service.js +4 -4
- package/dist/core/common/services/crud.service.js.map +1 -1
- package/dist/core/common/types/is-one-of.type.d.ts +3 -0
- package/dist/core/common/types/is-one-of.type.js +3 -0
- package/dist/core/common/types/is-one-of.type.js.map +1 -0
- package/dist/core/modules/auth/guards/auth.guard.js.map +1 -1
- package/dist/core/modules/auth/guards/roles.guard.js +11 -1
- package/dist/core/modules/auth/guards/roles.guard.js.map +1 -1
- package/dist/core/modules/user/core-user.service.d.ts +1 -1
- package/dist/core/modules/user/core-user.service.js +1 -1
- package/dist/core/modules/user/core-user.service.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/server/modules/auth/auth.module.js +3 -2
- package/dist/server/modules/auth/auth.module.js.map +1 -1
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/src/core/common/helpers/input.helper.ts +17 -3
- package/src/core/common/interceptors/check-security.interceptor.ts +13 -6
- package/src/core/common/models/core-model.model.ts +1 -1
- package/src/core/common/services/crud.service.ts +46 -39
- package/src/core/common/types/is-one-of.type.ts +26 -0
- package/src/core/modules/auth/guards/auth.guard.ts +1 -2
- package/src/core/modules/auth/guards/roles.guard.ts +13 -3
- package/src/core/modules/user/core-user.service.ts +2 -2
- package/src/index.ts +1 -0
- package/src/server/modules/auth/auth.module.ts +3 -2
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lenne.tech/nest-server",
|
|
3
|
-
"version": "9.2.
|
|
3
|
+
"version": "9.2.6",
|
|
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",
|
|
@@ -654,14 +654,22 @@ export function processDeep(
|
|
|
654
654
|
data: any,
|
|
655
655
|
func: (data: any) => any,
|
|
656
656
|
options?: {
|
|
657
|
+
// Remember already processed objects to avoid infinite processes
|
|
657
658
|
processedObjects?: WeakMap<new () => any, boolean>;
|
|
659
|
+
|
|
660
|
+
// For objects of special classes or objects with special functions or special properties,
|
|
661
|
+
// only the objects themselves are processed with func, not the individual properties of the object additionally
|
|
658
662
|
specialClasses?: ((new (args: any[]) => any) | string)[];
|
|
663
|
+
specialFunctions?: string[];
|
|
664
|
+
specialProperties?: string[];
|
|
659
665
|
}
|
|
660
666
|
): any {
|
|
661
667
|
// Set options
|
|
662
|
-
const { processedObjects, specialClasses } = {
|
|
668
|
+
const { processedObjects, specialClasses, specialFunctions, specialProperties } = {
|
|
663
669
|
processedObjects: new WeakMap(),
|
|
664
670
|
specialClasses: [],
|
|
671
|
+
specialFunctions: [],
|
|
672
|
+
specialProperties: [],
|
|
665
673
|
...options,
|
|
666
674
|
};
|
|
667
675
|
|
|
@@ -680,11 +688,17 @@ export function processDeep(
|
|
|
680
688
|
|
|
681
689
|
// Process array
|
|
682
690
|
if (Array.isArray(data)) {
|
|
683
|
-
return data.map((item) => processDeep(item, func, { processedObjects, specialClasses }));
|
|
691
|
+
return func(data.map((item) => processDeep(item, func, { processedObjects, specialClasses })));
|
|
684
692
|
}
|
|
685
693
|
|
|
686
694
|
// Process object
|
|
687
695
|
if (typeof data === 'object') {
|
|
696
|
+
if (
|
|
697
|
+
specialFunctions.find((sF) => typeof data[sF] === 'function') ||
|
|
698
|
+
specialProperties.find((sP) => Object.getOwnPropertyNames(data).includes(sP))
|
|
699
|
+
) {
|
|
700
|
+
return func(data);
|
|
701
|
+
}
|
|
688
702
|
for (const specialClass of specialClasses) {
|
|
689
703
|
if (
|
|
690
704
|
(typeof specialClass === 'string' && specialClass === data.constructor?.name) ||
|
|
@@ -696,7 +710,7 @@ export function processDeep(
|
|
|
696
710
|
for (const [key, value] of Object.entries(data)) {
|
|
697
711
|
data[key] = processDeep(value, func, { processedObjects, specialClasses });
|
|
698
712
|
}
|
|
699
|
-
return data;
|
|
713
|
+
return func(data);
|
|
700
714
|
}
|
|
701
715
|
|
|
702
716
|
// Process others
|
|
@@ -40,12 +40,19 @@ export class CheckSecurityInterceptor implements NestInterceptor {
|
|
|
40
40
|
}
|
|
41
41
|
|
|
42
42
|
// Check deep
|
|
43
|
-
return processDeep(
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
43
|
+
return processDeep(
|
|
44
|
+
data,
|
|
45
|
+
(item) => {
|
|
46
|
+
if (!item || typeof item !== 'object' || typeof item.securityCheck !== 'function') {
|
|
47
|
+
if (Array.isArray(item)) {
|
|
48
|
+
return item.filter((i) => i !== undefined);
|
|
49
|
+
}
|
|
50
|
+
return item;
|
|
51
|
+
}
|
|
52
|
+
return item.securityCheck(user, force);
|
|
53
|
+
},
|
|
54
|
+
{ specialFunctions: ['securityCheck'] }
|
|
55
|
+
);
|
|
49
56
|
})
|
|
50
57
|
);
|
|
51
58
|
}
|
|
@@ -129,7 +129,7 @@ export abstract class CoreModel {
|
|
|
129
129
|
/**
|
|
130
130
|
* Verification of the user's rights to access the properties of this object
|
|
131
131
|
*/
|
|
132
|
-
securityCheck(user: any, force?: boolean): this {
|
|
132
|
+
public securityCheck(user: any, force?: boolean): this {
|
|
133
133
|
return this;
|
|
134
134
|
}
|
|
135
135
|
}
|
|
@@ -6,14 +6,19 @@ import { convertFilterArgsToQuery } from '../helpers/filter.helper';
|
|
|
6
6
|
import { mergePlain, prepareServiceOptionsForCreate } from '../helpers/input.helper';
|
|
7
7
|
import { ServiceOptions } from '../interfaces/service-options.interface';
|
|
8
8
|
import { CoreModel } from '../models/core-model.model';
|
|
9
|
+
import { PlainObject } from '../types/plain-object.type';
|
|
9
10
|
import { ConfigService } from './config.service';
|
|
10
11
|
import { ModuleService } from './module.service';
|
|
11
12
|
|
|
12
|
-
export abstract class CrudService<
|
|
13
|
+
export abstract class CrudService<
|
|
14
|
+
Model extends CoreModel = any,
|
|
15
|
+
CreateInput = any,
|
|
16
|
+
UpdateInput = any
|
|
17
|
+
> extends ModuleService<Model> {
|
|
13
18
|
/**
|
|
14
19
|
* Create item
|
|
15
20
|
*/
|
|
16
|
-
async create(input:
|
|
21
|
+
async create(input: PlainObject<CreateInput>, serviceOptions?: ServiceOptions): Promise<Model> {
|
|
17
22
|
serviceOptions = prepareServiceOptionsForCreate(serviceOptions);
|
|
18
23
|
return this.process(
|
|
19
24
|
async (data) => {
|
|
@@ -28,7 +33,7 @@ export abstract class CrudService<T extends CoreModel = any> extends ModuleServi
|
|
|
28
33
|
* Create item without checks or restrictions
|
|
29
34
|
* Warning: Disables the handling of rights and restrictions!
|
|
30
35
|
*/
|
|
31
|
-
async createForce(input:
|
|
36
|
+
async createForce(input: PlainObject<CreateInput>, serviceOptions: ServiceOptions = {}): Promise<Model> {
|
|
32
37
|
serviceOptions = serviceOptions || {};
|
|
33
38
|
serviceOptions.force = true;
|
|
34
39
|
return this.create(input, serviceOptions);
|
|
@@ -38,7 +43,7 @@ export abstract class CrudService<T extends CoreModel = any> extends ModuleServi
|
|
|
38
43
|
* Create item without checks, restrictions or preparations
|
|
39
44
|
* Warning: Disables the handling of rights and restrictions! The raw data may contain secrets (such as passwords).
|
|
40
45
|
*/
|
|
41
|
-
async createRaw(input:
|
|
46
|
+
async createRaw(input: PlainObject<CreateInput>, serviceOptions: ServiceOptions = {}): Promise<Model> {
|
|
42
47
|
serviceOptions = serviceOptions || {};
|
|
43
48
|
serviceOptions.prepareInput = null;
|
|
44
49
|
serviceOptions.prepareOutput = null;
|
|
@@ -48,7 +53,7 @@ export abstract class CrudService<T extends CoreModel = any> extends ModuleServi
|
|
|
48
53
|
/**
|
|
49
54
|
* Get item by ID
|
|
50
55
|
*/
|
|
51
|
-
async get(id: string, serviceOptions?: ServiceOptions): Promise<
|
|
56
|
+
async get(id: string, serviceOptions?: ServiceOptions): Promise<Model> {
|
|
52
57
|
const dbObject = await this.mainDbModel.findById(id).exec();
|
|
53
58
|
if (!dbObject) {
|
|
54
59
|
throw new NotFoundException(`No ${this.mainModelConstructor.name} found with ID: ${id}`);
|
|
@@ -60,7 +65,7 @@ export abstract class CrudService<T extends CoreModel = any> extends ModuleServi
|
|
|
60
65
|
* Get item by ID without checks or restrictions
|
|
61
66
|
* Warning: Disables the handling of rights and restrictions!
|
|
62
67
|
*/
|
|
63
|
-
async getForce(id: string, serviceOptions: ServiceOptions = {}): Promise<
|
|
68
|
+
async getForce(id: string, serviceOptions: ServiceOptions = {}): Promise<Model> {
|
|
64
69
|
serviceOptions = serviceOptions || {};
|
|
65
70
|
serviceOptions.force = true;
|
|
66
71
|
return this.get(id, serviceOptions);
|
|
@@ -70,7 +75,7 @@ export abstract class CrudService<T extends CoreModel = any> extends ModuleServi
|
|
|
70
75
|
* Get item by ID without checks, restrictions or preparations
|
|
71
76
|
* Warning: Disables the handling of rights and restrictions! The raw data may contain secrets (such as passwords).
|
|
72
77
|
*/
|
|
73
|
-
async getRaw(id: string, serviceOptions: ServiceOptions = {}): Promise<
|
|
78
|
+
async getRaw(id: string, serviceOptions: ServiceOptions = {}): Promise<Model> {
|
|
74
79
|
serviceOptions = serviceOptions || {};
|
|
75
80
|
serviceOptions.prepareInput = null;
|
|
76
81
|
serviceOptions.prepareOutput = null;
|
|
@@ -83,7 +88,7 @@ export abstract class CrudService<T extends CoreModel = any> extends ModuleServi
|
|
|
83
88
|
async find(
|
|
84
89
|
filter?: FilterArgs | { filterQuery?: FilterQuery<any>; queryOptions?: QueryOptions; samples?: number },
|
|
85
90
|
serviceOptions?: ServiceOptions
|
|
86
|
-
): Promise<
|
|
91
|
+
): Promise<Model[]> {
|
|
87
92
|
// If filter is not instance of FilterArgs a simple form with filterQuery and queryOptions is set
|
|
88
93
|
// and should not be processed as FilterArgs
|
|
89
94
|
if (!(filter instanceof FilterArgs) && serviceOptions?.inputType === FilterArgs) {
|
|
@@ -124,7 +129,7 @@ export abstract class CrudService<T extends CoreModel = any> extends ModuleServi
|
|
|
124
129
|
async findForce(
|
|
125
130
|
filter?: FilterArgs | { filterQuery?: FilterQuery<any>; queryOptions?: QueryOptions; samples?: number },
|
|
126
131
|
serviceOptions: ServiceOptions = {}
|
|
127
|
-
): Promise<
|
|
132
|
+
): Promise<Model[]> {
|
|
128
133
|
serviceOptions = serviceOptions || {};
|
|
129
134
|
serviceOptions.force = true;
|
|
130
135
|
return this.find(filter, serviceOptions);
|
|
@@ -137,7 +142,7 @@ export abstract class CrudService<T extends CoreModel = any> extends ModuleServi
|
|
|
137
142
|
async findRaw(
|
|
138
143
|
filter?: FilterArgs | { filterQuery?: FilterQuery<any>; queryOptions?: QueryOptions; samples?: number },
|
|
139
144
|
serviceOptions: ServiceOptions = {}
|
|
140
|
-
): Promise<
|
|
145
|
+
): Promise<Model[]> {
|
|
141
146
|
serviceOptions = serviceOptions || {};
|
|
142
147
|
serviceOptions.prepareInput = null;
|
|
143
148
|
serviceOptions.prepareOutput = null;
|
|
@@ -150,7 +155,7 @@ export abstract class CrudService<T extends CoreModel = any> extends ModuleServi
|
|
|
150
155
|
async findAndCount(
|
|
151
156
|
filter?: FilterArgs | { filterQuery?: FilterQuery<any>; queryOptions?: QueryOptions; samples?: number },
|
|
152
157
|
serviceOptions?: ServiceOptions
|
|
153
|
-
): Promise<{ items:
|
|
158
|
+
): Promise<{ items: Model[]; totalCount: number }> {
|
|
154
159
|
// If filter is not instance of FilterArgs a simple form with filterQuery and queryOptions is set
|
|
155
160
|
// and should not be processed as FilterArgs
|
|
156
161
|
if (!(filter instanceof FilterArgs) && serviceOptions?.inputType === FilterArgs) {
|
|
@@ -229,7 +234,7 @@ export abstract class CrudService<T extends CoreModel = any> extends ModuleServi
|
|
|
229
234
|
async findAndCountForce(
|
|
230
235
|
filter?: FilterArgs | { filterQuery?: FilterQuery<any>; queryOptions?: QueryOptions; samples?: number },
|
|
231
236
|
serviceOptions: ServiceOptions = {}
|
|
232
|
-
): Promise<{ items:
|
|
237
|
+
): Promise<{ items: Model[]; totalCount: number }> {
|
|
233
238
|
serviceOptions = serviceOptions || {};
|
|
234
239
|
serviceOptions.force = true;
|
|
235
240
|
return this.findAndCount(filter, serviceOptions);
|
|
@@ -242,7 +247,7 @@ export abstract class CrudService<T extends CoreModel = any> extends ModuleServi
|
|
|
242
247
|
async findAndCountRaw(
|
|
243
248
|
filter?: FilterArgs | { filterQuery?: FilterQuery<any>; queryOptions?: QueryOptions; samples?: number },
|
|
244
249
|
serviceOptions: ServiceOptions = {}
|
|
245
|
-
): Promise<{ items:
|
|
250
|
+
): Promise<{ items: Model[]; totalCount: number }> {
|
|
246
251
|
serviceOptions = serviceOptions || {};
|
|
247
252
|
serviceOptions.prepareInput = null;
|
|
248
253
|
serviceOptions.prepareOutput = null;
|
|
@@ -253,15 +258,15 @@ export abstract class CrudService<T extends CoreModel = any> extends ModuleServi
|
|
|
253
258
|
* Find and update
|
|
254
259
|
*/
|
|
255
260
|
async findAndUpdate(
|
|
256
|
-
filter: FilterArgs | { filterQuery?: FilterQuery<any>; queryOptions?: QueryOptions },
|
|
257
|
-
update:
|
|
261
|
+
filter: FilterArgs | { filterQuery?: FilterQuery<any>; queryOptions?: QueryOptions; samples?: number },
|
|
262
|
+
update: PlainObject<UpdateInput>,
|
|
258
263
|
serviceOptions?: ServiceOptions
|
|
259
|
-
): Promise<
|
|
260
|
-
const dbItems:
|
|
264
|
+
): Promise<Model[]> {
|
|
265
|
+
const dbItems: Model[] = await this.find(filter, serviceOptions);
|
|
261
266
|
if (!dbItems?.length) {
|
|
262
267
|
return [];
|
|
263
268
|
}
|
|
264
|
-
const promises: Promise<
|
|
269
|
+
const promises: Promise<Model>[] = [];
|
|
265
270
|
for (const dbItem of dbItems) {
|
|
266
271
|
promises.push(
|
|
267
272
|
new Promise(async (resolve, reject) => {
|
|
@@ -282,12 +287,13 @@ export abstract class CrudService<T extends CoreModel = any> extends ModuleServi
|
|
|
282
287
|
* Warning: Disables the handling of rights and restrictions!
|
|
283
288
|
*/
|
|
284
289
|
async findAndUpdateForce(
|
|
285
|
-
filter
|
|
290
|
+
filter: FilterArgs | { filterQuery?: FilterQuery<any>; queryOptions?: QueryOptions; samples?: number },
|
|
291
|
+
update: PlainObject<UpdateInput>,
|
|
286
292
|
serviceOptions: ServiceOptions = {}
|
|
287
|
-
): Promise<
|
|
293
|
+
): Promise<Model[]> {
|
|
288
294
|
serviceOptions = serviceOptions || {};
|
|
289
295
|
serviceOptions.force = true;
|
|
290
|
-
return this.findAndUpdate(filter, serviceOptions);
|
|
296
|
+
return this.findAndUpdate(filter, update, serviceOptions);
|
|
291
297
|
}
|
|
292
298
|
|
|
293
299
|
/**
|
|
@@ -295,19 +301,20 @@ export abstract class CrudService<T extends CoreModel = any> extends ModuleServi
|
|
|
295
301
|
* Warning: Disables the handling of rights and restrictions! The raw data may contain secrets (such as passwords).
|
|
296
302
|
*/
|
|
297
303
|
async findAndUpdateRaw(
|
|
298
|
-
filter
|
|
304
|
+
filter: FilterArgs | { filterQuery?: FilterQuery<any>; queryOptions?: QueryOptions; samples?: number },
|
|
305
|
+
update: PlainObject<UpdateInput>,
|
|
299
306
|
serviceOptions: ServiceOptions = {}
|
|
300
|
-
): Promise<
|
|
307
|
+
): Promise<Model[]> {
|
|
301
308
|
serviceOptions = serviceOptions || {};
|
|
302
309
|
serviceOptions.prepareInput = null;
|
|
303
310
|
serviceOptions.prepareOutput = null;
|
|
304
|
-
return this.findAndUpdateForce(filter, serviceOptions);
|
|
311
|
+
return this.findAndUpdateForce(filter, update, serviceOptions);
|
|
305
312
|
}
|
|
306
313
|
|
|
307
314
|
/**
|
|
308
315
|
* CRUD alias for get
|
|
309
316
|
*/
|
|
310
|
-
async read(id: string, serviceOptions?: ServiceOptions): Promise<
|
|
317
|
+
async read(id: string, serviceOptions?: ServiceOptions): Promise<Model>;
|
|
311
318
|
|
|
312
319
|
/**
|
|
313
320
|
* CRUD alias for find
|
|
@@ -315,7 +322,7 @@ export abstract class CrudService<T extends CoreModel = any> extends ModuleServi
|
|
|
315
322
|
async read(
|
|
316
323
|
filter: FilterArgs | { filterQuery?: FilterQuery<any>; queryOptions?: QueryOptions },
|
|
317
324
|
serviceOptions?: ServiceOptions
|
|
318
|
-
): Promise<
|
|
325
|
+
): Promise<Model[]>;
|
|
319
326
|
|
|
320
327
|
/**
|
|
321
328
|
* CRUD alias for get or find
|
|
@@ -323,7 +330,7 @@ export abstract class CrudService<T extends CoreModel = any> extends ModuleServi
|
|
|
323
330
|
async read(
|
|
324
331
|
input: string | FilterArgs | { filterQuery?: FilterQuery<any>; queryOptions?: QueryOptions },
|
|
325
332
|
serviceOptions?: ServiceOptions
|
|
326
|
-
): Promise<
|
|
333
|
+
): Promise<Model | Model[]> {
|
|
327
334
|
if (typeof input === 'string') {
|
|
328
335
|
return this.get(input, serviceOptions);
|
|
329
336
|
} else {
|
|
@@ -335,7 +342,7 @@ export abstract class CrudService<T extends CoreModel = any> extends ModuleServi
|
|
|
335
342
|
* CRUD alias for getForce
|
|
336
343
|
* Warning: Disables the handling of rights and restrictions!
|
|
337
344
|
*/
|
|
338
|
-
async readForce(id: string, serviceOptions?: ServiceOptions): Promise<
|
|
345
|
+
async readForce(id: string, serviceOptions?: ServiceOptions): Promise<Model>;
|
|
339
346
|
|
|
340
347
|
/**
|
|
341
348
|
* CRUD alias for findForce
|
|
@@ -344,7 +351,7 @@ export abstract class CrudService<T extends CoreModel = any> extends ModuleServi
|
|
|
344
351
|
async readForce(
|
|
345
352
|
filter: FilterArgs | { filterQuery?: FilterQuery<any>; queryOptions?: QueryOptions },
|
|
346
353
|
serviceOptions?: ServiceOptions
|
|
347
|
-
): Promise<
|
|
354
|
+
): Promise<Model[]>;
|
|
348
355
|
|
|
349
356
|
/**
|
|
350
357
|
* CRUD alias for getForce or findForce
|
|
@@ -353,7 +360,7 @@ export abstract class CrudService<T extends CoreModel = any> extends ModuleServi
|
|
|
353
360
|
async readForce(
|
|
354
361
|
input: string | FilterArgs | { filterQuery?: FilterQuery<any>; queryOptions?: QueryOptions },
|
|
355
362
|
serviceOptions?: ServiceOptions
|
|
356
|
-
): Promise<
|
|
363
|
+
): Promise<Model | Model[]> {
|
|
357
364
|
if (typeof input === 'string') {
|
|
358
365
|
return this.getForce(input, serviceOptions);
|
|
359
366
|
} else {
|
|
@@ -365,7 +372,7 @@ export abstract class CrudService<T extends CoreModel = any> extends ModuleServi
|
|
|
365
372
|
* CRUD alias for getRaw
|
|
366
373
|
* Warning: Disables the handling of rights and restrictions! The raw data may contain secrets (such as passwords).
|
|
367
374
|
*/
|
|
368
|
-
async readRaw(id: string, serviceOptions?: ServiceOptions): Promise<
|
|
375
|
+
async readRaw(id: string, serviceOptions?: ServiceOptions): Promise<Model>;
|
|
369
376
|
|
|
370
377
|
/**
|
|
371
378
|
* CRUD alias for findRaw
|
|
@@ -374,7 +381,7 @@ export abstract class CrudService<T extends CoreModel = any> extends ModuleServi
|
|
|
374
381
|
async readRaw(
|
|
375
382
|
filter: FilterArgs | { filterQuery?: FilterQuery<any>; queryOptions?: QueryOptions },
|
|
376
383
|
serviceOptions?: ServiceOptions
|
|
377
|
-
): Promise<
|
|
384
|
+
): Promise<Model[]>;
|
|
378
385
|
|
|
379
386
|
/**
|
|
380
387
|
* CRUD alias for getRaw or findRaw
|
|
@@ -383,7 +390,7 @@ export abstract class CrudService<T extends CoreModel = any> extends ModuleServi
|
|
|
383
390
|
async readRaw(
|
|
384
391
|
input: string | FilterArgs | { filterQuery?: FilterQuery<any>; queryOptions?: QueryOptions },
|
|
385
392
|
serviceOptions?: ServiceOptions
|
|
386
|
-
): Promise<
|
|
393
|
+
): Promise<Model | Model[]> {
|
|
387
394
|
if (typeof input === 'string') {
|
|
388
395
|
return this.getRaw(input, serviceOptions);
|
|
389
396
|
} else {
|
|
@@ -394,7 +401,7 @@ export abstract class CrudService<T extends CoreModel = any> extends ModuleServi
|
|
|
394
401
|
/**
|
|
395
402
|
* Update item via ID
|
|
396
403
|
*/
|
|
397
|
-
async update(id: string, input:
|
|
404
|
+
async update(id: string, input: PlainObject<UpdateInput>, serviceOptions?: ServiceOptions): Promise<Model> {
|
|
398
405
|
const dbObject = await this.mainDbModel.findById(id).lean();
|
|
399
406
|
if (!dbObject) {
|
|
400
407
|
throw new NotFoundException(`No ${this.mainModelConstructor.name} found with ID: ${id}`);
|
|
@@ -413,7 +420,7 @@ export abstract class CrudService<T extends CoreModel = any> extends ModuleServi
|
|
|
413
420
|
* Update item via ID without checks or restrictions
|
|
414
421
|
* Warning: Disables the handling of rights and restrictions!
|
|
415
422
|
*/
|
|
416
|
-
async updateForce(id: string, input:
|
|
423
|
+
async updateForce(id: string, input: PlainObject<UpdateInput>, serviceOptions?: ServiceOptions): Promise<Model> {
|
|
417
424
|
serviceOptions = serviceOptions || {};
|
|
418
425
|
serviceOptions.force = true;
|
|
419
426
|
return this.update(id, input, serviceOptions);
|
|
@@ -423,7 +430,7 @@ export abstract class CrudService<T extends CoreModel = any> extends ModuleServi
|
|
|
423
430
|
* Update item via ID without checks, restrictions or preparations
|
|
424
431
|
* Warning: Disables the handling of rights and restrictions! The raw data may contain secrets (such as passwords).
|
|
425
432
|
*/
|
|
426
|
-
async updateRaw(id: string, input:
|
|
433
|
+
async updateRaw(id: string, input: PlainObject<UpdateInput>, serviceOptions?: ServiceOptions): Promise<Model> {
|
|
427
434
|
serviceOptions = serviceOptions || {};
|
|
428
435
|
serviceOptions.prepareInput = null;
|
|
429
436
|
serviceOptions.prepareOutput = null;
|
|
@@ -433,7 +440,7 @@ export abstract class CrudService<T extends CoreModel = any> extends ModuleServi
|
|
|
433
440
|
/**
|
|
434
441
|
* Delete item via ID
|
|
435
442
|
*/
|
|
436
|
-
async delete(id: string, serviceOptions?: ServiceOptions): Promise<
|
|
443
|
+
async delete(id: string, serviceOptions?: ServiceOptions): Promise<Model> {
|
|
437
444
|
const dbObject = await this.mainDbModel.findById(id).exec();
|
|
438
445
|
if (!dbObject) {
|
|
439
446
|
throw new NotFoundException(`No ${this.mainModelConstructor.name} found with ID: ${id}`);
|
|
@@ -451,7 +458,7 @@ export abstract class CrudService<T extends CoreModel = any> extends ModuleServi
|
|
|
451
458
|
* Delete item via ID without checks or restrictions
|
|
452
459
|
* Warning: Disables the handling of rights and restrictions!
|
|
453
460
|
*/
|
|
454
|
-
async deleteForce(id: string, serviceOptions?: ServiceOptions): Promise<
|
|
461
|
+
async deleteForce(id: string, serviceOptions?: ServiceOptions): Promise<Model> {
|
|
455
462
|
serviceOptions = serviceOptions || {};
|
|
456
463
|
serviceOptions.force = true;
|
|
457
464
|
return this.delete(id, serviceOptions);
|
|
@@ -461,7 +468,7 @@ export abstract class CrudService<T extends CoreModel = any> extends ModuleServi
|
|
|
461
468
|
* Delete item via ID without checks, restrictions or preparations
|
|
462
469
|
* Warning: Disables the handling of rights and restrictions! The raw data may contain secrets (such as passwords).
|
|
463
470
|
*/
|
|
464
|
-
async deleteRaw(id: string, serviceOptions?: ServiceOptions): Promise<
|
|
471
|
+
async deleteRaw(id: string, serviceOptions?: ServiceOptions): Promise<Model> {
|
|
465
472
|
serviceOptions = serviceOptions || {};
|
|
466
473
|
serviceOptions.prepareInput = null;
|
|
467
474
|
serviceOptions.prepareOutput = null;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Type that ensures that the property or method is of a specific class
|
|
3
|
+
*
|
|
4
|
+
* Example (see https://stackoverflow.com/a/66202968):
|
|
5
|
+
*
|
|
6
|
+
* interface myFunctions{
|
|
7
|
+
* one: () => number;
|
|
8
|
+
* two: () => number;
|
|
9
|
+
* echo: (str: string) => string;
|
|
10
|
+
* }
|
|
11
|
+
*
|
|
12
|
+
* const myFunctions: myFunctions = {
|
|
13
|
+
* one: () => 1,
|
|
14
|
+
* two: () => 2,
|
|
15
|
+
* echo: (str: string) => str
|
|
16
|
+
* }
|
|
17
|
+
*
|
|
18
|
+
* const wrapper = <U extends (...args: any[]) => any>(func: U extends IsOneOf<myFunctions, U> ? U : never) => (...args: Parameters<U>) : ReturnType<U> => func(...args);
|
|
19
|
+
*
|
|
20
|
+
* const one = wrapper(myFunctions.one);
|
|
21
|
+
* const two = wrapper(myFunctions.two);
|
|
22
|
+
* const echo = wrapper(myFunctions.echo);
|
|
23
|
+
* const rand = wrapper((a:string,b:number,c:boolean) => {}); //not assignable to parameter of type 'never'.
|
|
24
|
+
* const hm = wrapper(() => 'a'); //also error
|
|
25
|
+
*/
|
|
26
|
+
export type IsOneOf<T, F> = { [P in keyof T]: F extends T[P] ? (T[P] extends F ? T[P] : never) : never }[keyof T];
|
|
@@ -1,9 +1,8 @@
|
|
|
1
|
-
import { CanActivate, ExecutionContext, Logger, mixin, Optional
|
|
1
|
+
import { CanActivate, ExecutionContext, Logger, mixin, Optional } from '@nestjs/common';
|
|
2
2
|
import { GqlExecutionContext } from '@nestjs/graphql';
|
|
3
3
|
import { AuthModuleOptions, Type } from '@nestjs/passport';
|
|
4
4
|
import { defaultOptions } from '@nestjs/passport/dist/options';
|
|
5
5
|
import { memoize } from '@nestjs/passport/dist/utils/memoize.util';
|
|
6
|
-
import * as jwt from 'jsonwebtoken';
|
|
7
6
|
import * as passport from 'passport';
|
|
8
7
|
import { AuthGuardStrategy } from '../auth-guard-strategy.enum';
|
|
9
8
|
import { ExpiredRefreshTokenException } from '../exceptions/expired-refresh-token.exception';
|
|
@@ -3,6 +3,8 @@ import { Reflector } from '@nestjs/core';
|
|
|
3
3
|
import { GqlExecutionContext } from '@nestjs/graphql';
|
|
4
4
|
import { RoleEnum } from '../../../common/enums/role.enum';
|
|
5
5
|
import { AuthGuardStrategy } from '../auth-guard-strategy.enum';
|
|
6
|
+
import { ExpiredTokenException } from '../exceptions/expired-token.exception';
|
|
7
|
+
import { InvalidTokenException } from '../exceptions/invalid-token.exception';
|
|
6
8
|
import { AuthGuard } from './auth.guard';
|
|
7
9
|
|
|
8
10
|
/**
|
|
@@ -45,14 +47,22 @@ export class RolesGuard extends AuthGuard(AuthGuardStrategy.JWT) {
|
|
|
45
47
|
|
|
46
48
|
// Check user and user roles
|
|
47
49
|
if (!user?.hasRole?.(roles)) {
|
|
48
|
-
// Get args
|
|
49
|
-
const args: any = GqlExecutionContext.create(context).getArgs();
|
|
50
|
-
|
|
51
50
|
// Check special user roles (user is logged in or access is free for any)
|
|
52
51
|
if ((user && roles.includes(RoleEnum.S_USER)) || roles.includes(RoleEnum.S_EVERYONE)) {
|
|
53
52
|
return user;
|
|
54
53
|
}
|
|
55
54
|
|
|
55
|
+
// If user is missing throw token exception
|
|
56
|
+
if (!user) {
|
|
57
|
+
if (err) {
|
|
58
|
+
throw new InvalidTokenException();
|
|
59
|
+
}
|
|
60
|
+
if (info?.name === 'TokenExpiredError') {
|
|
61
|
+
throw new ExpiredTokenException();
|
|
62
|
+
}
|
|
63
|
+
throw new UnauthorizedException('Unauthorized');
|
|
64
|
+
}
|
|
65
|
+
|
|
56
66
|
// Requester is not authorized
|
|
57
67
|
throw new UnauthorizedException('Missing role');
|
|
58
68
|
}
|
|
@@ -20,7 +20,7 @@ export abstract class CoreUserService<
|
|
|
20
20
|
TUser extends CoreUserModel,
|
|
21
21
|
TUserInput extends CoreUserInput,
|
|
22
22
|
TUserCreateInput extends CoreUserCreateInput
|
|
23
|
-
> extends CrudService<TUser> {
|
|
23
|
+
> extends CrudService<TUser, TUserCreateInput, TUserInput> {
|
|
24
24
|
protected constructor(
|
|
25
25
|
protected override readonly configService: ConfigService,
|
|
26
26
|
protected readonly emailService: EmailService,
|
|
@@ -54,7 +54,7 @@ export abstract class CoreUserService<
|
|
|
54
54
|
try {
|
|
55
55
|
await createdUser.save();
|
|
56
56
|
} catch (error) {
|
|
57
|
-
if (error
|
|
57
|
+
if (error?.errors?.email?.kind === 'unique') {
|
|
58
58
|
throw new BadRequestException('Email address already in use');
|
|
59
59
|
} else {
|
|
60
60
|
throw new UnprocessableEntityException();
|
package/src/index.ts
CHANGED
|
@@ -64,6 +64,7 @@ export * from './core/common/types/core-model-constructor.type';
|
|
|
64
64
|
export * from './core/common/types/falsy.type';
|
|
65
65
|
export * from './core/common/types/field-selection.type';
|
|
66
66
|
export * from './core/common/types/ids.type';
|
|
67
|
+
export * from './core/common/types/is-one-of.type';
|
|
67
68
|
export * from './core/common/types/maybe-promise.type';
|
|
68
69
|
export * from './core/common/types/plain-input.type';
|
|
69
70
|
export * from './core/common/types/plain-object.type';
|
|
@@ -4,6 +4,7 @@ import { EmailService } from '../../../core/common/services/email.service';
|
|
|
4
4
|
import { CoreAuthModule } from '../../../core/modules/auth/core-auth.module';
|
|
5
5
|
import { UserModule } from '../user/user.module';
|
|
6
6
|
import { UserService } from '../user/user.service';
|
|
7
|
+
import { AuthController } from './auth.controller';
|
|
7
8
|
import { AuthResolver } from './auth.resolver';
|
|
8
9
|
import { AuthService } from './auth.service';
|
|
9
10
|
|
|
@@ -28,8 +29,8 @@ export class AuthModule {
|
|
|
28
29
|
},
|
|
29
30
|
}),
|
|
30
31
|
],
|
|
31
|
-
providers: [AuthResolver, AuthService, EmailService],
|
|
32
|
-
exports: [AuthResolver, CoreAuthModule],
|
|
32
|
+
providers: [AuthController, AuthResolver, AuthService, EmailService],
|
|
33
|
+
exports: [AuthController, AuthResolver, CoreAuthModule],
|
|
33
34
|
};
|
|
34
35
|
}
|
|
35
36
|
}
|