@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
|
@@ -2,6 +2,7 @@ import * as _ from 'lodash';
|
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Helper class for models
|
|
5
|
+
* @deprecated use functions directly
|
|
5
6
|
*/
|
|
6
7
|
export class ModelHelper {
|
|
7
8
|
/**
|
|
@@ -19,31 +20,7 @@ export class ModelHelper {
|
|
|
19
20
|
mapId?: boolean;
|
|
20
21
|
} = {}
|
|
21
22
|
): Partial<T> | Record<string, any> {
|
|
22
|
-
|
|
23
|
-
const config = {
|
|
24
|
-
cloneDeep: true,
|
|
25
|
-
funcAllowed: false,
|
|
26
|
-
mapId: false,
|
|
27
|
-
...options,
|
|
28
|
-
};
|
|
29
|
-
|
|
30
|
-
// Initializations
|
|
31
|
-
const result = {};
|
|
32
|
-
|
|
33
|
-
// Update properties
|
|
34
|
-
for (const key of Object.keys(target)) {
|
|
35
|
-
if (
|
|
36
|
-
(!['id', '_id'].includes(key) || config.mapId) &&
|
|
37
|
-
source[key] !== undefined &&
|
|
38
|
-
(config.funcAllowed || typeof (source[key] !== 'function'))
|
|
39
|
-
) {
|
|
40
|
-
result[key] = source[key] !== 'function' && config.cloneDeep ? _.cloneDeep(source[key]) : source[key];
|
|
41
|
-
} else if (key === 'id' && !config.mapId) {
|
|
42
|
-
result['id'] = source[key];
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
return result;
|
|
23
|
+
return prepareMap(source, target, options);
|
|
47
24
|
}
|
|
48
25
|
|
|
49
26
|
/**
|
|
@@ -58,27 +35,7 @@ export class ModelHelper {
|
|
|
58
35
|
mapId?: boolean;
|
|
59
36
|
} = {}
|
|
60
37
|
): T {
|
|
61
|
-
|
|
62
|
-
const config = {
|
|
63
|
-
cloneDeep: true,
|
|
64
|
-
funcAllowed: false,
|
|
65
|
-
mapId: false,
|
|
66
|
-
...options,
|
|
67
|
-
};
|
|
68
|
-
|
|
69
|
-
// Check source
|
|
70
|
-
if (!source || typeof source !== 'object' || Array.isArray(source)) {
|
|
71
|
-
return config.cloneDeep ? _.cloneDeep(target) : target;
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
// Prepare source
|
|
75
|
-
const preparedSource = ModelHelper.prepareMap(source, target, config);
|
|
76
|
-
|
|
77
|
-
// Merge target with prepared source
|
|
78
|
-
Object.assign(target, preparedSource);
|
|
79
|
-
|
|
80
|
-
// Return target
|
|
81
|
-
return target;
|
|
38
|
+
return map(source, target, options);
|
|
82
39
|
}
|
|
83
40
|
|
|
84
41
|
/**
|
|
@@ -89,19 +46,107 @@ export class ModelHelper {
|
|
|
89
46
|
targetClass: new (...args: any[]) => T,
|
|
90
47
|
cloneDeep = true
|
|
91
48
|
): T[] {
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
49
|
+
return maps(data, targetClass, cloneDeep);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Remove all properties from source which are not in target
|
|
55
|
+
* @param source
|
|
56
|
+
* @param target
|
|
57
|
+
* @param options
|
|
58
|
+
*/
|
|
59
|
+
export function prepareMap<T = Record<string, any>>(
|
|
60
|
+
source: Partial<T> | Record<string, any>,
|
|
61
|
+
target: T,
|
|
62
|
+
options: {
|
|
63
|
+
cloneDeep?: boolean;
|
|
64
|
+
funcAllowed?: boolean;
|
|
65
|
+
mapId?: boolean;
|
|
66
|
+
} = {}
|
|
67
|
+
): Partial<T> | Record<string, any> {
|
|
68
|
+
// Set config
|
|
69
|
+
const config = {
|
|
70
|
+
cloneDeep: true,
|
|
71
|
+
funcAllowed: false,
|
|
72
|
+
mapId: false,
|
|
73
|
+
...options,
|
|
74
|
+
};
|
|
96
75
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
76
|
+
// Initializations
|
|
77
|
+
const result = {};
|
|
78
|
+
|
|
79
|
+
// Update properties
|
|
80
|
+
for (const key of Object.keys(target)) {
|
|
81
|
+
if (
|
|
82
|
+
(!['id', '_id'].includes(key) || config.mapId) &&
|
|
83
|
+
source[key] !== undefined &&
|
|
84
|
+
(config.funcAllowed || typeof (source[key] !== 'function'))
|
|
85
|
+
) {
|
|
86
|
+
result[key] = source[key] !== 'function' && config.cloneDeep ? _.cloneDeep(source[key]) : source[key];
|
|
87
|
+
} else if (key === 'id' && !config.mapId) {
|
|
88
|
+
result['id'] = source[key];
|
|
100
89
|
}
|
|
90
|
+
}
|
|
101
91
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
92
|
+
return result;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Simple map function
|
|
97
|
+
*/
|
|
98
|
+
export function map<T = Record<string, any>>(
|
|
99
|
+
source: Partial<T> | Record<string, any>,
|
|
100
|
+
target: T,
|
|
101
|
+
options: {
|
|
102
|
+
cloneDeep?: boolean;
|
|
103
|
+
funcAllowed?: boolean;
|
|
104
|
+
mapId?: boolean;
|
|
105
|
+
} = {}
|
|
106
|
+
): T {
|
|
107
|
+
// Set config
|
|
108
|
+
const config = {
|
|
109
|
+
cloneDeep: true,
|
|
110
|
+
funcAllowed: false,
|
|
111
|
+
mapId: false,
|
|
112
|
+
...options,
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
// Check source
|
|
116
|
+
if (!source || typeof source !== 'object' || Array.isArray(source)) {
|
|
117
|
+
return config.cloneDeep ? _.cloneDeep(target) : target;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// Prepare source
|
|
121
|
+
const preparedSource = prepareMap(source, target, config);
|
|
122
|
+
|
|
123
|
+
// Merge target with prepared source
|
|
124
|
+
Object.assign(target, preparedSource);
|
|
125
|
+
|
|
126
|
+
// Return target
|
|
127
|
+
return target;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Create Object or Objects of specified type with specified data
|
|
132
|
+
*/
|
|
133
|
+
export function maps<T = Record<string, any>>(
|
|
134
|
+
data: Partial<T> | Partial<T>[] | Record<string, any> | Record<string, any>[],
|
|
135
|
+
targetClass: new (...args: any[]) => T,
|
|
136
|
+
cloneDeep = true
|
|
137
|
+
): T[] {
|
|
138
|
+
// Check data
|
|
139
|
+
if (!data || typeof data !== 'object') {
|
|
140
|
+
return undefined;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// Check array
|
|
144
|
+
if (!Array.isArray(data)) {
|
|
145
|
+
data = [data];
|
|
106
146
|
}
|
|
147
|
+
|
|
148
|
+
// Map
|
|
149
|
+
return (data as any[]).map((item) => {
|
|
150
|
+
return (targetClass as any).map(item, { cloneDeep });
|
|
151
|
+
});
|
|
107
152
|
}
|
|
@@ -5,8 +5,9 @@ import { RoleEnum } from '../enums/role.enum';
|
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* Helper class for services
|
|
8
|
+
* @deprecated use functions directly
|
|
8
9
|
*/
|
|
9
|
-
export class ServiceHelper {
|
|
10
|
+
export default class ServiceHelper {
|
|
10
11
|
/**
|
|
11
12
|
* Prepare input before save
|
|
12
13
|
*/
|
|
@@ -21,78 +22,7 @@ export class ServiceHelper {
|
|
|
21
22
|
removeUndefined?: boolean;
|
|
22
23
|
} = {}
|
|
23
24
|
): Promise<T> {
|
|
24
|
-
|
|
25
|
-
const config = {
|
|
26
|
-
checkRoles: false,
|
|
27
|
-
clone: false,
|
|
28
|
-
create: false,
|
|
29
|
-
getNewArray: false,
|
|
30
|
-
removeUndefined: false,
|
|
31
|
-
...options,
|
|
32
|
-
};
|
|
33
|
-
|
|
34
|
-
// Check input
|
|
35
|
-
if (typeof input !== 'object') {
|
|
36
|
-
return input;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
// Process array
|
|
40
|
-
if (Array.isArray(input)) {
|
|
41
|
-
const processedArray = input.map(
|
|
42
|
-
async (item) => await ServiceHelper.prepareInput(item, currentUser, options)
|
|
43
|
-
) as any;
|
|
44
|
-
return config.getNewArray ? processedArray : input;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
// Clone input
|
|
48
|
-
if (config.clone) {
|
|
49
|
-
if ((input as Record<string, any>).mapDeep && typeof (input as any).mapDeep === 'function') {
|
|
50
|
-
input = await Object.getPrototypeOf(input).mapDeep(input);
|
|
51
|
-
} else {
|
|
52
|
-
input = _.cloneDeep(input);
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
// Remove undefined properties to avoid unwanted overwrites
|
|
57
|
-
if (config.removeUndefined) {
|
|
58
|
-
Object.keys(input).forEach((key) => input[key] === undefined && delete input[key]);
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
// Process roles
|
|
62
|
-
if (
|
|
63
|
-
config.checkRoles &&
|
|
64
|
-
(input as Record<string, any>).roles &&
|
|
65
|
-
(!currentUser?.hasRole || !currentUser.hasRole(RoleEnum.ADMIN))
|
|
66
|
-
) {
|
|
67
|
-
if (!(currentUser as any)?.roles) {
|
|
68
|
-
throw new UnauthorizedException('Missing roles of current user');
|
|
69
|
-
} else {
|
|
70
|
-
const allowedRoles = _.intersection((input as Record<string, any>).roles, (currentUser as any).roles);
|
|
71
|
-
if (allowedRoles.length !== (input as Record<string, any>).roles.length) {
|
|
72
|
-
const missingRoles = _.difference((input as Record<string, any>).roles, (currentUser as any).roles);
|
|
73
|
-
throw new UnauthorizedException('Current user not allowed setting roles: ' + missingRoles);
|
|
74
|
-
}
|
|
75
|
-
(input as Record<string, any>).roles = allowedRoles;
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
// Hash password
|
|
80
|
-
if ((input as Record<string, any>).password) {
|
|
81
|
-
(input as Record<string, any>).password = await bcrypt.hash((input as any).password, 10);
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
// Set creator
|
|
85
|
-
if (config.create && currentUser) {
|
|
86
|
-
(input as Record<string, any>).createdBy = currentUser.id;
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
// Set updater
|
|
90
|
-
if (currentUser) {
|
|
91
|
-
(input as Record<string, any>).updatedBy = currentUser.id;
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
// Return prepared input
|
|
95
|
-
return input;
|
|
25
|
+
return prepareInput(input, currentUser, options);
|
|
96
26
|
}
|
|
97
27
|
|
|
98
28
|
/**
|
|
@@ -108,61 +38,163 @@ export class ServiceHelper {
|
|
|
108
38
|
targetModel?: new (...args: any[]) => T;
|
|
109
39
|
} = {}
|
|
110
40
|
): Promise<T | T[] | any> {
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
getNewArray: false,
|
|
115
|
-
removeUndefined: false,
|
|
116
|
-
targetModel: undefined,
|
|
117
|
-
...options,
|
|
118
|
-
};
|
|
119
|
-
|
|
120
|
-
// Check output
|
|
121
|
-
if (typeof output !== 'object') {
|
|
122
|
-
return output;
|
|
123
|
-
}
|
|
41
|
+
return prepareOutput(output, options);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
124
44
|
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
45
|
+
/**
|
|
46
|
+
* Prepare input before save
|
|
47
|
+
*/
|
|
48
|
+
export async function prepareInput<T = any>(
|
|
49
|
+
input: T,
|
|
50
|
+
currentUser: { [key: string]: any; id: string },
|
|
51
|
+
options: {
|
|
52
|
+
[key: string]: any;
|
|
53
|
+
create?: boolean;
|
|
54
|
+
clone?: boolean;
|
|
55
|
+
getNewArray?: boolean;
|
|
56
|
+
removeUndefined?: boolean;
|
|
57
|
+
} = {}
|
|
58
|
+
): Promise<T> {
|
|
59
|
+
// Configuration
|
|
60
|
+
const config = {
|
|
61
|
+
checkRoles: false,
|
|
62
|
+
clone: false,
|
|
63
|
+
create: false,
|
|
64
|
+
getNewArray: false,
|
|
65
|
+
removeUndefined: false,
|
|
66
|
+
...options,
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
// Check input
|
|
70
|
+
if (typeof input !== 'object') {
|
|
71
|
+
return input;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// Process array
|
|
75
|
+
if (Array.isArray(input)) {
|
|
76
|
+
const processedArray = input.map(async (item) => await prepareInput(item, currentUser, options)) as any;
|
|
77
|
+
return config.getNewArray ? processedArray : input;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// Clone input
|
|
81
|
+
if (config.clone) {
|
|
82
|
+
if ((input as Record<string, any>).mapDeep && typeof (input as any).mapDeep === 'function') {
|
|
83
|
+
input = await Object.getPrototypeOf(input).mapDeep(input);
|
|
84
|
+
} else {
|
|
85
|
+
input = _.cloneDeep(input);
|
|
129
86
|
}
|
|
87
|
+
}
|
|
130
88
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
89
|
+
// Remove undefined properties to avoid unwanted overwrites
|
|
90
|
+
if (config.removeUndefined) {
|
|
91
|
+
Object.keys(input).forEach((key) => input[key] === undefined && delete input[key]);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// Process roles
|
|
95
|
+
if (
|
|
96
|
+
config.checkRoles &&
|
|
97
|
+
(input as Record<string, any>).roles &&
|
|
98
|
+
(!currentUser?.hasRole || !currentUser.hasRole(RoleEnum.ADMIN))
|
|
99
|
+
) {
|
|
100
|
+
if (!(currentUser as any)?.roles) {
|
|
101
|
+
throw new UnauthorizedException('Missing roles of current user');
|
|
102
|
+
} else {
|
|
103
|
+
const allowedRoles = _.intersection((input as Record<string, any>).roles, (currentUser as any).roles);
|
|
104
|
+
if (allowedRoles.length !== (input as Record<string, any>).roles.length) {
|
|
105
|
+
const missingRoles = _.difference((input as Record<string, any>).roles, (currentUser as any).roles);
|
|
106
|
+
throw new UnauthorizedException('Current user not allowed setting roles: ' + missingRoles);
|
|
137
107
|
}
|
|
108
|
+
(input as Record<string, any>).roles = allowedRoles;
|
|
138
109
|
}
|
|
110
|
+
}
|
|
139
111
|
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
112
|
+
// Hash password
|
|
113
|
+
if ((input as Record<string, any>).password) {
|
|
114
|
+
(input as Record<string, any>).password = await bcrypt.hash((input as any).password, 10);
|
|
115
|
+
}
|
|
144
116
|
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
117
|
+
// Set creator
|
|
118
|
+
if (config.create && currentUser) {
|
|
119
|
+
(input as Record<string, any>).createdBy = currentUser.id;
|
|
120
|
+
}
|
|
149
121
|
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
122
|
+
// Set updater
|
|
123
|
+
if (currentUser) {
|
|
124
|
+
(input as Record<string, any>).updatedBy = currentUser.id;
|
|
125
|
+
}
|
|
154
126
|
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
}
|
|
127
|
+
// Return prepared input
|
|
128
|
+
return input;
|
|
129
|
+
}
|
|
159
130
|
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
131
|
+
/**
|
|
132
|
+
* Prepare output before return
|
|
133
|
+
*/
|
|
134
|
+
export async function prepareOutput<T = { [key: string]: any; map: (...args: any[]) => any }>(
|
|
135
|
+
output: any,
|
|
136
|
+
options: {
|
|
137
|
+
[key: string]: any;
|
|
138
|
+
clone?: boolean;
|
|
139
|
+
getNewArray?: boolean;
|
|
140
|
+
removeUndefined?: boolean;
|
|
141
|
+
targetModel?: new (...args: any[]) => T;
|
|
142
|
+
} = {}
|
|
143
|
+
): Promise<T | T[] | any> {
|
|
144
|
+
// Configuration
|
|
145
|
+
const config = {
|
|
146
|
+
clone: false,
|
|
147
|
+
getNewArray: false,
|
|
148
|
+
removeUndefined: false,
|
|
149
|
+
targetModel: undefined,
|
|
150
|
+
...options,
|
|
151
|
+
};
|
|
152
|
+
|
|
153
|
+
// Check output
|
|
154
|
+
if (typeof output !== 'object') {
|
|
155
|
+
return output;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
// Process array
|
|
159
|
+
if (Array.isArray(output)) {
|
|
160
|
+
const processedArray = output.map(async (item) => await prepareOutput(item, options)) as any;
|
|
161
|
+
return config.getNewArray ? processedArray : output;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
// Clone output
|
|
165
|
+
if (config.clone) {
|
|
166
|
+
if (output.mapDeep && typeof output.mapDeep === 'function') {
|
|
167
|
+
output = await Object.getPrototypeOf(output).mapDeep(output);
|
|
168
|
+
} else {
|
|
169
|
+
output = _.cloneDeep(output);
|
|
163
170
|
}
|
|
171
|
+
}
|
|
164
172
|
|
|
165
|
-
|
|
166
|
-
|
|
173
|
+
// Map output if target model exist
|
|
174
|
+
if (config.targetModel) {
|
|
175
|
+
output = await (config.targetModel as any).map(output);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// Remove password if exists
|
|
179
|
+
if (output.password) {
|
|
180
|
+
output.password = undefined;
|
|
167
181
|
}
|
|
182
|
+
|
|
183
|
+
// Remove verification token if exists
|
|
184
|
+
if (output.verificationToken) {
|
|
185
|
+
output.verificationToken = undefined;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
// Remove password reset token if exists
|
|
189
|
+
if (output.passwordResetToken) {
|
|
190
|
+
output.passwordResetToken = undefined;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
// Remove undefined properties to avoid unwanted overwrites
|
|
194
|
+
if (config.removeUndefined) {
|
|
195
|
+
Object.keys(output).forEach((key) => output[key] === undefined && delete output[key]);
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
// Return prepared output
|
|
199
|
+
return output;
|
|
168
200
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Field, InputType } from '@nestjs/graphql';
|
|
2
2
|
import { LogicalOperatorEnum } from '../enums/logical-operator.enum';
|
|
3
|
-
import {
|
|
3
|
+
import { maps } from '../helpers/model.helper';
|
|
4
4
|
import { CoreInput } from './core-input.input';
|
|
5
5
|
import { FilterInput } from './filter.input';
|
|
6
6
|
|
|
@@ -40,7 +40,7 @@ export class CombinedFilterInput extends CoreInput {
|
|
|
40
40
|
} = {}
|
|
41
41
|
): this {
|
|
42
42
|
super.map(data, options);
|
|
43
|
-
this.filters =
|
|
43
|
+
this.filters = maps(data.filters, FilterInput, options.cloneDeep);
|
|
44
44
|
Object.keys(this).forEach((key) => this[key] === undefined && delete this[key]);
|
|
45
45
|
return this;
|
|
46
46
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { map } from '../helpers/model.helper';
|
|
2
2
|
import { CoreModel } from '../models/core-model.model';
|
|
3
3
|
|
|
4
4
|
/**
|
|
@@ -29,7 +29,7 @@ export abstract class CoreInput extends CoreModel {
|
|
|
29
29
|
mapId: false,
|
|
30
30
|
...options,
|
|
31
31
|
};
|
|
32
|
-
const coreInput =
|
|
32
|
+
const coreInput = map(data, this, config);
|
|
33
33
|
Object.keys(coreInput).forEach((key) => coreInput[key] === undefined && delete coreInput[key]);
|
|
34
34
|
return coreInput;
|
|
35
35
|
}
|
|
@@ -2,7 +2,7 @@ import { CallHandler, ExecutionContext, Injectable, NestInterceptor } from '@nes
|
|
|
2
2
|
import { Observable } from 'rxjs';
|
|
3
3
|
import { map } from 'rxjs/operators';
|
|
4
4
|
import { checkRestricted } from '../decorators/restricted.decorator';
|
|
5
|
-
import {
|
|
5
|
+
import { getContextData } from '../helpers/context.helper';
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
8
|
* Interceptor to check the response data for current user
|
|
@@ -14,7 +14,7 @@ export class CheckResponseInterceptor implements NestInterceptor {
|
|
|
14
14
|
*/
|
|
15
15
|
intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
|
|
16
16
|
// Get current user
|
|
17
|
-
const { currentUser }: any =
|
|
17
|
+
const { currentUser }: any = getContextData(context);
|
|
18
18
|
|
|
19
19
|
// Response interception
|
|
20
20
|
return next.handle().pipe(
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { Model, Types } from 'mongoose';
|
|
2
|
+
import { FieldSelection } from '../types/field-selection.type';
|
|
3
|
+
import { IdsType } from '../types/ids.type';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* General service options
|
|
7
|
+
*/
|
|
8
|
+
export interface ServiceOptions {
|
|
9
|
+
// All fields are allowed to be compatible as far as possible
|
|
10
|
+
[key: string]: any;
|
|
11
|
+
|
|
12
|
+
// Check rights for input data (see check function in InputHelper)
|
|
13
|
+
// If falsy: input data will not be checked
|
|
14
|
+
// If truly (default): input data will be checked
|
|
15
|
+
checkRights?: boolean;
|
|
16
|
+
|
|
17
|
+
// Current user to set ownership, check roles and other things
|
|
18
|
+
currentUser?: {
|
|
19
|
+
[key: string]: any;
|
|
20
|
+
id: string;
|
|
21
|
+
roles?: string[];
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
// Field selection for results
|
|
25
|
+
fieldSelection?: FieldSelection;
|
|
26
|
+
|
|
27
|
+
// Overwrites type of input (array items)
|
|
28
|
+
inputType?: new (...params: any[]) => any;
|
|
29
|
+
|
|
30
|
+
// Owner IDs
|
|
31
|
+
ownerIds?: IdsType;
|
|
32
|
+
|
|
33
|
+
// Process field selection
|
|
34
|
+
// If {} or not set, then the field selection runs with defaults
|
|
35
|
+
// If falsy, then the field selection will not be automatically executed
|
|
36
|
+
processFieldSelection?: {
|
|
37
|
+
model?: new (...args: any[]) => any;
|
|
38
|
+
dbModel?: Model<any>;
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
// Prepare input configuration:
|
|
42
|
+
// If {} or not set, then the prepareInput function will run with defaults
|
|
43
|
+
// If falsy, then the prepareInput function is not executed
|
|
44
|
+
prepareInput?: {
|
|
45
|
+
[key: string]: any;
|
|
46
|
+
create?: boolean;
|
|
47
|
+
clone?: boolean;
|
|
48
|
+
getNewArray?: boolean;
|
|
49
|
+
removeUndefined?: boolean;
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
// Prepare output configuration:
|
|
53
|
+
// If {} or not set, then the prepareInput function will run with defaults
|
|
54
|
+
// If falsy, then the prepareInput function is not executed
|
|
55
|
+
prepareOutput?: {
|
|
56
|
+
[key: string]: any;
|
|
57
|
+
clone?: boolean;
|
|
58
|
+
getNewArray?: boolean;
|
|
59
|
+
removeUndefined?: boolean;
|
|
60
|
+
targetModel?: new (...args: any[]) => any;
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
// Whether to publish action via GraphQL subscription
|
|
64
|
+
pubSub?: boolean;
|
|
65
|
+
|
|
66
|
+
// Overwrites type of result (array items)
|
|
67
|
+
resultType?: new (...params: any[]) => any;
|
|
68
|
+
|
|
69
|
+
// Roles (as string) to check
|
|
70
|
+
roles?: string | string[];
|
|
71
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { map } from '../helpers/model.helper';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Core Model
|
|
@@ -26,6 +26,7 @@ export abstract class CoreModel {
|
|
|
26
26
|
this: new (...args: any[]) => T,
|
|
27
27
|
data: Partial<T> | Record<string, any>,
|
|
28
28
|
options: {
|
|
29
|
+
[key: string]: any;
|
|
29
30
|
cloneDeep?: boolean;
|
|
30
31
|
funcAllowed?: boolean;
|
|
31
32
|
init?: any;
|
|
@@ -55,6 +56,7 @@ export abstract class CoreModel {
|
|
|
55
56
|
this: new (...args: any[]) => T,
|
|
56
57
|
data: Partial<T> | Record<string, any>,
|
|
57
58
|
options: {
|
|
59
|
+
[key: string]: any;
|
|
58
60
|
cloneDeep?: boolean;
|
|
59
61
|
funcAllowed?: boolean;
|
|
60
62
|
init?: any;
|
|
@@ -76,7 +78,7 @@ export abstract class CoreModel {
|
|
|
76
78
|
* Initialize instance with default values instead of undefined
|
|
77
79
|
* Should be overwritten in child class to organize the defaults
|
|
78
80
|
*/
|
|
79
|
-
public init
|
|
81
|
+
public init(...args: any[]): this {
|
|
80
82
|
return this;
|
|
81
83
|
}
|
|
82
84
|
|
|
@@ -86,6 +88,7 @@ export abstract class CoreModel {
|
|
|
86
88
|
public map(
|
|
87
89
|
data: Partial<this> | Record<string, any>,
|
|
88
90
|
options: {
|
|
91
|
+
[key: string]: any;
|
|
89
92
|
cloneDeep?: boolean;
|
|
90
93
|
funcAllowed?: boolean;
|
|
91
94
|
init?: any;
|
|
@@ -99,7 +102,7 @@ export abstract class CoreModel {
|
|
|
99
102
|
mapId: false,
|
|
100
103
|
...options,
|
|
101
104
|
};
|
|
102
|
-
return config.init ?
|
|
105
|
+
return config.init ? map(data, this, config).init(config.init) : map(data, this, config);
|
|
103
106
|
}
|
|
104
107
|
|
|
105
108
|
/**
|
|
@@ -113,6 +116,7 @@ export abstract class CoreModel {
|
|
|
113
116
|
public mapDeep(
|
|
114
117
|
data: Partial<this> | Record<string, any>,
|
|
115
118
|
options: {
|
|
119
|
+
[key: string]: any;
|
|
116
120
|
cloneDeep?: boolean;
|
|
117
121
|
funcAllowed?: boolean;
|
|
118
122
|
init?: any;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { ArgumentMetadata, Inject, Injectable, PipeTransform } from '@nestjs/common';
|
|
2
2
|
import { CONTEXT } from '@nestjs/graphql';
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
3
|
+
import { getContextData } from '../helpers/context.helper';
|
|
4
|
+
import { check } from '../helpers/input.helper';
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* The CheckInputPipe checks the permissibility of individual properties of inputs for the resolvers
|
|
@@ -25,9 +25,9 @@ export class CheckInputPipe implements PipeTransform {
|
|
|
25
25
|
const metatype = metadata?.metatype;
|
|
26
26
|
|
|
27
27
|
// Get user
|
|
28
|
-
const { user }: any =
|
|
28
|
+
const { user }: any = getContextData(this.context);
|
|
29
29
|
|
|
30
30
|
// Check and return
|
|
31
|
-
return
|
|
31
|
+
return check(value, user, { metatype });
|
|
32
32
|
}
|
|
33
33
|
}
|