@lenne.tech/nest-server 11.0.1 → 11.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/core/common/args/filter.args.js +6 -8
- package/dist/core/common/args/filter.args.js.map +1 -1
- package/dist/core/common/args/pagination.args.js +16 -16
- package/dist/core/common/args/pagination.args.js.map +1 -1
- package/dist/core/common/decorators/restricted.decorator.js +1 -1
- package/dist/core/common/decorators/restricted.decorator.js.map +1 -1
- package/dist/core/common/decorators/unified-field.decorator.d.ts +25 -0
- package/dist/core/common/decorators/unified-field.decorator.js +167 -0
- package/dist/core/common/decorators/unified-field.decorator.js.map +1 -0
- package/dist/core/common/helpers/config.helper.js +1 -1
- package/dist/core/common/helpers/config.helper.js.map +1 -1
- package/dist/core/common/helpers/db.helper.js +1 -1
- package/dist/core/common/helpers/db.helper.js.map +1 -1
- package/dist/core/common/helpers/graphql.helper.js.map +1 -1
- package/dist/core/common/helpers/input.helper.js +2 -2
- package/dist/core/common/helpers/input.helper.js.map +1 -1
- package/dist/core/common/helpers/service.helper.js +33 -12
- package/dist/core/common/helpers/service.helper.js.map +1 -1
- package/dist/core/common/inputs/combined-filter.input.js +8 -4
- package/dist/core/common/inputs/combined-filter.input.js.map +1 -1
- package/dist/core/common/inputs/filter.input.js +10 -7
- package/dist/core/common/inputs/filter.input.js.map +1 -1
- package/dist/core/common/inputs/single-filter.input.js +26 -18
- package/dist/core/common/inputs/single-filter.input.js.map +1 -1
- package/dist/core/common/inputs/sort.input.js +10 -4
- package/dist/core/common/inputs/sort.input.js.map +1 -1
- package/dist/core/common/models/core-persistence.model.d.ts +2 -0
- package/dist/core/common/models/core-persistence.model.js +40 -11
- package/dist/core/common/models/core-persistence.model.js.map +1 -1
- package/dist/core/common/pipes/map-and-validate.pipe.js +12 -3
- package/dist/core/common/pipes/map-and-validate.pipe.js.map +1 -1
- package/dist/core/common/services/brevo.service.js +1 -1
- package/dist/core/common/services/brevo.service.js.map +1 -1
- package/dist/core/common/services/config.service.js +1 -1
- package/dist/core/common/services/config.service.js.map +1 -1
- package/dist/core/common/services/email.service.js +1 -1
- package/dist/core/common/services/email.service.js.map +1 -1
- package/dist/core/common/services/model-doc.service.js +1 -1
- package/dist/core/common/services/model-doc.service.js.map +1 -1
- package/dist/core/common/services/module.service.js +1 -1
- package/dist/core/common/services/module.service.js.map +1 -1
- package/dist/core/common/services/template.service.js +2 -2
- package/dist/core/common/services/template.service.js.map +1 -1
- package/dist/core/modules/auth/core-auth.model.js +10 -11
- package/dist/core/modules/auth/core-auth.model.js.map +1 -1
- package/dist/core/modules/auth/guards/auth.guard.js +1 -1
- package/dist/core/modules/auth/guards/auth.guard.js.map +1 -1
- package/dist/core/modules/auth/inputs/core-auth-sign-in.input.js +25 -21
- package/dist/core/modules/auth/inputs/core-auth-sign-in.input.js.map +1 -1
- package/dist/core/modules/auth/services/core-auth.service.js +1 -1
- package/dist/core/modules/auth/services/core-auth.service.js.map +1 -1
- package/dist/core/modules/health-check/core-health-check-result.model.js +18 -11
- package/dist/core/modules/health-check/core-health-check-result.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-create.input.js +6 -3
- package/dist/core/modules/user/inputs/core-user-create.input.js.map +1 -1
- package/dist/core/modules/user/inputs/core-user.input.js +32 -18
- package/dist/core/modules/user/inputs/core-user.input.js.map +1 -1
- package/dist/core.module.js +1 -1
- package/dist/core.module.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/main.js +2 -2
- package/dist/main.js.map +1 -1
- package/dist/server/common/models/persistence.model.js +1 -1
- package/dist/server/common/models/persistence.model.js.map +1 -1
- package/dist/server/modules/auth/inputs/auth-sign-up.input.js +11 -4
- package/dist/server/modules/auth/inputs/auth-sign-up.input.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/user/outputs/find-and-count-users-result.output.js +11 -4
- package/dist/server/modules/user/outputs/find-and-count-users-result.output.js.map +1 -1
- package/dist/server/modules/user/user.model.js +2 -0
- package/dist/server/modules/user/user.model.js.map +1 -1
- package/dist/server/modules/user/user.service.js +1 -1
- package/dist/server/modules/user/user.service.js.map +1 -1
- package/dist/test/test.helper.js +1 -1
- package/dist/test/test.helper.js.map +1 -1
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/package.json +25 -25
- package/src/core/common/args/filter.args.ts +7 -10
- package/src/core/common/args/pagination.args.ts +17 -17
- package/src/core/common/decorators/restricted.decorator.ts +1 -2
- package/src/core/common/decorators/unified-field.decorator.ts +269 -0
- package/src/core/common/helpers/config.helper.ts +1 -4
- package/src/core/common/helpers/db.helper.ts +1 -2
- package/src/core/common/helpers/graphql.helper.ts +0 -1
- package/src/core/common/helpers/input.helper.ts +2 -3
- package/src/core/common/helpers/service.helper.ts +39 -14
- package/src/core/common/inputs/combined-filter.input.ts +9 -5
- package/src/core/common/inputs/filter.input.ts +14 -11
- package/src/core/common/inputs/single-filter.input.ts +28 -19
- package/src/core/common/inputs/sort.input.ts +11 -5
- package/src/core/common/models/core-persistence.model.ts +38 -12
- package/src/core/common/pipes/map-and-validate.pipe.ts +15 -4
- package/src/core/common/services/brevo.service.ts +1 -2
- package/src/core/common/services/config.service.ts +1 -2
- package/src/core/common/services/email.service.ts +1 -2
- package/src/core/common/services/model-doc.service.ts +1 -2
- package/src/core/common/services/module.service.ts +1 -2
- package/src/core/common/services/template.service.ts +2 -3
- package/src/core/modules/auth/core-auth.model.ts +11 -12
- package/src/core/modules/auth/guards/auth.guard.ts +1 -2
- package/src/core/modules/auth/inputs/core-auth-sign-in.input.ts +27 -23
- package/src/core/modules/auth/services/core-auth.service.ts +1 -2
- package/src/core/modules/health-check/core-health-check-result.model.ts +19 -12
- package/src/core/modules/user/core-user.service.ts +2 -3
- package/src/core/modules/user/inputs/core-user-create.input.ts +7 -4
- package/src/core/modules/user/inputs/core-user.input.ts +34 -20
- package/src/core.module.ts +1 -2
- package/src/index.ts +1 -0
- package/src/main.ts +2 -3
- package/src/server/common/models/persistence.model.ts +1 -2
- package/src/server/modules/auth/inputs/auth-sign-up.input.ts +12 -5
- package/src/server/modules/file/file.resolver.ts +2 -3
- package/src/server/modules/user/outputs/find-and-count-users-result.output.ts +12 -5
- package/src/server/modules/user/user.model.ts +2 -0
- package/src/server/modules/user/user.service.ts +1 -2
- package/src/test/test.helper.ts +2 -3
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lenne.tech/nest-server",
|
|
3
|
-
"version": "11.
|
|
3
|
+
"version": "11.1.1",
|
|
4
4
|
"description": "Modern, fast, powerful Node.js web framework in TypeScript based on Nest with a GraphQL API and a connection to MongoDB (or other databases).",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"node",
|
|
@@ -22,8 +22,8 @@
|
|
|
22
22
|
"docs:ci": "ts-node ./scripts/init-server.ts && npm run docs:bootstrap && compodoc -p tsconfig.json",
|
|
23
23
|
"format": "prettier --write 'src/**/*.ts'",
|
|
24
24
|
"format:staged": "pretty-quick --staged",
|
|
25
|
-
"lint": "eslint '{src,apps,libs,
|
|
26
|
-
"lint:fix": "eslint '{src,apps,libs,
|
|
25
|
+
"lint": "eslint '{src,apps,libs,tests}/**/*.{ts,js}' --cache",
|
|
26
|
+
"lint:fix": "eslint '{src,apps,libs,tests}/**/*.{ts,js}' --fix --cache",
|
|
27
27
|
"prestart:prod": "npm run build",
|
|
28
28
|
"reinit": "rimraf package-lock.json && rimraf node_modules && npm i && npm run lint && npm run test:e2e && npm run test:ci && npm run build",
|
|
29
29
|
"reinit:clean": "rimraf package-lock.json && rimraf node_modules && npm cache clean --force && npm i && npm run test:e2e && npm run build",
|
|
@@ -70,26 +70,26 @@
|
|
|
70
70
|
"@lenne.tech/mongoose-gridfs": "1.4.2",
|
|
71
71
|
"@lenne.tech/multer-gridfs-storage": "5.0.6",
|
|
72
72
|
"@nestjs/apollo": "13.1.0",
|
|
73
|
-
"@nestjs/common": "11.0
|
|
74
|
-
"@nestjs/core": "11.0
|
|
73
|
+
"@nestjs/common": "11.1.0",
|
|
74
|
+
"@nestjs/core": "11.1.0",
|
|
75
75
|
"@nestjs/graphql": "13.1.0",
|
|
76
76
|
"@nestjs/jwt": "11.0.0",
|
|
77
77
|
"@nestjs/mongoose": "11.0.3",
|
|
78
78
|
"@nestjs/passport": "11.0.5",
|
|
79
|
-
"@nestjs/platform-express": "11.0
|
|
80
|
-
"@nestjs/schedule": "
|
|
81
|
-
"@nestjs/swagger": "11.
|
|
79
|
+
"@nestjs/platform-express": "11.1.0",
|
|
80
|
+
"@nestjs/schedule": "6.0.0",
|
|
81
|
+
"@nestjs/swagger": "11.2.0",
|
|
82
82
|
"@nestjs/terminus": "11.0.0",
|
|
83
83
|
"apollo-server-core": "3.13.0",
|
|
84
84
|
"apollo-server-express": "3.13.0",
|
|
85
85
|
"bcrypt": "5.1.1",
|
|
86
86
|
"class-transformer": "0.5.1",
|
|
87
|
-
"class-validator": "0.14.
|
|
87
|
+
"class-validator": "0.14.2",
|
|
88
88
|
"compression": "1.8.0",
|
|
89
89
|
"cookie-parser": "1.4.7",
|
|
90
90
|
"dotenv": "16.5.0",
|
|
91
91
|
"ejs": "3.1.10",
|
|
92
|
-
"graphql": "16.
|
|
92
|
+
"graphql": "16.11.0",
|
|
93
93
|
"graphql-query-complexity": "1.1.0",
|
|
94
94
|
"graphql-subscriptions": "3.0.0",
|
|
95
95
|
"graphql-upload": "15.0.2",
|
|
@@ -97,12 +97,12 @@
|
|
|
97
97
|
"json-to-graphql-query": "2.3.0",
|
|
98
98
|
"light-my-request": "6.6.0",
|
|
99
99
|
"lodash": "4.17.21",
|
|
100
|
-
"mongodb": "6.
|
|
101
|
-
"mongoose": "7.8.
|
|
100
|
+
"mongodb": "6.16.0",
|
|
101
|
+
"mongoose": "7.8.7",
|
|
102
102
|
"multer": "1.4.5-lts.2",
|
|
103
103
|
"node-mailjet": "6.0.8",
|
|
104
|
-
"nodemailer": "
|
|
105
|
-
"nodemon": "3.1.
|
|
104
|
+
"nodemailer": "7.0.3",
|
|
105
|
+
"nodemon": "3.1.10",
|
|
106
106
|
"passport": "0.7.0",
|
|
107
107
|
"passport-jwt": "4.0.1",
|
|
108
108
|
"reflect-metadata": "0.2.2",
|
|
@@ -114,13 +114,13 @@
|
|
|
114
114
|
"devDependencies": {
|
|
115
115
|
"@babel/plugin-proposal-private-methods": "7.18.6",
|
|
116
116
|
"@compodoc/compodoc": "1.1.26",
|
|
117
|
-
"@lenne.tech/eslint-config-ts": "
|
|
118
|
-
"@nestjs/cli": "11.0.
|
|
117
|
+
"@lenne.tech/eslint-config-ts": "2.0.1",
|
|
118
|
+
"@nestjs/cli": "11.0.7",
|
|
119
119
|
"@nestjs/schematics": "11.0.5",
|
|
120
|
-
"@nestjs/testing": "11.0
|
|
121
|
-
"@swc/cli": "0.
|
|
122
|
-
"@swc/core": "1.11.
|
|
123
|
-
"@swc/jest": "0.2.
|
|
120
|
+
"@nestjs/testing": "11.1.0",
|
|
121
|
+
"@swc/cli": "0.7.5",
|
|
122
|
+
"@swc/core": "1.11.24",
|
|
123
|
+
"@swc/jest": "0.2.38",
|
|
124
124
|
"@types/compression": "1.7.5",
|
|
125
125
|
"@types/cookie-parser": "1.4.8",
|
|
126
126
|
"@types/ejs": "3.1.5",
|
|
@@ -128,15 +128,15 @@
|
|
|
128
128
|
"@types/jest": "29.5.14",
|
|
129
129
|
"@types/lodash": "4.17.16",
|
|
130
130
|
"@types/multer": "1.4.12",
|
|
131
|
-
"@types/node": "22.
|
|
131
|
+
"@types/node": "22.15.17",
|
|
132
132
|
"@types/nodemailer": "6.4.17",
|
|
133
133
|
"@types/passport": "1.0.17",
|
|
134
134
|
"@types/supertest": "6.0.3",
|
|
135
|
-
"@typescript-eslint/eslint-plugin": "8.
|
|
136
|
-
"@typescript-eslint/parser": "8.
|
|
135
|
+
"@typescript-eslint/eslint-plugin": "8.32.0",
|
|
136
|
+
"@typescript-eslint/parser": "8.32.0",
|
|
137
137
|
"coffeescript": "2.7.0",
|
|
138
|
-
"eslint": "9.
|
|
139
|
-
"eslint-config-prettier": "10.1.
|
|
138
|
+
"eslint": "9.26.0",
|
|
139
|
+
"eslint-config-prettier": "10.1.5",
|
|
140
140
|
"eslint-plugin-unused-imports": "4.1.4",
|
|
141
141
|
"find-file-up": "2.0.1",
|
|
142
142
|
"grunt": "1.6.1",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { ArgsType
|
|
2
|
-
import { IsOptional } from 'class-validator';
|
|
1
|
+
import { ArgsType } from '@nestjs/graphql';
|
|
3
2
|
|
|
3
|
+
import { UnifiedField } from '../decorators/unified-field.decorator';
|
|
4
4
|
import { FilterInput } from '../inputs/filter.input';
|
|
5
5
|
import { PaginationArgs } from './pagination.args';
|
|
6
6
|
|
|
@@ -9,20 +9,17 @@ export class FilterArgs extends PaginationArgs {
|
|
|
9
9
|
/**
|
|
10
10
|
* Filtering
|
|
11
11
|
*/
|
|
12
|
-
@
|
|
13
|
-
|
|
14
|
-
|
|
12
|
+
@UnifiedField({
|
|
13
|
+
isOptional: true,
|
|
14
|
+
type: FilterInput,
|
|
15
15
|
})
|
|
16
|
-
@IsOptional()
|
|
17
16
|
filter?: FilterInput = undefined;
|
|
18
17
|
|
|
19
18
|
/**
|
|
20
19
|
* Get a specific number of random samples from filter results
|
|
21
20
|
*/
|
|
22
|
-
@
|
|
23
|
-
|
|
24
|
-
'Request only a specified number of samples from the filter results; if not specified, all results are returned.',
|
|
25
|
-
nullable: true,
|
|
21
|
+
@UnifiedField({
|
|
22
|
+
isOptional: true,
|
|
26
23
|
})
|
|
27
24
|
samples?: number = undefined;
|
|
28
25
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { ArgsType,
|
|
2
|
-
import { IsOptional } from 'class-validator';
|
|
1
|
+
import { ArgsType, Int } from '@nestjs/graphql';
|
|
3
2
|
|
|
3
|
+
import { UnifiedField } from '../decorators/unified-field.decorator';
|
|
4
4
|
import { maps } from '../helpers/model.helper';
|
|
5
5
|
import { CoreInput } from '../inputs/core-input.input';
|
|
6
6
|
import { SortInput } from '../inputs/sort.input';
|
|
@@ -10,51 +10,51 @@ export class PaginationArgs extends CoreInput {
|
|
|
10
10
|
/**
|
|
11
11
|
* Limit for pagination
|
|
12
12
|
*/
|
|
13
|
-
@
|
|
13
|
+
@UnifiedField({
|
|
14
14
|
description: 'Limit specifies the maximum number of elements found that are to be returned',
|
|
15
|
-
|
|
15
|
+
isOptional: true,
|
|
16
|
+
type: Int,
|
|
16
17
|
})
|
|
17
|
-
@IsOptional()
|
|
18
18
|
limit?: number = undefined;
|
|
19
19
|
|
|
20
20
|
/**
|
|
21
21
|
* Alias for skip
|
|
22
22
|
*/
|
|
23
|
-
@
|
|
23
|
+
@UnifiedField({
|
|
24
24
|
description: 'Alias for skip',
|
|
25
|
-
|
|
25
|
+
isOptional: true,
|
|
26
|
+
type: Int,
|
|
26
27
|
})
|
|
27
|
-
@IsOptional()
|
|
28
28
|
offset?: number = undefined;
|
|
29
29
|
|
|
30
30
|
/**
|
|
31
31
|
* Skip for pagination
|
|
32
32
|
*/
|
|
33
|
-
@
|
|
33
|
+
@UnifiedField({
|
|
34
34
|
description: 'Skip specifies how many found elements should be skipped on return',
|
|
35
|
-
|
|
35
|
+
isOptional: true,
|
|
36
|
+
type: Int,
|
|
36
37
|
})
|
|
37
|
-
@IsOptional()
|
|
38
38
|
skip?: number = undefined;
|
|
39
39
|
|
|
40
40
|
/**
|
|
41
41
|
* Sorting for pagination
|
|
42
42
|
*/
|
|
43
|
-
@
|
|
43
|
+
@UnifiedField({
|
|
44
44
|
description: 'Sorting the returned elements',
|
|
45
|
-
|
|
45
|
+
isOptional: true,
|
|
46
|
+
type: () => SortInput,
|
|
46
47
|
})
|
|
47
|
-
@IsOptional()
|
|
48
48
|
sort?: SortInput[] = undefined;
|
|
49
49
|
|
|
50
50
|
/**
|
|
51
51
|
* Alias for limit
|
|
52
52
|
*/
|
|
53
|
-
@
|
|
53
|
+
@UnifiedField({
|
|
54
54
|
description: 'Alias for limit',
|
|
55
|
-
|
|
55
|
+
isOptional: true,
|
|
56
|
+
type: () => Int,
|
|
56
57
|
})
|
|
57
|
-
@IsOptional()
|
|
58
58
|
take?: number = undefined;
|
|
59
59
|
|
|
60
60
|
// ===================================================================================================================
|
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
import { UnauthorizedException } from '@nestjs/common';
|
|
2
2
|
import 'reflect-metadata';
|
|
3
|
+
import _ = require('lodash');
|
|
3
4
|
|
|
4
5
|
import { ProcessType } from '../enums/process-type.enum';
|
|
5
6
|
import { RoleEnum } from '../enums/role.enum';
|
|
6
7
|
import { equalIds, getIncludedIds } from '../helpers/db.helper';
|
|
7
8
|
import { RequireAtLeastOne } from '../types/required-at-least-one.type';
|
|
8
9
|
|
|
9
|
-
import _ = require('lodash');
|
|
10
|
-
|
|
11
10
|
/**
|
|
12
11
|
* Restricted meta key
|
|
13
12
|
*/
|
|
@@ -0,0 +1,269 @@
|
|
|
1
|
+
import { Field, FieldOptions } from '@nestjs/graphql';
|
|
2
|
+
import { ApiProperty, ApiPropertyOptions } from '@nestjs/swagger';
|
|
3
|
+
import { EnumAllowedTypes } from '@nestjs/swagger/dist/interfaces/schema-object-metadata.interface';
|
|
4
|
+
import { Type } from 'class-transformer';
|
|
5
|
+
import {
|
|
6
|
+
IsArray,
|
|
7
|
+
IsBoolean,
|
|
8
|
+
IsDate,
|
|
9
|
+
IsEnum,
|
|
10
|
+
IsNotEmpty,
|
|
11
|
+
IsNumber,
|
|
12
|
+
IsObject,
|
|
13
|
+
IsOptional,
|
|
14
|
+
IsString,
|
|
15
|
+
ValidateIf,
|
|
16
|
+
ValidateNested,
|
|
17
|
+
ValidationOptions,
|
|
18
|
+
} from 'class-validator';
|
|
19
|
+
import { GraphQLScalarType } from 'graphql';
|
|
20
|
+
|
|
21
|
+
import { RoleEnum } from '../enums/role.enum';
|
|
22
|
+
import { Restricted, RestrictedType } from './restricted.decorator';
|
|
23
|
+
|
|
24
|
+
export interface UnifiedFieldOptions {
|
|
25
|
+
/**
|
|
26
|
+
* Indicates whether the property is an array.
|
|
27
|
+
*
|
|
28
|
+
* This value is typically determined automatically based on the property type or metadata.
|
|
29
|
+
*
|
|
30
|
+
* However, cases involving complex or dynamic type definitions (e.g., union types, generics, or factory functions)
|
|
31
|
+
* may result in inaccurate detection.
|
|
32
|
+
*
|
|
33
|
+
* When in doubt, explicitly set this property to ensure correct behavior.
|
|
34
|
+
*/
|
|
35
|
+
array?: boolean;
|
|
36
|
+
/** Description used for both Swagger & Gql */
|
|
37
|
+
description?: string;
|
|
38
|
+
/** Enum for class-validator */
|
|
39
|
+
enum?: { enum: EnumAllowedTypes; options?: ValidationOptions };
|
|
40
|
+
/** Example value for swagger api documentation */
|
|
41
|
+
example?: any;
|
|
42
|
+
/** Options for graphql */
|
|
43
|
+
gqlOptions?: FieldOptions;
|
|
44
|
+
/** Default: false */
|
|
45
|
+
isOptional?: boolean;
|
|
46
|
+
/** Restricted roles */
|
|
47
|
+
roles?: RestrictedType | RoleEnum | RoleEnum[];
|
|
48
|
+
/** Options for swagger api documentation */
|
|
49
|
+
swaggerApiOptions?: ApiPropertyOptions;
|
|
50
|
+
/** Type of the field, if not specified, it will be determined automatically.
|
|
51
|
+
*
|
|
52
|
+
* Required if the field is an array (inferred automatically or via the array flag).
|
|
53
|
+
*
|
|
54
|
+
* Enums should be defined via the enum option.
|
|
55
|
+
*
|
|
56
|
+
* Supports:
|
|
57
|
+
* - A factory function that returns the type: `() => MyType`
|
|
58
|
+
* - A GraphQL scalar: `GraphQLScalarType`
|
|
59
|
+
* - A class constructor: `MyClass`
|
|
60
|
+
* */
|
|
61
|
+
type?: (() => any) | GraphQLScalarType | (new (...args: any[]) => any) | Record<number | string, number | string>; // Enums;
|
|
62
|
+
/** Condition for validation */
|
|
63
|
+
validateIf?: (obj: any, val: any) => boolean;
|
|
64
|
+
/** Validation options for class-validator */
|
|
65
|
+
validationOptions?: ValidationOptions;
|
|
66
|
+
/** Custom validators, when using this option, all built-in validators are ignored */
|
|
67
|
+
validator?: (opts: ValidationOptions) => PropertyDecorator[];
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export function UnifiedField(opts: UnifiedFieldOptions = {}): PropertyDecorator {
|
|
71
|
+
return (target: any, propertyKey: string | symbol) => {
|
|
72
|
+
const metadataType = Reflect.getMetadata('design:type', target, propertyKey);
|
|
73
|
+
const userType = opts.type;
|
|
74
|
+
const isArrayField = opts.array === true || metadataType === Array;
|
|
75
|
+
|
|
76
|
+
// Throwing because metatype only returns the generic array, but not the type of the array items
|
|
77
|
+
if (metadataType === Array && !userType) {
|
|
78
|
+
throw new Error(`Array field '${String(propertyKey)}' of '${String(target)}' must have an explicit type`);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
if (opts.enum && userType) {
|
|
82
|
+
throw new Error(`Can't set both enum and type of ${String(propertyKey)} in ${target.constructor.name}`);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
const resolvedTypeFn = (): any => {
|
|
86
|
+
if (opts.enum?.enum) {
|
|
87
|
+
return opts.enum.enum; // Ensure enums are handled directly
|
|
88
|
+
}
|
|
89
|
+
if (userType) {
|
|
90
|
+
if (userType instanceof GraphQLScalarType) { // Case if it's a scalar
|
|
91
|
+
return userType;
|
|
92
|
+
}
|
|
93
|
+
if (
|
|
94
|
+
typeof userType === 'function'
|
|
95
|
+
&& userType.prototype
|
|
96
|
+
&& userType.prototype.constructor === userType
|
|
97
|
+
) { // Case if it's a function
|
|
98
|
+
return userType;
|
|
99
|
+
}
|
|
100
|
+
try { // case if its a factory
|
|
101
|
+
return (userType as () => any)();
|
|
102
|
+
} catch {
|
|
103
|
+
return userType;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
return metadataType;
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
const baseType = resolvedTypeFn();
|
|
110
|
+
|
|
111
|
+
// Prepare merged options
|
|
112
|
+
const gqlOpts: FieldOptions = { ...opts.gqlOptions };
|
|
113
|
+
const swaggerOpts: ApiPropertyOptions = { ...opts.swaggerApiOptions };
|
|
114
|
+
const valOpts: ValidationOptions = { ...opts.validationOptions };
|
|
115
|
+
|
|
116
|
+
// Optionality
|
|
117
|
+
if (opts.isOptional) {
|
|
118
|
+
gqlOpts.nullable = true;
|
|
119
|
+
swaggerOpts.nullable = true;
|
|
120
|
+
} else {
|
|
121
|
+
gqlOpts.nullable = false;
|
|
122
|
+
swaggerOpts.nullable = false;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// Description
|
|
126
|
+
const defaultDesc = opts.description ?? `${String(propertyKey)} of ${target.constructor.name}`;
|
|
127
|
+
gqlOpts.description = gqlOpts.description ?? defaultDesc;
|
|
128
|
+
swaggerOpts.description = swaggerOpts.description ?? defaultDesc;
|
|
129
|
+
|
|
130
|
+
// Swagger example
|
|
131
|
+
if (opts.example !== undefined) {
|
|
132
|
+
swaggerOpts.example = swaggerOpts.example ?? opts.example;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
if (opts.enum && opts.enum.enum) {
|
|
136
|
+
swaggerOpts.enum = opts.enum.enum;
|
|
137
|
+
}
|
|
138
|
+
// Array handling
|
|
139
|
+
if (isArrayField) {
|
|
140
|
+
swaggerOpts.isArray = true;
|
|
141
|
+
IsArray(valOpts)(target, propertyKey);
|
|
142
|
+
valOpts.each = true;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
if (opts.isOptional) {
|
|
146
|
+
IsOptional(valOpts)(target, propertyKey);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// Type function for gql
|
|
150
|
+
const gqlTypeFn = isArrayField
|
|
151
|
+
? () => [opts.enum?.enum || resolvedTypeFn()]
|
|
152
|
+
: () => opts.enum?.enum || resolvedTypeFn();
|
|
153
|
+
|
|
154
|
+
// Gql decorator
|
|
155
|
+
Field(gqlTypeFn, gqlOpts)(target, propertyKey);
|
|
156
|
+
|
|
157
|
+
// Trims keys with 'undefined' properties.
|
|
158
|
+
function trimUndefined<T>(obj: T): Partial<T> {
|
|
159
|
+
if (typeof obj !== 'object' || obj === null) {
|
|
160
|
+
return obj;
|
|
161
|
+
}
|
|
162
|
+
const result: any = Array.isArray(obj) ? [] : {};
|
|
163
|
+
for (const key in obj) {
|
|
164
|
+
if (Object.prototype.hasOwnProperty.call(obj, key)) {
|
|
165
|
+
const value = (obj as any)[key];
|
|
166
|
+
|
|
167
|
+
if (typeof value === 'object' && value !== null) {
|
|
168
|
+
const cleaned = trimUndefined(value);
|
|
169
|
+
if (Array.isArray(cleaned) ? cleaned.length > 0 : Object.keys(cleaned).length > 0) {
|
|
170
|
+
result[key] = cleaned;
|
|
171
|
+
}
|
|
172
|
+
} else if (value !== undefined) {
|
|
173
|
+
result[key] = value;
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
return result;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
ApiProperty(trimUndefined({
|
|
182
|
+
deprecated: swaggerOpts.deprecated,
|
|
183
|
+
description: swaggerOpts.description,
|
|
184
|
+
enum: swaggerOpts.enum,
|
|
185
|
+
example: swaggerOpts.example,
|
|
186
|
+
examples: swaggerOpts.examples,
|
|
187
|
+
isArray: swaggerOpts.isArray,
|
|
188
|
+
nullable: swaggerOpts.nullable,
|
|
189
|
+
pattern: swaggerOpts.pattern,
|
|
190
|
+
type: () => resolvedTypeFn(),
|
|
191
|
+
}))(target, propertyKey);
|
|
192
|
+
|
|
193
|
+
// Conditional validation
|
|
194
|
+
if (opts.validateIf) {
|
|
195
|
+
ValidateIf(opts.validateIf)(target, propertyKey);
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
// isOptional validation
|
|
199
|
+
if (opts.isOptional) {
|
|
200
|
+
IsOptional()(target, propertyKey);
|
|
201
|
+
} else {
|
|
202
|
+
IsNotEmpty()(target, propertyKey);
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
// Custom or builtin validator
|
|
206
|
+
if (opts.validator) {
|
|
207
|
+
opts.validator(valOpts).forEach(d => d(target, propertyKey));
|
|
208
|
+
} else {
|
|
209
|
+
const validator = getBuiltInValidator(baseType, valOpts, isArrayField, target);
|
|
210
|
+
if (validator) {
|
|
211
|
+
validator(target, propertyKey);
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
// Enum validation
|
|
216
|
+
if (opts.enum) {
|
|
217
|
+
IsEnum(opts.enum.enum, opts.enum.options)(target, propertyKey);
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
// Check if it's a primitive, if not apply transform
|
|
221
|
+
if (!isPrimitive(baseType) && !opts.enum && !isGraphQLScalar(baseType)) {
|
|
222
|
+
Type(() => baseType)(target, propertyKey);
|
|
223
|
+
ValidateNested({ each: isArrayField })(target, propertyKey);
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
// Roles
|
|
227
|
+
if (opts.roles) {
|
|
228
|
+
const rolesArr = Array.isArray(opts.roles) ? opts.roles : [opts.roles];
|
|
229
|
+
Restricted(...rolesArr)(target, propertyKey);
|
|
230
|
+
}
|
|
231
|
+
};
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
function getBuiltInValidator(
|
|
235
|
+
type: any,
|
|
236
|
+
opts: ValidationOptions,
|
|
237
|
+
each: boolean,
|
|
238
|
+
target: any,
|
|
239
|
+
): ((t: any, k: string | symbol) => void) | null {
|
|
240
|
+
const map = new Map<any, PropertyDecorator>([
|
|
241
|
+
[Boolean, IsBoolean(opts)],
|
|
242
|
+
[Date, IsDate(opts)],
|
|
243
|
+
[Number, IsNumber({}, opts)],
|
|
244
|
+
[Object, IsObject(opts)],
|
|
245
|
+
[String, IsString(opts)],
|
|
246
|
+
]);
|
|
247
|
+
const decorator = map.get(type);
|
|
248
|
+
if (!decorator) {
|
|
249
|
+
return null;
|
|
250
|
+
}
|
|
251
|
+
if (each) {
|
|
252
|
+
return (t, k) => decorator(target, k);
|
|
253
|
+
}
|
|
254
|
+
return decorator;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
function isGraphQLScalar(type: any): boolean {
|
|
258
|
+
// CustomScalar check (The CustomScalar interface implements these functions below)
|
|
259
|
+
return type
|
|
260
|
+
&& typeof type === 'function'
|
|
261
|
+
&& typeof type.prototype?.serialize === 'function'
|
|
262
|
+
&& typeof type.prototype?.parseValue === 'function'
|
|
263
|
+
&& typeof type.prototype?.parseLiteral === 'function'
|
|
264
|
+
|| type instanceof GraphQLScalarType;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
function isPrimitive(fn: any): boolean {
|
|
268
|
+
return [Boolean, Date, Number, String].includes(fn);
|
|
269
|
+
}
|
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import * as dotenv from 'dotenv';
|
|
2
|
+
import _ = require('lodash');
|
|
2
3
|
import * as process from 'node:process';
|
|
3
4
|
import { join } from 'path';
|
|
4
5
|
|
|
5
|
-
import _ = require('lodash');
|
|
6
|
-
|
|
7
6
|
/**
|
|
8
7
|
* Helper class for configurations
|
|
9
8
|
* @deprecated use functions directly
|
|
@@ -28,8 +27,6 @@ export default class Config {
|
|
|
28
27
|
}
|
|
29
28
|
}
|
|
30
29
|
|
|
31
|
-
|
|
32
|
-
|
|
33
30
|
/**
|
|
34
31
|
* Get environment configuration (deeply merged into config object set via options)
|
|
35
32
|
*
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { FieldNode, GraphQLResolveInfo, SelectionNode } from 'graphql';
|
|
2
|
+
import _ = require('lodash');
|
|
2
3
|
import { Document, Model, PopulateOptions, Query, Types } from 'mongoose';
|
|
3
4
|
|
|
4
5
|
import { ResolveSelector } from '../interfaces/resolve-selector.interface';
|
|
@@ -8,8 +9,6 @@ import { IdsType } from '../types/ids.type';
|
|
|
8
9
|
import { StringOrObjectId } from '../types/string-or-object-id.type';
|
|
9
10
|
import { removePropertiesDeep } from './input.helper';
|
|
10
11
|
|
|
11
|
-
import _ = require('lodash');
|
|
12
|
-
|
|
13
12
|
// =====================================================================================================================
|
|
14
13
|
// Export functions
|
|
15
14
|
// =====================================================================================================================
|
|
@@ -4,6 +4,8 @@ import { validate } from 'class-validator';
|
|
|
4
4
|
import { ValidatorOptions } from 'class-validator/types/validation/ValidatorOptions';
|
|
5
5
|
import { Kind } from 'graphql/index';
|
|
6
6
|
import * as inspector from 'inspector';
|
|
7
|
+
import _ = require('lodash');
|
|
8
|
+
import rfdc = require('rfdc');
|
|
7
9
|
import * as util from 'util';
|
|
8
10
|
|
|
9
11
|
import { checkRestricted } from '../decorators/restricted.decorator';
|
|
@@ -12,9 +14,6 @@ import { RoleEnum } from '../enums/role.enum';
|
|
|
12
14
|
import { merge } from './config.helper';
|
|
13
15
|
import { equalIds } from './db.helper';
|
|
14
16
|
|
|
15
|
-
import _ = require('lodash');
|
|
16
|
-
import rfdc = require('rfdc');
|
|
17
|
-
|
|
18
17
|
/**
|
|
19
18
|
* Helper class for inputs
|
|
20
19
|
* @deprecated use functions directly
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { UnauthorizedException } from '@nestjs/common';
|
|
2
|
+
import bcrypt = require('bcrypt');
|
|
2
3
|
import { plainToInstance } from 'class-transformer';
|
|
3
4
|
import { sha256 } from 'js-sha256';
|
|
5
|
+
import _ = require('lodash');
|
|
4
6
|
import { Types } from 'mongoose';
|
|
5
7
|
|
|
6
|
-
import { getTranslatablePropertyKeys } from '../decorators/translatable.decorator';
|
|
7
8
|
import { RoleEnum } from '../enums/role.enum';
|
|
8
9
|
import { PrepareInputOptions } from '../interfaces/prepare-input-options.interface';
|
|
9
10
|
import { PrepareOutputOptions } from '../interfaces/prepare-output-options.interface';
|
|
@@ -13,9 +14,6 @@ import { ConfigService } from '../services/config.service';
|
|
|
13
14
|
import { getStringIds } from './db.helper';
|
|
14
15
|
import { clone, processDeep } from './input.helper';
|
|
15
16
|
|
|
16
|
-
import bcrypt = require('bcrypt');
|
|
17
|
-
import _ = require('lodash');
|
|
18
|
-
|
|
19
17
|
/**
|
|
20
18
|
* Helper class for services
|
|
21
19
|
* @deprecated use functions directly
|
|
@@ -277,16 +275,7 @@ export async function prepareOutput<T = { [key: string]: any; map: (...args: any
|
|
|
277
275
|
|
|
278
276
|
// Add translated values of current selected language if _translations object exists
|
|
279
277
|
if (config.targetModel && config.language && typeof output === 'object' && '_translations' in output) {
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
if (typeof translation === 'object') {
|
|
283
|
-
const keys = getTranslatablePropertyKeys(config.targetModel);
|
|
284
|
-
for (const key of keys) {
|
|
285
|
-
if (translation[key] != null) {
|
|
286
|
-
output[key] = translation[key];
|
|
287
|
-
}
|
|
288
|
-
}
|
|
289
|
-
}
|
|
278
|
+
applyTranslationsRecursively(output, config.language);
|
|
290
279
|
}
|
|
291
280
|
|
|
292
281
|
// Return prepared output
|
|
@@ -347,3 +336,39 @@ export function prepareServiceOptions(
|
|
|
347
336
|
// Return (cloned and) prepared service options
|
|
348
337
|
return serviceOptions;
|
|
349
338
|
}
|
|
339
|
+
|
|
340
|
+
function applyTranslationsRecursively(obj: any, language: string, visited: WeakSet<object> = new WeakSet()) {
|
|
341
|
+
if (typeof obj !== 'object' || obj === null) {
|
|
342
|
+
return;
|
|
343
|
+
}
|
|
344
|
+
if (visited.has(obj)) {
|
|
345
|
+
return;
|
|
346
|
+
} // Cycle detected -> cancel
|
|
347
|
+
|
|
348
|
+
visited.add(obj);
|
|
349
|
+
|
|
350
|
+
// If _translations exists
|
|
351
|
+
if ('_translations' in obj && typeof obj._translations === 'object') {
|
|
352
|
+
const translation = obj._translations?.[language];
|
|
353
|
+
if (typeof translation === 'object') {
|
|
354
|
+
for (const key in translation) {
|
|
355
|
+
if (translation[key] != null) {
|
|
356
|
+
obj[key] = translation[key];
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
// Recursive over all properties
|
|
363
|
+
for (const key of Object.keys(obj)) {
|
|
364
|
+
const value = obj[key];
|
|
365
|
+
|
|
366
|
+
if (Array.isArray(value)) {
|
|
367
|
+
for (const item of value) {
|
|
368
|
+
applyTranslationsRecursively(item, language, visited);
|
|
369
|
+
}
|
|
370
|
+
} else if (typeof value === 'object' && value !== null) {
|
|
371
|
+
applyTranslationsRecursively(value, language, visited);
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
}
|