@lenne.tech/nest-server 10.0.2 → 10.0.3
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 +29 -17
- package/dist/config.env.js.map +1 -1
- package/dist/core/common/args/filter.args.js +3 -3
- package/dist/core/common/args/filter.args.js.map +1 -1
- package/dist/core/common/args/pagination.args.js +6 -6
- package/dist/core/common/args/pagination.args.js.map +1 -1
- package/dist/core/common/decorators/restricted.decorator.js +15 -17
- package/dist/core/common/decorators/restricted.decorator.js.map +1 -1
- package/dist/core/common/filters/http-exception-log.filter.js +1 -3
- package/dist/core/common/filters/http-exception-log.filter.js.map +1 -1
- package/dist/core/common/helpers/db.helper.js +14 -14
- package/dist/core/common/helpers/db.helper.js.map +1 -1
- package/dist/core/common/helpers/file.helper.js +2 -2
- package/dist/core/common/helpers/file.helper.js.map +1 -1
- package/dist/core/common/helpers/filter.helper.d.ts +2 -2
- package/dist/core/common/helpers/filter.helper.js +1 -1
- package/dist/core/common/helpers/filter.helper.js.map +1 -1
- package/dist/core/common/helpers/graphql.helper.js +1 -1
- package/dist/core/common/helpers/graphql.helper.js.map +1 -1
- package/dist/core/common/helpers/input.helper.js +31 -38
- package/dist/core/common/helpers/input.helper.js.map +1 -1
- package/dist/core/common/helpers/model.helper.js +7 -7
- package/dist/core/common/helpers/model.helper.js.map +1 -1
- package/dist/core/common/helpers/service.helper.js +2 -2
- package/dist/core/common/helpers/service.helper.js.map +1 -1
- package/dist/core/common/inputs/combined-filter.input.js +3 -3
- 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/inputs/filter.input.js +3 -3
- package/dist/core/common/inputs/filter.input.js.map +1 -1
- package/dist/core/common/inputs/single-filter.input.js +4 -4
- package/dist/core/common/inputs/single-filter.input.js.map +1 -1
- package/dist/core/common/inputs/sort.input.js +1 -1
- package/dist/core/common/inputs/sort.input.js.map +1 -1
- package/dist/core/common/interceptors/check-security.interceptor.d.ts +1 -1
- package/dist/core/common/interceptors/check-security.interceptor.js +2 -2
- package/dist/core/common/interceptors/check-security.interceptor.js.map +1 -1
- package/dist/core/common/interfaces/server-options.interface.d.ts +27 -0
- package/dist/core/common/models/core-model.model.js.map +1 -1
- package/dist/core/common/models/core-persistence.model.js +3 -3
- package/dist/core/common/models/core-persistence.model.js.map +1 -1
- package/dist/core/common/pipes/map-and-validate.pipe.d.ts +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/scalars/any.scalar.js +2 -2
- package/dist/core/common/scalars/any.scalar.js.map +1 -1
- package/dist/core/common/scalars/date-timestamp.scalar.js +1 -1
- package/dist/core/common/scalars/date-timestamp.scalar.js.map +1 -1
- package/dist/core/common/scalars/date.scalar.js +1 -1
- package/dist/core/common/scalars/date.scalar.js.map +1 -1
- package/dist/core/common/scalars/json.scalar.js +2 -2
- package/dist/core/common/scalars/json.scalar.js.map +1 -1
- package/dist/core/common/services/config.service.js +7 -7
- package/dist/core/common/services/config.service.js.map +1 -1
- package/dist/core/common/services/core-cron-jobs.service.js +5 -5
- package/dist/core/common/services/core-cron-jobs.service.js.map +1 -1
- package/dist/core/common/services/crud.service.js +1 -1
- package/dist/core/common/services/crud.service.js.map +1 -1
- package/dist/core/common/services/mailjet.service.js +5 -5
- package/dist/core/common/services/mailjet.service.js.map +1 -1
- package/dist/core/common/services/module.service.js.map +1 -1
- package/dist/core/common/services/template.service.js +3 -3
- package/dist/core/common/services/template.service.js.map +1 -1
- package/dist/core/common/types/core-model-constructor.type.d.ts +2 -2
- package/dist/core/modules/auth/core-auth.module.js +3 -3
- package/dist/core/modules/auth/core-auth.module.js.map +1 -1
- package/dist/core/modules/auth/core-auth.resolver.js +5 -5
- package/dist/core/modules/auth/core-auth.resolver.js.map +1 -1
- package/dist/core/modules/auth/guards/auth.guard.js +4 -4
- package/dist/core/modules/auth/guards/auth.guard.js.map +1 -1
- package/dist/core/modules/auth/guards/roles.guard.js +1 -1
- package/dist/core/modules/auth/guards/roles.guard.js.map +1 -1
- package/dist/core/modules/auth/services/core-auth.service.js +5 -5
- package/dist/core/modules/auth/services/core-auth.service.js.map +1 -1
- package/dist/core/modules/auth/strategies/jwt.strategy.js.map +1 -1
- package/dist/core/modules/auth/tokens.decorator.js +2 -2
- package/dist/core/modules/auth/tokens.decorator.js.map +1 -1
- package/dist/core/modules/file/core-file-info.model.js +2 -2
- package/dist/core/modules/file/core-file-info.model.js.map +1 -1
- package/dist/core/modules/file/core-file.controller.d.ts +1 -2
- package/dist/core/modules/file/core-file.controller.js +3 -6
- package/dist/core/modules/file/core-file.controller.js.map +1 -1
- package/dist/core/modules/file/core-file.service.js +1 -1
- package/dist/core/modules/file/core-file.service.js.map +1 -1
- package/dist/core/modules/file/interfaces/file-upload.interface.d.ts +1 -1
- package/dist/core/modules/health-check/core-health-check-result.model.d.ts +8 -0
- package/dist/core/modules/health-check/core-health-check-result.model.js +53 -0
- package/dist/core/modules/health-check/core-health-check-result.model.js.map +1 -0
- package/dist/core/modules/health-check/core-health-check.controller.d.ts +6 -0
- package/dist/core/modules/health-check/core-health-check.controller.js +33 -0
- package/dist/core/modules/health-check/core-health-check.controller.js.map +1 -0
- package/dist/core/modules/health-check/core-health-check.module.d.ts +2 -0
- package/dist/core/modules/health-check/core-health-check.module.js +24 -0
- package/dist/core/modules/health-check/core-health-check.module.js.map +1 -0
- package/dist/core/modules/health-check/core-health-check.resolver.d.ts +6 -0
- package/dist/core/modules/health-check/core-health-check.resolver.js +38 -0
- package/dist/core/modules/health-check/core-health-check.resolver.js.map +1 -0
- package/dist/core/modules/health-check/core-health-check.service.d.ts +11 -0
- package/dist/core/modules/health-check/core-health-check.service.js +52 -0
- package/dist/core/modules/health-check/core-health-check.service.js.map +1 -0
- package/dist/core/modules/user/core-user.model.js +4 -4
- package/dist/core/modules/user/core-user.model.js.map +1 -1
- package/dist/core/modules/user/core-user.service.js +2 -2
- package/dist/core/modules/user/core-user.service.js.map +1 -1
- package/dist/core/modules/user/inputs/core-user.input.js +1 -1
- package/dist/core/modules/user/inputs/core-user.input.js.map +1 -1
- package/dist/core.module.js +10 -5
- package/dist/core.module.js.map +1 -1
- package/dist/index.d.ts +5 -0
- package/dist/index.js +5 -0
- package/dist/index.js.map +1 -1
- package/dist/main.js +1 -1
- package/dist/main.js.map +1 -1
- package/dist/server/modules/auth/auth.service.js +1 -1
- package/dist/server/modules/auth/auth.service.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/file/file.resolver.js +2 -2
- package/dist/server/modules/file/file.resolver.js.map +1 -1
- package/dist/server/modules/file/file.service.js +1 -1
- package/dist/server/modules/file/file.service.js.map +1 -1
- package/dist/server/modules/file/multer-config.service.js +1 -1
- package/dist/server/modules/file/multer-config.service.js.map +1 -1
- package/dist/server/modules/user/avatar.controller.js +1 -1
- package/dist/server/modules/user/avatar.controller.js.map +1 -1
- package/dist/server/modules/user/user.resolver.js +1 -1
- package/dist/server/modules/user/user.resolver.js.map +1 -1
- package/dist/server/modules/user/user.service.js +3 -3
- package/dist/server/modules/user/user.service.js.map +1 -1
- package/dist/templates/index.ejs +2 -0
- package/dist/templates/password-reset.ejs +3 -0
- package/dist/templates/welcome.ejs +3 -0
- package/dist/test/test.helper.d.ts +1 -1
- package/dist/test/test.helper.js +7 -7
- package/dist/test/test.helper.js.map +1 -1
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/package.json +26 -23
- package/src/config.env.ts +32 -20
- package/src/core/common/args/filter.args.ts +4 -4
- package/src/core/common/args/pagination.args.ts +7 -7
- package/src/core/common/decorators/graphql-service-options.decorator.ts +2 -2
- package/src/core/common/decorators/graphql-user.decorator.ts +1 -1
- package/src/core/common/decorators/rest-user.decorator.ts +1 -1
- package/src/core/common/decorators/restricted.decorator.ts +18 -18
- package/src/core/common/filters/http-exception-log.filter.ts +4 -4
- package/src/core/common/helpers/db.helper.ts +35 -40
- package/src/core/common/helpers/decorator.helper.ts +1 -1
- package/src/core/common/helpers/file.helper.ts +2 -2
- package/src/core/common/helpers/filter.helper.ts +7 -8
- package/src/core/common/helpers/graphql.helper.ts +6 -6
- package/src/core/common/helpers/input.helper.ts +54 -61
- package/src/core/common/helpers/model.helper.ts +33 -41
- package/src/core/common/helpers/service.helper.ts +8 -8
- package/src/core/common/inputs/combined-filter.input.ts +4 -4
- package/src/core/common/inputs/core-input.input.ts +2 -2
- package/src/core/common/inputs/filter.input.ts +4 -4
- package/src/core/common/inputs/single-filter.input.ts +4 -4
- package/src/core/common/inputs/sort.input.ts +1 -1
- package/src/core/common/interceptors/check-response.interceptor.ts +1 -1
- package/src/core/common/interceptors/check-security.interceptor.ts +5 -5
- package/src/core/common/interfaces/server-options.interface.ts +31 -0
- package/src/core/common/models/core-model.model.ts +6 -4
- package/src/core/common/models/core-persistence.model.ts +3 -3
- package/src/core/common/pipes/map-and-validate.pipe.ts +2 -2
- package/src/core/common/scalars/any.scalar.ts +2 -2
- package/src/core/common/scalars/date-timestamp.scalar.ts +1 -2
- package/src/core/common/scalars/date.scalar.ts +1 -2
- package/src/core/common/scalars/json.scalar.ts +4 -4
- package/src/core/common/services/config.service.ts +16 -16
- package/src/core/common/services/core-cron-jobs.service.ts +7 -7
- package/src/core/common/services/crud.service.ts +22 -22
- package/src/core/common/services/email.service.ts +1 -1
- package/src/core/common/services/mailjet.service.ts +8 -8
- package/src/core/common/services/module.service.ts +5 -6
- package/src/core/common/services/template.service.ts +4 -4
- package/src/core/common/types/core-model-constructor.type.ts +2 -2
- package/src/core/modules/auth/core-auth.controller.ts +2 -2
- package/src/core/modules/auth/core-auth.module.ts +4 -4
- package/src/core/modules/auth/core-auth.resolver.ts +9 -9
- package/src/core/modules/auth/guards/auth.guard.ts +8 -7
- package/src/core/modules/auth/guards/roles.guard.ts +1 -1
- package/src/core/modules/auth/services/core-auth.service.ts +9 -9
- package/src/core/modules/auth/strategies/jwt-refresh.strategy.ts +1 -1
- package/src/core/modules/auth/strategies/jwt.strategy.ts +1 -1
- package/src/core/modules/auth/tokens.decorator.ts +6 -7
- package/src/core/modules/file/core-file-info.model.ts +2 -2
- package/src/core/modules/file/core-file.controller.ts +2 -4
- package/src/core/modules/file/core-file.service.ts +6 -5
- package/src/core/modules/file/interfaces/file-upload.interface.ts +1 -1
- package/src/core/modules/health-check/core-health-check-result.model.ts +46 -0
- package/src/core/modules/health-check/core-health-check.controller.ts +24 -0
- package/src/core/modules/health-check/core-health-check.module.ts +17 -0
- package/src/core/modules/health-check/core-health-check.resolver.ts +32 -0
- package/src/core/modules/health-check/core-health-check.service.ts +60 -0
- package/src/core/modules/user/core-user.model.ts +5 -5
- package/src/core/modules/user/core-user.service.ts +10 -9
- package/src/core/modules/user/inputs/core-user.input.ts +1 -2
- package/src/core.module.ts +16 -10
- package/src/index.ts +10 -0
- package/src/main.ts +2 -2
- package/src/server/modules/auth/auth.controller.ts +1 -1
- package/src/server/modules/auth/auth.resolver.ts +3 -3
- package/src/server/modules/auth/auth.service.ts +2 -2
- package/src/server/modules/file/file.controller.ts +1 -2
- package/src/server/modules/file/file.module.ts +1 -1
- package/src/server/modules/file/file.resolver.ts +4 -3
- package/src/server/modules/file/file.service.ts +1 -1
- package/src/server/modules/file/multer-config.service.ts +1 -1
- package/src/server/modules/user/avatar.controller.ts +3 -3
- package/src/server/modules/user/user.model.ts +1 -1
- package/src/server/modules/user/user.resolver.ts +4 -4
- package/src/server/modules/user/user.service.ts +4 -4
- package/src/test/test.helper.ts +11 -11
|
@@ -1,6 +1,6 @@
|
|
|
1
|
+
import { extname } from 'path';
|
|
1
2
|
import { MulterOptions } from '@nestjs/platform-express/multer/interfaces/multer-options.interface';
|
|
2
3
|
import { diskStorage } from 'multer';
|
|
3
|
-
import { extname } from 'path';
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* Helper class for inputs
|
|
@@ -63,7 +63,7 @@ export function multerFileFilter(fileTypeRegex = /jpeg|jpg|png/) {
|
|
|
63
63
|
if (mimetype && extName) {
|
|
64
64
|
return cb(null, true);
|
|
65
65
|
}
|
|
66
|
-
cb(
|
|
66
|
+
cb(`Error: File upload only supports the following filetypes - ${fileTypeRegex}`);
|
|
67
67
|
};
|
|
68
68
|
}
|
|
69
69
|
|
|
@@ -32,7 +32,7 @@ export class Filter {
|
|
|
32
32
|
/**
|
|
33
33
|
* Generate find options
|
|
34
34
|
*/
|
|
35
|
-
public static generateFindOptions
|
|
35
|
+
public static generateFindOptions(filterArgs: Partial<FilterArgs>): QueryOptions {
|
|
36
36
|
return generateFindOptions(filterArgs);
|
|
37
37
|
}
|
|
38
38
|
}
|
|
@@ -86,7 +86,7 @@ export function findFilter(options?: {
|
|
|
86
86
|
}
|
|
87
87
|
|
|
88
88
|
// Filter falsy values
|
|
89
|
-
filterOptions[config.type] = filterOptions[config.type].filter(
|
|
89
|
+
filterOptions[config.type] = filterOptions[config.type].filter(value => value);
|
|
90
90
|
|
|
91
91
|
// Optimizations
|
|
92
92
|
if (!filterOptions[config.type].length) {
|
|
@@ -113,7 +113,7 @@ export function convertFilterArgsToQuery<T = any>(filterArgs: Partial<FilterArgs
|
|
|
113
113
|
*/
|
|
114
114
|
export function generateFilterQuery<T = any>(
|
|
115
115
|
filter?: Partial<FilterInput>,
|
|
116
|
-
options?: { automaticObjectIdFiltering?: boolean }
|
|
116
|
+
options?: { automaticObjectIdFiltering?: boolean },
|
|
117
117
|
): FilterQuery<T> | any {
|
|
118
118
|
// Check filter
|
|
119
119
|
if (!filter) {
|
|
@@ -156,10 +156,9 @@ export function generateFilterQuery<T = any>(
|
|
|
156
156
|
// Convert value to object ID(s)
|
|
157
157
|
if (convertToObjectId || isReference) {
|
|
158
158
|
value = getObjectIds(value);
|
|
159
|
-
}
|
|
160
159
|
|
|
161
|
-
|
|
162
|
-
else if (config.automaticObjectIdFiltering && checkStringIds(value)) {
|
|
160
|
+
// Check if value is a string ID and automatic ObjectID filtering is activated
|
|
161
|
+
} else if (config.automaticObjectIdFiltering && checkStringIds(value)) {
|
|
163
162
|
// Set both the string filter and the ObjectID filtering in an OR construction
|
|
164
163
|
const alternativeQuery = clone(filter.singleFilter, { circles: false });
|
|
165
164
|
alternativeQuery.value = getObjectIds(value);
|
|
@@ -215,9 +214,9 @@ export function generateFilterQuery<T = any>(
|
|
|
215
214
|
/**
|
|
216
215
|
* Generate find options
|
|
217
216
|
*/
|
|
218
|
-
export function generateFindOptions
|
|
217
|
+
export function generateFindOptions(
|
|
219
218
|
filterArgs: Partial<FilterArgs>,
|
|
220
|
-
options?: { maxLimit?: number }
|
|
219
|
+
options?: { maxLimit?: number },
|
|
221
220
|
): QueryOptions {
|
|
222
221
|
// Check filterArgs
|
|
223
222
|
if (!filterArgs) {
|
|
@@ -106,7 +106,7 @@ export default class GraphQLHelper {
|
|
|
106
106
|
ast: FieldNode,
|
|
107
107
|
info: GraphQLResolveInfo,
|
|
108
108
|
obj: any = {},
|
|
109
|
-
config: Partial<GraphQLFieldsConfig> = {}
|
|
109
|
+
config: Partial<GraphQLFieldsConfig> = {},
|
|
110
110
|
) {
|
|
111
111
|
return flattenAST(ast, info, obj, config);
|
|
112
112
|
}
|
|
@@ -117,7 +117,7 @@ export default class GraphQLHelper {
|
|
|
117
117
|
public static getFields(
|
|
118
118
|
info: GraphQLResolveInfo,
|
|
119
119
|
obj: Record<string, any> = {},
|
|
120
|
-
config: Partial<GraphQLFieldsConfig> = {}
|
|
120
|
+
config: Partial<GraphQLFieldsConfig> = {},
|
|
121
121
|
) {
|
|
122
122
|
return getFields(info, obj, config);
|
|
123
123
|
}
|
|
@@ -190,7 +190,7 @@ export function getArguments(ast: FieldNode) {
|
|
|
190
190
|
const valueNode = argument.value;
|
|
191
191
|
const argumentValue = !isListValueNode(valueNode)
|
|
192
192
|
? (valueNode as any).value
|
|
193
|
-
: (valueNode as any).values.map(
|
|
193
|
+
: (valueNode as any).values.map(value => value.value);
|
|
194
194
|
|
|
195
195
|
return {
|
|
196
196
|
[argument.name.value]: {
|
|
@@ -251,7 +251,7 @@ export function flattenAST(
|
|
|
251
251
|
ast: FieldNode,
|
|
252
252
|
info: GraphQLResolveInfo,
|
|
253
253
|
obj: any = {},
|
|
254
|
-
config: Partial<GraphQLFieldsConfig> = {}
|
|
254
|
+
config: Partial<GraphQLFieldsConfig> = {},
|
|
255
255
|
) {
|
|
256
256
|
// Process configuration
|
|
257
257
|
config = Object.assign(
|
|
@@ -259,7 +259,7 @@ export function flattenAST(
|
|
|
259
259
|
processArguments: false,
|
|
260
260
|
excludedFields: [],
|
|
261
261
|
},
|
|
262
|
-
config
|
|
262
|
+
config,
|
|
263
263
|
);
|
|
264
264
|
|
|
265
265
|
return getASTSelections(ast).reduce((flattened, a) => {
|
|
@@ -306,7 +306,7 @@ export function flattenAST(
|
|
|
306
306
|
export function getFields(
|
|
307
307
|
info: GraphQLResolveInfo,
|
|
308
308
|
obj: Record<string, any> = {},
|
|
309
|
-
config: Partial<GraphQLFieldsConfig> = {}
|
|
309
|
+
config: Partial<GraphQLFieldsConfig> = {},
|
|
310
310
|
) {
|
|
311
311
|
// Check info
|
|
312
312
|
if (!info || (!info.fieldNodes && !(info as any).fieldASTs)) {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { BadRequestException,
|
|
1
|
+
import { BadRequestException, UnauthorizedException } from '@nestjs/common';
|
|
2
2
|
import { plainToInstance } from 'class-transformer';
|
|
3
3
|
import { validate } from 'class-validator';
|
|
4
4
|
import { ValidatorOptions } from 'class-validator/types/validation/ValidatorOptions';
|
|
@@ -28,7 +28,7 @@ export default class InputHelper {
|
|
|
28
28
|
processType?: ProcessType;
|
|
29
29
|
roles?: string | string[];
|
|
30
30
|
throwError?: boolean;
|
|
31
|
-
}
|
|
31
|
+
},
|
|
32
32
|
): Promise<any> {
|
|
33
33
|
return check(value, user, options);
|
|
34
34
|
}
|
|
@@ -59,7 +59,7 @@ export default class InputHelper {
|
|
|
59
59
|
parameter: number,
|
|
60
60
|
min: number,
|
|
61
61
|
max: number,
|
|
62
|
-
falseFunction: (...params) => any = errorFunction
|
|
62
|
+
falseFunction: (...params) => any = errorFunction,
|
|
63
63
|
): boolean {
|
|
64
64
|
return isBetween(parameter, min, max, falseFunction);
|
|
65
65
|
}
|
|
@@ -105,7 +105,7 @@ export default class InputHelper {
|
|
|
105
105
|
public static isGreater(
|
|
106
106
|
parameter: number,
|
|
107
107
|
compare: number,
|
|
108
|
-
falseFunction: (...params) => any = errorFunction
|
|
108
|
+
falseFunction: (...params) => any = errorFunction,
|
|
109
109
|
): boolean {
|
|
110
110
|
return isGreater(parameter, compare, falseFunction);
|
|
111
111
|
}
|
|
@@ -116,7 +116,7 @@ export default class InputHelper {
|
|
|
116
116
|
public static isLower(
|
|
117
117
|
parameter: number,
|
|
118
118
|
compare: number,
|
|
119
|
-
falseFunction: (...params) => any = errorFunction
|
|
119
|
+
falseFunction: (...params) => any = errorFunction,
|
|
120
120
|
): boolean {
|
|
121
121
|
return isLower(parameter, compare, falseFunction);
|
|
122
122
|
}
|
|
@@ -125,7 +125,7 @@ export default class InputHelper {
|
|
|
125
125
|
* Check if parameter is a non-empty array
|
|
126
126
|
*/
|
|
127
127
|
public static isNonEmptyArray(parameter: any, falseFunction: (...params) => any = errorFunction): boolean {
|
|
128
|
-
return isNonEmptyString(parameter,
|
|
128
|
+
return isNonEmptyString(parameter, falseFunction);
|
|
129
129
|
}
|
|
130
130
|
|
|
131
131
|
/**
|
|
@@ -182,7 +182,7 @@ export default class InputHelper {
|
|
|
182
182
|
* @deprecated use mapClass function
|
|
183
183
|
*/
|
|
184
184
|
public static map<T>(values: Partial<T>, ctor: new () => T, cloneDeep = true): T {
|
|
185
|
-
return mapClass(values, ctor);
|
|
185
|
+
return mapClass(values, ctor, { cloneDeep });
|
|
186
186
|
}
|
|
187
187
|
}
|
|
188
188
|
|
|
@@ -194,13 +194,10 @@ export function assignPlain(target: Record<any, any>, ...args: Record<any, any>[
|
|
|
194
194
|
target,
|
|
195
195
|
...args.map(
|
|
196
196
|
// Prepare records
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
: // Return cloned record with undefined properties removed
|
|
202
|
-
filterProperties(clone(item, { circles: false }), (prop) => prop !== undefined)
|
|
203
|
-
)
|
|
197
|
+
item =>
|
|
198
|
+
// Return item if not an object or cloned record with undefined properties removed
|
|
199
|
+
!item ? item : filterProperties(clone(item, { circles: false }), prop => prop !== undefined),
|
|
200
|
+
),
|
|
204
201
|
);
|
|
205
202
|
}
|
|
206
203
|
|
|
@@ -217,7 +214,7 @@ export async function check(
|
|
|
217
214
|
roles?: string | string[];
|
|
218
215
|
throwError?: boolean;
|
|
219
216
|
validatorOptions?: ValidatorOptions;
|
|
220
|
-
}
|
|
217
|
+
},
|
|
221
218
|
): Promise<any> {
|
|
222
219
|
const config = {
|
|
223
220
|
throwError: true,
|
|
@@ -245,15 +242,15 @@ export async function check(
|
|
|
245
242
|
// Check access
|
|
246
243
|
if (
|
|
247
244
|
// check if any user, including users who are not logged in, can access
|
|
248
|
-
roles.includes(RoleEnum.S_EVERYONE)
|
|
245
|
+
roles.includes(RoleEnum.S_EVERYONE)
|
|
249
246
|
// check if user is logged in
|
|
250
|
-
(roles.includes(RoleEnum.S_USER) && user?.id)
|
|
247
|
+
|| (roles.includes(RoleEnum.S_USER) && user?.id)
|
|
251
248
|
// check if the user has at least one of the required roles
|
|
252
|
-
user?.hasRole?.(roles)
|
|
249
|
+
|| user?.hasRole?.(roles)
|
|
253
250
|
// check if the user is herself / himself
|
|
254
|
-
(roles.includes(RoleEnum.S_SELF) && equalIds(config.dbObject, user))
|
|
251
|
+
|| (roles.includes(RoleEnum.S_SELF) && equalIds(config.dbObject, user))
|
|
255
252
|
// check if the user is the creator
|
|
256
|
-
(roles.includes(RoleEnum.S_CREATOR) && equalIds(config.dbObject?.createdBy, user))
|
|
253
|
+
|| (roles.includes(RoleEnum.S_CREATOR) && equalIds(config.dbObject?.createdBy, user))
|
|
257
254
|
) {
|
|
258
255
|
valid = true;
|
|
259
256
|
}
|
|
@@ -394,10 +391,10 @@ export function errorFunction(caller: (...params) => any, message = 'Required pa
|
|
|
394
391
|
*/
|
|
395
392
|
export function filterProperties<T = Record<string, any>>(
|
|
396
393
|
obj: T,
|
|
397
|
-
filterFunction: (value?: any, key?: string, obj?: T) => boolean
|
|
394
|
+
filterFunction: (value?: any, key?: string, obj?: T) => boolean,
|
|
398
395
|
): Partial<T> {
|
|
399
396
|
return Object.keys(obj)
|
|
400
|
-
.filter(
|
|
397
|
+
.filter(key => filterFunction(obj[key], key, obj))
|
|
401
398
|
.reduce((res, key) => Object.assign(res, { [key]: obj[key] }), {});
|
|
402
399
|
}
|
|
403
400
|
|
|
@@ -454,7 +451,7 @@ export function isBetween(
|
|
|
454
451
|
parameter: number,
|
|
455
452
|
min: number,
|
|
456
453
|
max: number,
|
|
457
|
-
falseFunction: (...params) => any = errorFunction
|
|
454
|
+
falseFunction: (...params) => any = errorFunction,
|
|
458
455
|
): boolean {
|
|
459
456
|
return typeof parameter === 'number' && parameter > min && parameter < max ? true : falseFunction(isBetween);
|
|
460
457
|
}
|
|
@@ -485,12 +482,12 @@ export function isFalse(parameter: any, falseFunction: (...params) => any = erro
|
|
|
485
482
|
* Check if parameter is a valid file
|
|
486
483
|
*/
|
|
487
484
|
export function isFile(parameter: any, falseFunction: (...params) => any = errorFunction): boolean {
|
|
488
|
-
return parameter !== null
|
|
489
|
-
typeof parameter !== 'undefined'
|
|
490
|
-
parameter.name
|
|
491
|
-
parameter.path
|
|
492
|
-
parameter.type
|
|
493
|
-
parameter.size > 0
|
|
485
|
+
return parameter !== null
|
|
486
|
+
&& typeof parameter !== 'undefined'
|
|
487
|
+
&& parameter.name
|
|
488
|
+
&& parameter.path
|
|
489
|
+
&& parameter.type
|
|
490
|
+
&& parameter.size > 0
|
|
494
491
|
? true
|
|
495
492
|
: falseFunction(isFile);
|
|
496
493
|
}
|
|
@@ -508,7 +505,7 @@ export function isFunction(parameter: (...params) => any, falseFunction: (...par
|
|
|
508
505
|
export function isGreater(
|
|
509
506
|
parameter: number,
|
|
510
507
|
compare: number,
|
|
511
|
-
falseFunction: (...params) => any = errorFunction
|
|
508
|
+
falseFunction: (...params) => any = errorFunction,
|
|
512
509
|
): boolean {
|
|
513
510
|
return typeof parameter === 'number' && parameter > compare ? true : falseFunction(isGreater);
|
|
514
511
|
}
|
|
@@ -519,7 +516,7 @@ export function isGreater(
|
|
|
519
516
|
export function isLower(
|
|
520
517
|
parameter: number,
|
|
521
518
|
compare: number,
|
|
522
|
-
falseFunction: (...params) => any = errorFunction
|
|
519
|
+
falseFunction: (...params) => any = errorFunction,
|
|
523
520
|
): boolean {
|
|
524
521
|
return typeof parameter === 'number' && parameter < compare ? true : falseFunction(isLower);
|
|
525
522
|
}
|
|
@@ -528,10 +525,10 @@ export function isLower(
|
|
|
528
525
|
* Check if parameter is a non empty array
|
|
529
526
|
*/
|
|
530
527
|
export function isNonEmptyArray(parameter: any, falseFunction: (...params) => any = errorFunction): boolean {
|
|
531
|
-
return parameter !== null
|
|
532
|
-
typeof parameter !== 'undefined'
|
|
533
|
-
parameter.constructor === Array
|
|
534
|
-
parameter.length > 0
|
|
528
|
+
return parameter !== null
|
|
529
|
+
&& typeof parameter !== 'undefined'
|
|
530
|
+
&& parameter.constructor === Array
|
|
531
|
+
&& parameter.length > 0
|
|
535
532
|
? true
|
|
536
533
|
: falseFunction(isNonEmptyArray);
|
|
537
534
|
}
|
|
@@ -540,10 +537,10 @@ export function isNonEmptyArray(parameter: any, falseFunction: (...params) => an
|
|
|
540
537
|
* Check if parameter is a non empty object
|
|
541
538
|
*/
|
|
542
539
|
export function isNonEmptyObject(parameter: any, falseFunction: (...params) => any = errorFunction): boolean {
|
|
543
|
-
return parameter !== null
|
|
544
|
-
typeof parameter !== 'undefined'
|
|
545
|
-
parameter.constructor === Object
|
|
546
|
-
Object.keys(parameter).length !== 0
|
|
540
|
+
return parameter !== null
|
|
541
|
+
&& typeof parameter !== 'undefined'
|
|
542
|
+
&& parameter.constructor === Object
|
|
543
|
+
&& Object.keys(parameter).length !== 0
|
|
547
544
|
? true
|
|
548
545
|
: falseFunction(isNonEmptyObject);
|
|
549
546
|
}
|
|
@@ -593,13 +590,10 @@ export function mergePlain(target: Record<any, any>, ...args: Record<any, any>[]
|
|
|
593
590
|
target,
|
|
594
591
|
...args.map(
|
|
595
592
|
// Prepare records
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
: // Return cloned record with undefined properties removed
|
|
601
|
-
filterProperties(clone(item, { circles: false }), (prop) => prop !== undefined)
|
|
602
|
-
)
|
|
593
|
+
item =>
|
|
594
|
+
// Return item if not an object or cloned record with undefined properties removed
|
|
595
|
+
!item ? item : filterProperties(clone(item, { circles: false }), prop => prop !== undefined),
|
|
596
|
+
),
|
|
603
597
|
);
|
|
604
598
|
}
|
|
605
599
|
|
|
@@ -636,12 +630,13 @@ export function mapClass<T>(
|
|
|
636
630
|
cloneDeep?: boolean;
|
|
637
631
|
circle?: boolean;
|
|
638
632
|
proto?: boolean;
|
|
639
|
-
}
|
|
633
|
+
},
|
|
640
634
|
): T {
|
|
641
635
|
const config = {
|
|
642
636
|
cloneDeep: true,
|
|
643
637
|
circles: false,
|
|
644
638
|
proto: false,
|
|
639
|
+
...options,
|
|
645
640
|
};
|
|
646
641
|
const instance = new ctor();
|
|
647
642
|
|
|
@@ -708,7 +703,7 @@ export function processDeep(
|
|
|
708
703
|
specialClasses?: ((new (args: any[]) => any) | string)[];
|
|
709
704
|
specialFunctions?: string[];
|
|
710
705
|
specialProperties?: string[];
|
|
711
|
-
}
|
|
706
|
+
},
|
|
712
707
|
): any {
|
|
713
708
|
// Set options
|
|
714
709
|
const { processedObjects, specialClasses, specialFunctions, specialProperties } = {
|
|
@@ -722,10 +717,9 @@ export function processDeep(
|
|
|
722
717
|
// Check for falsifiable values
|
|
723
718
|
if (!data) {
|
|
724
719
|
return func(data);
|
|
725
|
-
}
|
|
726
720
|
|
|
727
|
-
|
|
728
|
-
else if (typeof data === 'object') {
|
|
721
|
+
// Prevent circular processing
|
|
722
|
+
} else if (typeof data === 'object') {
|
|
729
723
|
if (processedObjects.get(data)) {
|
|
730
724
|
return data;
|
|
731
725
|
}
|
|
@@ -734,21 +728,21 @@ export function processDeep(
|
|
|
734
728
|
|
|
735
729
|
// Process array
|
|
736
730
|
if (Array.isArray(data)) {
|
|
737
|
-
return func(data.map(
|
|
731
|
+
return func(data.map(item => processDeep(item, func, { processedObjects, specialClasses })));
|
|
738
732
|
}
|
|
739
733
|
|
|
740
734
|
// Process object
|
|
741
735
|
if (typeof data === 'object') {
|
|
742
736
|
if (
|
|
743
|
-
specialFunctions.find(
|
|
744
|
-
specialProperties.find(
|
|
737
|
+
specialFunctions.find(sF => typeof data[sF] === 'function')
|
|
738
|
+
|| specialProperties.find(sP => Object.getOwnPropertyNames(data).includes(sP))
|
|
745
739
|
) {
|
|
746
740
|
return func(data);
|
|
747
741
|
}
|
|
748
742
|
for (const specialClass of specialClasses) {
|
|
749
743
|
if (
|
|
750
|
-
(typeof specialClass === 'string' && specialClass === data.constructor?.name)
|
|
751
|
-
(typeof specialClass !== 'string' && data instanceof specialClass)
|
|
744
|
+
(typeof specialClass === 'string' && specialClass === data.constructor?.name)
|
|
745
|
+
|| (typeof specialClass !== 'string' && data instanceof specialClass)
|
|
752
746
|
) {
|
|
753
747
|
return func(data);
|
|
754
748
|
}
|
|
@@ -787,7 +781,7 @@ export function removePropertiesDeep(
|
|
|
787
781
|
properties: string[],
|
|
788
782
|
options?: {
|
|
789
783
|
processedObjects?: WeakMap<new () => any, boolean>;
|
|
790
|
-
}
|
|
784
|
+
},
|
|
791
785
|
): any {
|
|
792
786
|
// Set options
|
|
793
787
|
const { processedObjects } = {
|
|
@@ -798,10 +792,9 @@ export function removePropertiesDeep(
|
|
|
798
792
|
// Check for falsifiable values
|
|
799
793
|
if (!data) {
|
|
800
794
|
return data;
|
|
801
|
-
}
|
|
802
795
|
|
|
803
|
-
|
|
804
|
-
else if (typeof data === 'object') {
|
|
796
|
+
// Prevent circular processing
|
|
797
|
+
} else if (typeof data === 'object') {
|
|
805
798
|
if (processedObjects.get(data)) {
|
|
806
799
|
return data;
|
|
807
800
|
}
|
|
@@ -810,7 +803,7 @@ export function removePropertiesDeep(
|
|
|
810
803
|
|
|
811
804
|
// Process array
|
|
812
805
|
if (Array.isArray(data)) {
|
|
813
|
-
return data.map(
|
|
806
|
+
return data.map(item => removePropertiesDeep(item, properties, { processedObjects }));
|
|
814
807
|
}
|
|
815
808
|
|
|
816
809
|
// Process object
|
|
@@ -17,7 +17,7 @@ export class ModelHelper {
|
|
|
17
17
|
cloneDeep?: boolean;
|
|
18
18
|
funcAllowed?: boolean;
|
|
19
19
|
mapId?: boolean;
|
|
20
|
-
} = {}
|
|
20
|
+
} = {},
|
|
21
21
|
): Partial<T> | Record<string, any> {
|
|
22
22
|
return prepareMap(source, target, options);
|
|
23
23
|
}
|
|
@@ -32,7 +32,7 @@ export class ModelHelper {
|
|
|
32
32
|
cloneDeep?: boolean;
|
|
33
33
|
funcAllowed?: boolean;
|
|
34
34
|
mapId?: boolean;
|
|
35
|
-
} = {}
|
|
35
|
+
} = {},
|
|
36
36
|
): T {
|
|
37
37
|
return map(source, target, options);
|
|
38
38
|
}
|
|
@@ -43,7 +43,7 @@ export class ModelHelper {
|
|
|
43
43
|
public static maps<T = Record<string, any>>(
|
|
44
44
|
data: Partial<T> | Partial<T>[] | Record<string, any> | Record<string, any>[],
|
|
45
45
|
targetClass: new (...args: any[]) => T,
|
|
46
|
-
cloneDeep = true
|
|
46
|
+
cloneDeep = true,
|
|
47
47
|
): T[] {
|
|
48
48
|
return maps(data, targetClass, cloneDeep);
|
|
49
49
|
}
|
|
@@ -61,7 +61,7 @@ export function prepareMap<T = Record<string, any>>(
|
|
|
61
61
|
funcAllowed?: boolean;
|
|
62
62
|
mapId?: boolean;
|
|
63
63
|
proto?: boolean;
|
|
64
|
-
} = {}
|
|
64
|
+
} = {},
|
|
65
65
|
): Partial<T> | Record<string, any> {
|
|
66
66
|
// Set config
|
|
67
67
|
const config = {
|
|
@@ -79,12 +79,12 @@ export function prepareMap<T = Record<string, any>>(
|
|
|
79
79
|
// Update properties
|
|
80
80
|
for (const key of Object.keys(target)) {
|
|
81
81
|
if (
|
|
82
|
-
(!['id', '_id'].includes(key) || config.mapId)
|
|
83
|
-
source[key] !== undefined
|
|
84
|
-
(config.funcAllowed || typeof (source[key] !== 'function'))
|
|
82
|
+
(!['id', '_id'].includes(key) || config.mapId)
|
|
83
|
+
&& source[key] !== undefined
|
|
84
|
+
&& (config.funcAllowed || typeof (source[key] !== 'function'))
|
|
85
85
|
) {
|
|
86
|
-
result[key]
|
|
87
|
-
source[key] !== 'function' && config.cloneDeep
|
|
86
|
+
result[key]
|
|
87
|
+
= source[key] !== 'function' && config.cloneDeep
|
|
88
88
|
? clone(source[key], { circles: config.circles, proto: config.proto })
|
|
89
89
|
: source[key];
|
|
90
90
|
} else if (key === 'id' && !config.mapId) {
|
|
@@ -107,7 +107,7 @@ export function map<T = Record<string, any>>(
|
|
|
107
107
|
funcAllowed?: boolean;
|
|
108
108
|
mapId?: boolean;
|
|
109
109
|
proto?: boolean;
|
|
110
|
-
} = {}
|
|
110
|
+
} = {},
|
|
111
111
|
): T {
|
|
112
112
|
// Set config
|
|
113
113
|
const config = {
|
|
@@ -140,7 +140,7 @@ export function map<T = Record<string, any>>(
|
|
|
140
140
|
export function maps<T = Record<string, any>>(
|
|
141
141
|
data: Partial<T> | Partial<T>[] | Record<string, any> | Record<string, any>[],
|
|
142
142
|
targetClass: new (...args: any[]) => T,
|
|
143
|
-
cloneDeep = true
|
|
143
|
+
cloneDeep = true,
|
|
144
144
|
): T[] {
|
|
145
145
|
// Check data
|
|
146
146
|
if (!data || typeof data !== 'object') {
|
|
@@ -171,7 +171,7 @@ export function mapClasses<T = Record<string, any>>(
|
|
|
171
171
|
input: Record<string, any>,
|
|
172
172
|
mapping: Record<string, new (...args: any[]) => any>,
|
|
173
173
|
target?: T,
|
|
174
|
-
options?: { objectIdsToString?: boolean; removeUndefinedProperties?: boolean }
|
|
174
|
+
options?: { objectIdsToString?: boolean; removeUndefinedProperties?: boolean },
|
|
175
175
|
): T {
|
|
176
176
|
// Check params
|
|
177
177
|
if (!target) {
|
|
@@ -198,10 +198,9 @@ export function mapClasses<T = Record<string, any>>(
|
|
|
198
198
|
if (value === null) {
|
|
199
199
|
target[prop] = null;
|
|
200
200
|
continue;
|
|
201
|
-
}
|
|
202
201
|
|
|
203
|
-
|
|
204
|
-
else if (Array.isArray(value)) {
|
|
202
|
+
// Process array
|
|
203
|
+
} else if (Array.isArray(value)) {
|
|
205
204
|
const arr = [];
|
|
206
205
|
for (const item of value) {
|
|
207
206
|
if (item instanceof targetClass) {
|
|
@@ -219,15 +218,13 @@ export function mapClasses<T = Record<string, any>>(
|
|
|
219
218
|
}
|
|
220
219
|
}
|
|
221
220
|
target[prop] = arr as any;
|
|
222
|
-
}
|
|
223
221
|
|
|
224
|
-
|
|
225
|
-
else if (value instanceof Types.ObjectId) {
|
|
222
|
+
// Process ObjectId
|
|
223
|
+
} else if (value instanceof Types.ObjectId) {
|
|
226
224
|
target[prop] = config.objectIdsToString ? value.toHexString() : value;
|
|
227
|
-
}
|
|
228
225
|
|
|
229
|
-
|
|
230
|
-
else if (typeof value === 'object') {
|
|
226
|
+
// Process object
|
|
227
|
+
} else if (typeof value === 'object') {
|
|
231
228
|
if (value instanceof targetClass) {
|
|
232
229
|
target[prop] = value as any;
|
|
233
230
|
} else {
|
|
@@ -237,10 +234,9 @@ export function mapClasses<T = Record<string, any>>(
|
|
|
237
234
|
target[prop] = plainToInstance(targetClass, value) as any;
|
|
238
235
|
}
|
|
239
236
|
}
|
|
240
|
-
}
|
|
241
237
|
|
|
242
|
-
|
|
243
|
-
else if (!config.removeUndefinedProperties || value !== undefined) {
|
|
238
|
+
// Others
|
|
239
|
+
} else if (!config.removeUndefinedProperties || value !== undefined) {
|
|
244
240
|
target[prop] = value;
|
|
245
241
|
}
|
|
246
242
|
}
|
|
@@ -262,7 +258,7 @@ export async function mapClassesAsync<T = Record<string, any>>(
|
|
|
262
258
|
input: Record<string, any>,
|
|
263
259
|
mapping: Record<string, new (...args: any[]) => any>,
|
|
264
260
|
target?: T,
|
|
265
|
-
options?: { objectIdsToString?: boolean; removeUndefinedProperties?: boolean }
|
|
261
|
+
options?: { objectIdsToString?: boolean; removeUndefinedProperties?: boolean },
|
|
266
262
|
): Promise<T> {
|
|
267
263
|
// Check params
|
|
268
264
|
if (!target) {
|
|
@@ -289,10 +285,9 @@ export async function mapClassesAsync<T = Record<string, any>>(
|
|
|
289
285
|
if (value === null) {
|
|
290
286
|
target[prop] = null;
|
|
291
287
|
continue;
|
|
292
|
-
}
|
|
293
288
|
|
|
294
|
-
|
|
295
|
-
else if (Array.isArray(value)) {
|
|
289
|
+
// Process array
|
|
290
|
+
} else if (Array.isArray(value)) {
|
|
296
291
|
const arr = [];
|
|
297
292
|
for (const item of value) {
|
|
298
293
|
if (item instanceof targetClass) {
|
|
@@ -310,15 +305,13 @@ export async function mapClassesAsync<T = Record<string, any>>(
|
|
|
310
305
|
}
|
|
311
306
|
}
|
|
312
307
|
target[prop] = arr as any;
|
|
313
|
-
}
|
|
314
308
|
|
|
315
|
-
|
|
316
|
-
else if (value instanceof Types.ObjectId) {
|
|
309
|
+
// Process ObjectId
|
|
310
|
+
} else if (value instanceof Types.ObjectId) {
|
|
317
311
|
target[prop] = config.objectIdsToString ? value.toHexString() : value;
|
|
318
|
-
}
|
|
319
312
|
|
|
320
|
-
|
|
321
|
-
else if (typeof value === 'object') {
|
|
313
|
+
// Process object
|
|
314
|
+
} else if (typeof value === 'object') {
|
|
322
315
|
if (value instanceof targetClass) {
|
|
323
316
|
target[prop] = value as any;
|
|
324
317
|
} else {
|
|
@@ -328,10 +321,9 @@ export async function mapClassesAsync<T = Record<string, any>>(
|
|
|
328
321
|
target[prop] = plainToInstance(targetClass, value) as any;
|
|
329
322
|
}
|
|
330
323
|
}
|
|
331
|
-
}
|
|
332
324
|
|
|
333
|
-
|
|
334
|
-
else if (!config.removeUndefinedProperties || value !== undefined) {
|
|
325
|
+
// Others
|
|
326
|
+
} else if (!config.removeUndefinedProperties || value !== undefined) {
|
|
335
327
|
target[prop] = value;
|
|
336
328
|
}
|
|
337
329
|
}
|
|
@@ -347,14 +339,14 @@ export function mapInputClasses<T = Record<string, any>>(
|
|
|
347
339
|
input: Record<string, any>,
|
|
348
340
|
mapping: Record<string, new (...args: any[]) => any>,
|
|
349
341
|
target?: T,
|
|
350
|
-
options?: { objectIdsToString?: boolean; removeUndefinedProperties?: boolean }
|
|
342
|
+
options?: { objectIdsToString?: boolean; removeUndefinedProperties?: boolean },
|
|
351
343
|
) {
|
|
352
344
|
// Get config
|
|
353
345
|
const config = {
|
|
354
346
|
removeUndefinedProperties: true,
|
|
355
347
|
...options,
|
|
356
348
|
};
|
|
357
|
-
return mapClasses(input, mapping, target,
|
|
349
|
+
return mapClasses(input, mapping, target, config);
|
|
358
350
|
}
|
|
359
351
|
|
|
360
352
|
/**
|
|
@@ -364,12 +356,12 @@ export function mapInputClassesAsync<T = Record<string, any>>(
|
|
|
364
356
|
input: Record<string, any>,
|
|
365
357
|
mapping: Record<string, new (...args: any[]) => any>,
|
|
366
358
|
target?: T,
|
|
367
|
-
options?: { objectIdsToString?: boolean; removeUndefinedProperties?: boolean }
|
|
359
|
+
options?: { objectIdsToString?: boolean; removeUndefinedProperties?: boolean },
|
|
368
360
|
) {
|
|
369
361
|
// Get config
|
|
370
362
|
const config = {
|
|
371
363
|
removeUndefinedProperties: true,
|
|
372
364
|
...options,
|
|
373
365
|
};
|
|
374
|
-
return mapClassesAsync(input, mapping, target,
|
|
366
|
+
return mapClassesAsync(input, mapping, target, config);
|
|
375
367
|
}
|