@lenne.tech/nest-server 8.0.2 → 8.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/config.env.js +3 -2
- package/dist/config.env.js.map +1 -1
- package/dist/core/common/args/pagination.args.js +1 -1
- package/dist/core/common/args/pagination.args.js.map +1 -1
- package/dist/core/common/decorators/restricted.decorator.d.ts +3 -0
- package/dist/core/common/decorators/restricted.decorator.js +14 -8
- package/dist/core/common/decorators/restricted.decorator.js.map +1 -1
- package/dist/core/common/enums/role.enum.d.ts +3 -2
- package/dist/core/common/enums/role.enum.js +3 -2
- package/dist/core/common/enums/role.enum.js.map +1 -1
- package/dist/core/common/helpers/config.helper.d.ts +2 -1
- package/dist/core/common/helpers/config.helper.js +11 -7
- package/dist/core/common/helpers/config.helper.js.map +1 -1
- package/dist/core/common/helpers/context.helper.d.ts +7 -1
- package/dist/core/common/helpers/context.helper.js +33 -29
- package/dist/core/common/helpers/context.helper.js.map +1 -1
- package/dist/core/common/helpers/db.helper.d.ts +37 -0
- package/dist/core/common/helpers/db.helper.js +356 -0
- package/dist/core/common/helpers/db.helper.js.map +1 -0
- package/dist/core/common/helpers/file.helper.d.ts +8 -1
- package/dist/core/common/helpers/file.helper.js +43 -31
- package/dist/core/common/helpers/file.helper.js.map +1 -1
- package/dist/core/common/helpers/filter.helper.d.ts +3 -0
- package/dist/core/common/helpers/filter.helper.js +93 -81
- package/dist/core/common/helpers/filter.helper.js.map +1 -1
- package/dist/core/common/helpers/graphql.helper.d.ts +24 -1
- package/dist/core/common/helpers/graphql.helper.js +144 -96
- package/dist/core/common/helpers/graphql.helper.js.map +1 -1
- package/dist/core/common/helpers/input.helper.d.ts +42 -4
- package/dist/core/common/helpers/input.helper.js +256 -97
- package/dist/core/common/helpers/input.helper.js.map +1 -1
- package/dist/core/common/helpers/model.helper.d.ts +11 -0
- package/dist/core/common/helpers/model.helper.js +41 -29
- package/dist/core/common/helpers/model.helper.js.map +1 -1
- package/dist/core/common/helpers/service.helper.d.ts +21 -1
- package/dist/core/common/helpers/service.helper.js +80 -72
- package/dist/core/common/helpers/service.helper.js.map +1 -1
- package/dist/core/common/inputs/combined-filter.input.js +1 -1
- package/dist/core/common/inputs/combined-filter.input.js.map +1 -1
- package/dist/core/common/inputs/core-input.input.js +1 -1
- package/dist/core/common/inputs/core-input.input.js.map +1 -1
- package/dist/core/common/interceptors/check-response.interceptor.js +1 -1
- package/dist/core/common/interceptors/check-response.interceptor.js.map +1 -1
- package/dist/core/common/interfaces/resolve-selector.interface.d.ts +5 -0
- package/dist/core/common/interfaces/resolve-selector.interface.js +3 -0
- package/dist/core/common/interfaces/resolve-selector.interface.js.map +1 -0
- package/dist/core/common/interfaces/service-options.interface.d.ts +36 -0
- package/dist/core/common/interfaces/service-options.interface.js +3 -0
- package/dist/core/common/interfaces/service-options.interface.js.map +1 -0
- package/dist/core/common/models/core-model.model.d.ts +5 -1
- package/dist/core/common/models/core-model.model.js +1 -1
- package/dist/core/common/models/core-model.model.js.map +1 -1
- package/dist/core/common/pipes/check-input.pipe.js +2 -2
- package/dist/core/common/pipes/check-input.pipe.js.map +1 -1
- package/dist/core/common/pipes/map-and-validate.pipe.js +1 -1
- package/dist/core/common/pipes/map-and-validate.pipe.js.map +1 -1
- package/dist/core/common/services/crud.service.d.ts +13 -0
- package/dist/core/common/services/crud.service.js +57 -0
- package/dist/core/common/services/crud.service.js.map +1 -0
- package/dist/core/common/services/email.service.js +8 -8
- package/dist/core/common/services/email.service.js.map +1 -1
- package/dist/core/common/services/module.service.d.ts +40 -0
- package/dist/core/common/services/module.service.js +80 -0
- package/dist/core/common/services/module.service.js.map +1 -0
- package/dist/core/common/types/core-model-constructor.type.d.ts +21 -0
- package/dist/core/common/types/core-model-constructor.type.js +3 -0
- package/dist/core/common/types/core-model-constructor.type.js.map +1 -0
- package/dist/core/common/types/field-selection.type.d.ts +4 -0
- package/dist/core/common/types/field-selection.type.js +3 -0
- package/dist/core/common/types/field-selection.type.js.map +1 -0
- package/dist/core/common/types/ids.type.d.ts +8 -0
- package/dist/core/common/types/ids.type.js +3 -0
- package/dist/core/common/types/ids.type.js.map +1 -0
- package/dist/core/common/types/string-or-object-id.type.d.ts +2 -0
- package/dist/core/common/types/string-or-object-id.type.js +3 -0
- package/dist/core/common/types/string-or-object-id.type.js.map +1 -0
- package/dist/core/modules/auth/core-auth.resolver.d.ts +2 -1
- package/dist/core/modules/auth/core-auth.resolver.js +4 -3
- package/dist/core/modules/auth/core-auth.resolver.js.map +1 -1
- package/dist/core/modules/auth/guards/roles.guard.js +1 -2
- package/dist/core/modules/auth/guards/roles.guard.js.map +1 -1
- package/dist/core/modules/auth/services/core-auth-user.service.d.ts +3 -1
- package/dist/core/modules/auth/services/core-auth-user.service.js.map +1 -1
- package/dist/core/modules/auth/services/core-auth.service.d.ts +2 -1
- package/dist/core/modules/auth/services/core-auth.service.js +6 -4
- package/dist/core/modules/auth/services/core-auth.service.js.map +1 -1
- package/dist/core/modules/user/core-user.model.js +1 -1
- package/dist/core/modules/user/core-user.model.js.map +1 -1
- package/dist/core/modules/user/core-user.service.d.ts +16 -25
- package/dist/core/modules/user/core-user.service.js +69 -90
- package/dist/core/modules/user/core-user.service.js.map +1 -1
- package/dist/core.module.js +1 -1
- package/dist/core.module.js.map +1 -1
- package/dist/index.d.ts +9 -1
- package/dist/index.js +9 -1
- package/dist/index.js.map +1 -1
- package/dist/server/modules/auth/auth.resolver.d.ts +2 -1
- package/dist/server/modules/auth/auth.resolver.js +4 -3
- package/dist/server/modules/auth/auth.resolver.js.map +1 -1
- package/dist/server/modules/file/file.controller.js +1 -1
- package/dist/server/modules/file/file.controller.js.map +1 -1
- package/dist/server/modules/user/avatar.controller.js +2 -2
- package/dist/server/modules/user/avatar.controller.js.map +1 -1
- package/dist/server/modules/user/user.model.d.ts +2 -1
- package/dist/server/modules/user/user.module.js +7 -3
- package/dist/server/modules/user/user.module.js.map +1 -1
- package/dist/server/modules/user/user.resolver.d.ts +8 -7
- package/dist/server/modules/user/user.resolver.js +85 -49
- package/dist/server/modules/user/user.resolver.js.map +1 -1
- package/dist/server/modules/user/user.service.d.ts +9 -18
- package/dist/server/modules/user/user.service.js +23 -30
- package/dist/server/modules/user/user.service.js.map +1 -1
- package/dist/test/test.helper.d.ts +1 -2
- package/dist/test/test.helper.js +1 -16
- package/dist/test/test.helper.js.map +1 -1
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/package.json +58 -59
- package/src/config.env.ts +3 -2
- package/src/core/common/args/pagination.args.ts +2 -2
- package/src/core/common/decorators/restricted.decorator.ts +24 -12
- package/src/core/common/enums/role.enum.ts +23 -5
- package/src/core/common/helpers/config.helper.ts +26 -6
- package/src/core/common/helpers/context.helper.ts +42 -33
- package/src/core/common/helpers/db.helper.ts +595 -0
- package/src/core/common/helpers/file.helper.ts +76 -49
- package/src/core/common/helpers/filter.helper.ts +119 -96
- package/src/core/common/helpers/graphql.helper.ts +219 -117
- package/src/core/common/helpers/input.helper.ts +349 -108
- package/src/core/common/helpers/model.helper.ts +102 -57
- package/src/core/common/helpers/service.helper.ts +149 -117
- package/src/core/common/inputs/combined-filter.input.ts +2 -2
- package/src/core/common/inputs/core-input.input.ts +2 -2
- package/src/core/common/interceptors/check-response.interceptor.ts +2 -2
- package/src/core/common/interfaces/resolve-selector.interface.ts +9 -0
- package/src/core/common/interfaces/service-options.interface.ts +71 -0
- package/src/core/common/models/core-model.model.ts +7 -3
- package/src/core/common/pipes/check-input.pipe.ts +4 -4
- package/src/core/common/pipes/map-and-validate.pipe.ts +2 -2
- package/src/core/common/services/crud.service.ts +100 -0
- package/src/core/common/services/email.service.ts +9 -9
- package/src/core/common/services/module.service.ts +188 -0
- package/src/core/common/types/core-model-constructor.type.ts +30 -0
- package/src/core/common/types/field-selection.type.ts +8 -0
- package/src/core/common/types/ids.type.ts +7 -0
- package/src/core/common/types/string-or-object-id.type.ts +3 -0
- package/src/core/modules/auth/core-auth.module.ts +1 -1
- package/src/core/modules/auth/core-auth.resolver.ts +8 -3
- package/src/core/modules/auth/guards/roles.guard.ts +5 -7
- package/src/core/modules/auth/services/core-auth-user.service.ts +7 -1
- package/src/core/modules/auth/services/core-auth.service.ts +14 -4
- package/src/core/modules/user/core-user.model.ts +2 -1
- package/src/core/modules/user/core-user.service.ts +115 -185
- package/src/core.module.ts +2 -2
- package/src/index.ts +9 -1
- package/src/main.ts +1 -1
- package/src/server/modules/auth/auth.resolver.ts +8 -3
- package/src/server/modules/file/file.controller.ts +2 -2
- package/src/server/modules/user/avatar.controller.ts +3 -3
- package/src/server/modules/user/user.module.ts +7 -3
- package/src/server/modules/user/user.resolver.ts +74 -43
- package/src/server/modules/user/user.service.ts +30 -53
- package/src/test/test.helper.ts +31 -30
- package/dist/core/modules/user/core-basic-user.service.d.ts +0 -17
- package/dist/core/modules/user/core-basic-user.service.js +0 -73
- package/dist/core/modules/user/core-basic-user.service.js.map +0 -1
- package/src/core/modules/user/core-basic-user.service.ts +0 -138
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import { PipeTransform, Injectable, ArgumentMetadata, BadRequestException } from '@nestjs/common';
|
|
2
2
|
import { plainToInstance } from 'class-transformer';
|
|
3
3
|
import { validate } from 'class-validator';
|
|
4
|
-
import {
|
|
4
|
+
import { isBasicType } from '../helpers/input.helper';
|
|
5
5
|
|
|
6
6
|
@Injectable()
|
|
7
7
|
export class MapAndValidatePipe implements PipeTransform {
|
|
8
8
|
async transform(value: any, metadata: ArgumentMetadata) {
|
|
9
9
|
const { metatype } = metadata;
|
|
10
10
|
|
|
11
|
-
if (typeof value !== 'object' || !metatype ||
|
|
11
|
+
if (typeof value !== 'object' || !metatype || isBasicType(metatype)) {
|
|
12
12
|
return value;
|
|
13
13
|
}
|
|
14
14
|
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { NotFoundException } from '@nestjs/common';
|
|
2
|
+
import { FilterArgs } from '../args/filter.args';
|
|
3
|
+
import { merge } from '../helpers/config.helper';
|
|
4
|
+
import { convertFilterArgsToQuery } from '../helpers/filter.helper';
|
|
5
|
+
import { ServiceOptions } from '../interfaces/service-options.interface';
|
|
6
|
+
import { CoreModel } from '../models/core-model.model';
|
|
7
|
+
import { ModuleService } from './module.service';
|
|
8
|
+
|
|
9
|
+
export abstract class CrudService<T extends CoreModel = any> extends ModuleService<T> {
|
|
10
|
+
/**
|
|
11
|
+
* Create item
|
|
12
|
+
*/
|
|
13
|
+
async create(input: any, serviceOptions?: ServiceOptions): Promise<T> {
|
|
14
|
+
merge({ prepareInput: { create: true } }, serviceOptions);
|
|
15
|
+
return this.process(
|
|
16
|
+
async (data) => {
|
|
17
|
+
return new this.mainDbModel({ ...data.input }).save();
|
|
18
|
+
},
|
|
19
|
+
{ input, serviceOptions }
|
|
20
|
+
);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Get item by ID
|
|
25
|
+
*/
|
|
26
|
+
async get(id: string, serviceOptions?: ServiceOptions): Promise<T> {
|
|
27
|
+
const dbObject = await this.mainDbModel.findById(id).exec();
|
|
28
|
+
if (!dbObject) {
|
|
29
|
+
throw new NotFoundException(`No ${this.mainModelConstructor.name} found with ID: ${id}`);
|
|
30
|
+
}
|
|
31
|
+
return this.process(async () => dbObject, { dbObject, serviceOptions });
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Get items via filter
|
|
36
|
+
*/
|
|
37
|
+
async find(filterArgs?: FilterArgs, serviceOptions?: ServiceOptions): Promise<T[]> {
|
|
38
|
+
return this.process(
|
|
39
|
+
async (data) => {
|
|
40
|
+
const filterQuery = convertFilterArgsToQuery(data.input);
|
|
41
|
+
return this.mainDbModel.find(filterQuery[0], null, filterQuery[1]).exec();
|
|
42
|
+
},
|
|
43
|
+
{ input: filterArgs, serviceOptions }
|
|
44
|
+
);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* CRUD alias for get
|
|
49
|
+
*/
|
|
50
|
+
async read(id: string, serviceOptions?: ServiceOptions): Promise<T>;
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* CRUD alias for find
|
|
54
|
+
*/
|
|
55
|
+
async read(filterArgs?: FilterArgs, serviceOptions?: ServiceOptions): Promise<T[]>;
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* CRUD alias for get or find
|
|
59
|
+
*/
|
|
60
|
+
async read(input: string | FilterArgs, serviceOptions?: ServiceOptions): Promise<T | T[]> {
|
|
61
|
+
if (typeof input === 'string') {
|
|
62
|
+
return this.get(input, serviceOptions);
|
|
63
|
+
} else {
|
|
64
|
+
return this.find(input, serviceOptions);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Update item via ID
|
|
70
|
+
*/
|
|
71
|
+
async update(id: string, input: any, serviceOptions?: ServiceOptions): Promise<T> {
|
|
72
|
+
const dbObject = await this.mainDbModel.findById(id).exec();
|
|
73
|
+
if (!dbObject) {
|
|
74
|
+
throw new NotFoundException(`No ${this.mainModelConstructor.name} found with ID: ${id}`);
|
|
75
|
+
}
|
|
76
|
+
return this.process(
|
|
77
|
+
async (data) => {
|
|
78
|
+
return await Object.assign(dbObject, data.input).save();
|
|
79
|
+
},
|
|
80
|
+
{ dbObject, input, serviceOptions }
|
|
81
|
+
);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Delete item via ID
|
|
86
|
+
*/
|
|
87
|
+
async delete(id: string, serviceOptions?: ServiceOptions): Promise<T> {
|
|
88
|
+
const dbObject = await this.mainDbModel.findById(id).exec();
|
|
89
|
+
if (!dbObject) {
|
|
90
|
+
throw new NotFoundException(`No ${this.mainModelConstructor.name} found with ID: ${id}`);
|
|
91
|
+
}
|
|
92
|
+
return this.process(
|
|
93
|
+
async (data) => {
|
|
94
|
+
await this.mainDbModel.findByIdAndDelete(id).exec();
|
|
95
|
+
return dbObject;
|
|
96
|
+
},
|
|
97
|
+
{ dbObject, input: id, serviceOptions }
|
|
98
|
+
);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Injectable } from '@nestjs/common';
|
|
2
2
|
import * as nodemailer from 'nodemailer';
|
|
3
3
|
import { Attachment } from 'nodemailer/lib/mailer';
|
|
4
|
-
import {
|
|
4
|
+
import { isNonEmptyString, isTrue, returnFalse } from '../helpers/input.helper';
|
|
5
5
|
import { ConfigService } from './config.service';
|
|
6
6
|
import { TemplateService } from './template.service';
|
|
7
7
|
|
|
@@ -43,10 +43,10 @@ export class EmailService {
|
|
|
43
43
|
let text = config.text;
|
|
44
44
|
|
|
45
45
|
// Check parameter
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
46
|
+
isTrue(recipients);
|
|
47
|
+
isNonEmptyString(subject);
|
|
48
|
+
isNonEmptyString(senderName);
|
|
49
|
+
isNonEmptyString(senderEmail);
|
|
50
50
|
|
|
51
51
|
// Process text template
|
|
52
52
|
if (htmlTemplate) {
|
|
@@ -59,11 +59,11 @@ export class EmailService {
|
|
|
59
59
|
}
|
|
60
60
|
|
|
61
61
|
// Check if at lest one of text or html is set
|
|
62
|
-
if (!
|
|
63
|
-
|
|
62
|
+
if (!isNonEmptyString(html, returnFalse)) {
|
|
63
|
+
isNonEmptyString(text);
|
|
64
64
|
}
|
|
65
|
-
if (!
|
|
66
|
-
|
|
65
|
+
if (!isNonEmptyString(text, returnFalse)) {
|
|
66
|
+
isNonEmptyString(html);
|
|
67
67
|
}
|
|
68
68
|
|
|
69
69
|
// Init transporter
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
import { Document, Model, Types } from 'mongoose';
|
|
2
|
+
import { getStringIds, popAndMap } from '../helpers/db.helper';
|
|
3
|
+
import { check } from '../helpers/input.helper';
|
|
4
|
+
import { prepareInput, prepareOutput } from '../helpers/service.helper';
|
|
5
|
+
import { ServiceOptions } from '../interfaces/service-options.interface';
|
|
6
|
+
import { CoreModel } from '../models/core-model.model';
|
|
7
|
+
import { FieldSelection } from '../types/field-selection.type';
|
|
8
|
+
import { IdsType } from '../types/ids.type';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Module service class to be extended by concrete module services
|
|
12
|
+
*/
|
|
13
|
+
export abstract class ModuleService<T extends CoreModel = any> {
|
|
14
|
+
/**
|
|
15
|
+
* Main model constructor of the service, will be used as default for populate and mapping
|
|
16
|
+
*/
|
|
17
|
+
protected mainModelConstructor: new (...args: any[]) => T;
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Main DB model of the service, will be used as default for populate and mapping
|
|
21
|
+
*/
|
|
22
|
+
protected mainDbModel: Model<T & Document>;
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Set main properties
|
|
26
|
+
*/
|
|
27
|
+
protected constructor(options?: {
|
|
28
|
+
mainDbModel: Model<T & Document>;
|
|
29
|
+
mainModelConstructor?: new (...args: any[]) => T;
|
|
30
|
+
}) {
|
|
31
|
+
this.mainDbModel = options?.mainDbModel;
|
|
32
|
+
this.mainModelConstructor = options?.mainModelConstructor;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Check rights of current user for input
|
|
37
|
+
*/
|
|
38
|
+
checkRights(
|
|
39
|
+
input: any,
|
|
40
|
+
currentUser: { id: any; hasRole: (roles: string[]) => boolean },
|
|
41
|
+
options?: {
|
|
42
|
+
creator?: IdsType;
|
|
43
|
+
metatype?: any;
|
|
44
|
+
ownerIds?: IdsType;
|
|
45
|
+
roles?: string | string[];
|
|
46
|
+
throwError?: boolean;
|
|
47
|
+
}
|
|
48
|
+
): Promise<any> {
|
|
49
|
+
const config = {
|
|
50
|
+
metatype: this.mainModelConstructor,
|
|
51
|
+
...options,
|
|
52
|
+
};
|
|
53
|
+
return check(input, currentUser, config);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Get function to get Object via ID, necessary for checkInput
|
|
58
|
+
*/
|
|
59
|
+
abstract get(id: any, ...args: any[]): any;
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Run service function with pre- and post-functions
|
|
63
|
+
*/
|
|
64
|
+
async process(
|
|
65
|
+
serviceFunc: (options?: { [key: string]: any; input?: any; serviceOptions?: ServiceOptions }) => any,
|
|
66
|
+
options?: {
|
|
67
|
+
[key: string]: any;
|
|
68
|
+
dbObject?: string | Types.ObjectId | any;
|
|
69
|
+
input?: any;
|
|
70
|
+
serviceOptions?: ServiceOptions;
|
|
71
|
+
}
|
|
72
|
+
) {
|
|
73
|
+
// Configuration with default values
|
|
74
|
+
const config = {
|
|
75
|
+
checkRights: true,
|
|
76
|
+
dbObject: options?.dbObject,
|
|
77
|
+
input: options?.input,
|
|
78
|
+
processFieldSelection: {},
|
|
79
|
+
prepareInput: {},
|
|
80
|
+
prepareOutput: {},
|
|
81
|
+
pubSub: true,
|
|
82
|
+
...options?.serviceOptions,
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
// Prepare input
|
|
86
|
+
if (config.prepareInput && this.prepareInput) {
|
|
87
|
+
await this.prepareInput(config.input, config.prepareInput);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// Get DB object
|
|
91
|
+
const getDbObject = async () => {
|
|
92
|
+
if (config.dbObject) {
|
|
93
|
+
if (typeof config.dbObject === 'string' || config.dbObject instanceof Types.ObjectId) {
|
|
94
|
+
const dbObject = await this.get(getStringIds(config.dbObject));
|
|
95
|
+
if (dbObject) {
|
|
96
|
+
config.dbObject = dbObject;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
return config.dbObject;
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
// Get owner IDs
|
|
104
|
+
let ownerIds = undefined;
|
|
105
|
+
if (config.checkRights && this.checkRights) {
|
|
106
|
+
ownerIds = getStringIds(config.ownerIds);
|
|
107
|
+
if (!ownerIds?.length) {
|
|
108
|
+
ownerIds = (await getDbObject())?.ownerIds;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// Check rights for input
|
|
113
|
+
if (config.input && config.checkRights && this.checkRights) {
|
|
114
|
+
const opts: any = { creator: (await getDbObject())?.createdBy, ownerIds, roles: config.roles };
|
|
115
|
+
if (config.inputType) {
|
|
116
|
+
opts.metatype = config.resultType;
|
|
117
|
+
}
|
|
118
|
+
config.input = await this.checkRights(config.input, config.currentUser as any, opts);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// Run service function
|
|
122
|
+
let result = await serviceFunc(config);
|
|
123
|
+
|
|
124
|
+
// Pop and map main model
|
|
125
|
+
if (config.processFieldSelection && config.fieldSelection && this.processFieldSelection) {
|
|
126
|
+
await this.processFieldSelection(result, config.fieldSelection, config.processFieldSelection);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// Prepare output
|
|
130
|
+
if (config.prepareOutput && this.prepareOutput) {
|
|
131
|
+
// Check if mapping is already done by processFieldSelection
|
|
132
|
+
if (config.processFieldSelection && config.fieldSelection && this.processFieldSelection) {
|
|
133
|
+
config.prepareOutput.targetModel = null;
|
|
134
|
+
}
|
|
135
|
+
result = await this.prepareOutput(result, config.prepareOutput);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// Check output rights
|
|
139
|
+
if (config.checkRights && this.checkRights) {
|
|
140
|
+
const opts: any = { creator: (await getDbObject())?.createdBy, ownerIds, roles: config.roles, throwError: false };
|
|
141
|
+
if (config.resultType) {
|
|
142
|
+
opts.metatype = config.resultType;
|
|
143
|
+
}
|
|
144
|
+
result = await this.checkRights(result, config.currentUser as any, opts);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// Return (prepared) result
|
|
148
|
+
return result;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Prepare input before save
|
|
153
|
+
*/
|
|
154
|
+
async prepareInput(input: Record<string, any>, options: ServiceOptions = {}) {
|
|
155
|
+
return prepareInput(input, options.currentUser, options.prepareInput);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Prepare output before return
|
|
160
|
+
*/
|
|
161
|
+
async prepareOutput(output: any, options: ServiceOptions = {}) {
|
|
162
|
+
const config = {
|
|
163
|
+
targetModel: this.mainModelConstructor,
|
|
164
|
+
...options?.prepareOutput,
|
|
165
|
+
};
|
|
166
|
+
return prepareOutput(output, config);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* Process fieldSelection
|
|
171
|
+
* @protected
|
|
172
|
+
*/
|
|
173
|
+
async processFieldSelection(
|
|
174
|
+
data: any,
|
|
175
|
+
fieldsSelection: FieldSelection,
|
|
176
|
+
options: {
|
|
177
|
+
model?: new (...args: any[]) => T;
|
|
178
|
+
dbModel?: Model<T & Document>;
|
|
179
|
+
} = {}
|
|
180
|
+
) {
|
|
181
|
+
const config = {
|
|
182
|
+
model: this.mainModelConstructor,
|
|
183
|
+
dbModel: this.mainDbModel,
|
|
184
|
+
...options,
|
|
185
|
+
};
|
|
186
|
+
return popAndMap(data, fieldsSelection, config.model, config.dbModel);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { CoreModel } from '../models/core-model.model';
|
|
2
|
+
|
|
3
|
+
export type CoreModelConstructor<T extends CoreModel> = {
|
|
4
|
+
new (): T;
|
|
5
|
+
init(this: new (...args: any[]) => T, ...args: any[]): T;
|
|
6
|
+
map(
|
|
7
|
+
this: new (...args: any[]) => T,
|
|
8
|
+
data: Partial<T> | Record<string, any>,
|
|
9
|
+
options?: {
|
|
10
|
+
[key: string]: any;
|
|
11
|
+
cloneDeep?: boolean;
|
|
12
|
+
funcAllowed?: boolean;
|
|
13
|
+
init?: any;
|
|
14
|
+
item?: T;
|
|
15
|
+
mapId?: boolean;
|
|
16
|
+
}
|
|
17
|
+
): T;
|
|
18
|
+
mapDeep(
|
|
19
|
+
this: new (...args: any[]) => T,
|
|
20
|
+
data: Partial<T> | Record<string, any>,
|
|
21
|
+
options: {
|
|
22
|
+
[key: string]: any;
|
|
23
|
+
cloneDeep?: boolean;
|
|
24
|
+
funcAllowed?: boolean;
|
|
25
|
+
init?: any;
|
|
26
|
+
item?: T;
|
|
27
|
+
mapId?: boolean;
|
|
28
|
+
}
|
|
29
|
+
): T;
|
|
30
|
+
};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { SelectionNode } from 'graphql';
|
|
2
|
+
import { PopulateOptions } from 'mongoose';
|
|
3
|
+
import { ResolveSelector } from '../interfaces/resolve-selector.interface';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Field selection to set fields of (populated) result
|
|
7
|
+
*/
|
|
8
|
+
export type FieldSelection = PopulateOptions[] | SelectionNode[] | ResolveSelector;
|
|
@@ -25,7 +25,7 @@ export class CoreAuthModule {
|
|
|
25
25
|
providers?: Provider[];
|
|
26
26
|
}
|
|
27
27
|
): DynamicModule {
|
|
28
|
-
//
|
|
28
|
+
// Process imports
|
|
29
29
|
let imports: any[] = [UserModule, PassportModule.register({ defaultStrategy: 'jwt' }), JwtModule.register(options)];
|
|
30
30
|
if (Array.isArray(options?.imports)) {
|
|
31
31
|
imports = imports.concat(options.imports);
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { Args, Query, Resolver } from '@nestjs/graphql';
|
|
1
|
+
import { Args, Info, Query, Resolver } from '@nestjs/graphql';
|
|
2
|
+
import { GraphQLResolveInfo } from 'graphql';
|
|
2
3
|
import { CoreAuthModel } from './core-auth.model';
|
|
3
4
|
import { CoreAuthService } from './services/core-auth.service';
|
|
4
5
|
|
|
@@ -20,7 +21,11 @@ export class CoreAuthResolver {
|
|
|
20
21
|
* Get user via ID
|
|
21
22
|
*/
|
|
22
23
|
@Query((returns) => CoreAuthModel, { description: 'Get JWT token' })
|
|
23
|
-
async signIn(
|
|
24
|
-
|
|
24
|
+
async signIn(
|
|
25
|
+
@Args('email') email: string,
|
|
26
|
+
@Args('password') password: string,
|
|
27
|
+
@Info() info: GraphQLResolveInfo
|
|
28
|
+
): Promise<Partial<CoreAuthModel>> {
|
|
29
|
+
return await this.authService.signIn(email, password, { fieldSelection: { info, select: 'signIn' } });
|
|
25
30
|
}
|
|
26
31
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ExecutionContext, Injectable, UnauthorizedException } from '@nestjs/common';
|
|
1
|
+
import { ExecutionContext, Inject, Injectable, UnauthorizedException } from '@nestjs/common';
|
|
2
2
|
import { Reflector } from '@nestjs/core';
|
|
3
3
|
import { GqlExecutionContext } from '@nestjs/graphql';
|
|
4
4
|
import { RoleEnum } from '../../../common/enums/role.enum';
|
|
@@ -8,7 +8,8 @@ import { AuthGuard } from './auth.guard';
|
|
|
8
8
|
* Role guard
|
|
9
9
|
*
|
|
10
10
|
* The RoleGuard is activated by the Role decorator. It checks whether the current user has at least one of the
|
|
11
|
-
* specified roles
|
|
11
|
+
* specified roles or is logged in when the S_USER role is set.
|
|
12
|
+
* If this is not the case, an UnauthorizedException is thrown.
|
|
12
13
|
*/
|
|
13
14
|
@Injectable()
|
|
14
15
|
export class RolesGuard extends AuthGuard('jwt') {
|
|
@@ -41,11 +42,8 @@ export class RolesGuard extends AuthGuard('jwt') {
|
|
|
41
42
|
// Get args
|
|
42
43
|
const args: any = GqlExecutionContext.create(context).getArgs();
|
|
43
44
|
|
|
44
|
-
// Check special role
|
|
45
|
-
if (
|
|
46
|
-
user &&
|
|
47
|
-
(roles.includes(RoleEnum.USER) || (roles.includes(RoleEnum.OWNER) && user.id.toString() === args.id))
|
|
48
|
-
) {
|
|
45
|
+
// Check special user role (user is logged in)
|
|
46
|
+
if (user && roles.includes(RoleEnum.S_USER)) {
|
|
49
47
|
return user;
|
|
50
48
|
}
|
|
51
49
|
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { ServiceOptions } from '../../../common/interfaces/service-options.interface';
|
|
1
2
|
import { ICoreAuthUser } from '../interfaces/core-auth-user.interface';
|
|
2
3
|
|
|
3
4
|
/**
|
|
@@ -7,5 +8,10 @@ export abstract class CoreAuthUserService {
|
|
|
7
8
|
/**
|
|
8
9
|
* Get user via email
|
|
9
10
|
*/
|
|
10
|
-
abstract getViaEmail(email: string): Promise<ICoreAuthUser>;
|
|
11
|
+
abstract getViaEmail(email: string, serviceOptions?: ServiceOptions): Promise<ICoreAuthUser>;
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Prepare output
|
|
15
|
+
*/
|
|
16
|
+
abstract prepareOutput(output: any, options?: ServiceOptions): Promise<ICoreAuthUser>;
|
|
11
17
|
}
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { Injectable, UnauthorizedException } from '@nestjs/common';
|
|
2
2
|
import { JwtService } from '@nestjs/jwt';
|
|
3
3
|
import * as bcrypt from 'bcrypt';
|
|
4
|
+
import { merge } from '../../../common/helpers/config.helper';
|
|
5
|
+
import { ServiceOptions } from '../../../common/interfaces/service-options.interface';
|
|
4
6
|
import { ICoreAuthUser } from '../interfaces/core-auth-user.interface';
|
|
5
7
|
import { JwtPayload } from '../interfaces/jwt-payload.interface';
|
|
6
8
|
import { CoreAuthUserService } from './core-auth-user.service';
|
|
@@ -15,15 +17,20 @@ export class CoreAuthService {
|
|
|
15
17
|
/**
|
|
16
18
|
* User sign in via email
|
|
17
19
|
*/
|
|
18
|
-
async signIn(
|
|
19
|
-
|
|
20
|
-
|
|
20
|
+
async signIn(
|
|
21
|
+
email: string,
|
|
22
|
+
password: string,
|
|
23
|
+
serviceOptions?: ServiceOptions
|
|
24
|
+
): Promise<{ token: string; user: ICoreAuthUser }> {
|
|
25
|
+
serviceOptions = merge(serviceOptions || {}, { prepareOutput: null });
|
|
26
|
+
const user = await this.userService.getViaEmail(email, serviceOptions);
|
|
27
|
+
if (!user || !(await bcrypt.compare(password, user.password))) {
|
|
21
28
|
throw new UnauthorizedException();
|
|
22
29
|
}
|
|
23
30
|
const payload: JwtPayload = { email: user.email };
|
|
24
31
|
return {
|
|
25
32
|
token: this.jwtService.sign(payload),
|
|
26
|
-
user,
|
|
33
|
+
user: await this.userService.prepareOutput(user),
|
|
27
34
|
};
|
|
28
35
|
}
|
|
29
36
|
|
|
@@ -34,6 +41,9 @@ export class CoreAuthService {
|
|
|
34
41
|
return await this.userService.getViaEmail(payload.email);
|
|
35
42
|
}
|
|
36
43
|
|
|
44
|
+
/**
|
|
45
|
+
* Decode JWT
|
|
46
|
+
*/
|
|
37
47
|
decodeJwt(token: string): JwtPayload {
|
|
38
48
|
return this.jwtService.decode(token) as JwtPayload;
|
|
39
49
|
}
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { Field, ObjectType } from '@nestjs/graphql';
|
|
2
|
+
import { Prop, Schema as MongooseSchema } from '@nestjs/mongoose';
|
|
2
3
|
import { IsEmail, IsOptional } from 'class-validator';
|
|
3
4
|
import { Document } from 'mongoose';
|
|
5
|
+
import { User } from '../../../server/modules/user/user.model';
|
|
4
6
|
import { CorePersistenceModel } from '../../common/models/core-persistence.model';
|
|
5
|
-
import { Prop, Schema as MongooseSchema } from '@nestjs/mongoose';
|
|
6
7
|
|
|
7
8
|
export type CoreUserModelDocument = CoreUserModel & Document;
|
|
8
9
|
|