@lenne.tech/nest-server 2.0.4 → 3.0.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/core/common/helpers/service.helper.d.ts +1 -0
- package/dist/core/common/helpers/service.helper.js +18 -1
- package/dist/core/common/helpers/service.helper.js.map +1 -1
- package/dist/core/modules/user/core-basic-user.service.d.ts +1 -1
- package/dist/core/modules/user/core-user.service.d.ts +4 -3
- package/dist/core/modules/user/core-user.service.js +26 -1
- package/dist/core/modules/user/core-user.service.js.map +1 -1
- package/dist/server/modules/user/user.model.d.ts +1 -1
- package/dist/server/server.module.js.map +1 -1
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/package.json +38 -48
- package/src/core/common/helpers/service.helper.ts +21 -2
- package/src/core/modules/user/core-basic-user.service.ts +3 -3
- package/src/core/modules/user/core-user.service.ts +48 -8
- package/src/server/server.module.ts +0 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lenne.tech/nest-server",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "3.0.0",
|
|
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",
|
|
@@ -49,48 +49,38 @@
|
|
|
49
49
|
"url": "https://github.com/lenneTech/nest-server/issues"
|
|
50
50
|
},
|
|
51
51
|
"engines": {
|
|
52
|
-
"node": ">=
|
|
53
|
-
},
|
|
54
|
-
"peerDependencies": {
|
|
55
|
-
"@nestjs/testing": "8.1.2",
|
|
56
|
-
"@nestjs/core": "8.1.2",
|
|
57
|
-
"@nestjs/common": "8.1.2",
|
|
58
|
-
"@nestjs/graphql": "9.1.1",
|
|
59
|
-
"@nestjs/jwt": "8.0.0",
|
|
60
|
-
"@nestjs/mongoose": "9.0.1",
|
|
61
|
-
"@nestjs/passport": "8.0.1",
|
|
62
|
-
"@nestjs/platform-express": "8.1.2"
|
|
52
|
+
"node": ">= 16.13.0"
|
|
63
53
|
},
|
|
64
54
|
"dependencies": {
|
|
65
|
-
"@apollo/federation": "0.33.
|
|
55
|
+
"@apollo/federation": "0.33.9",
|
|
66
56
|
"@apollo/gateway": "0.42.3",
|
|
67
|
-
"@nestjs/
|
|
68
|
-
"@nestjs/core": "8.
|
|
69
|
-
"@nestjs/
|
|
70
|
-
"@nestjs/graphql": "9.1.1",
|
|
57
|
+
"@nestjs/common": "8.2.6",
|
|
58
|
+
"@nestjs/core": "8.2.6",
|
|
59
|
+
"@nestjs/graphql": "9.1.2",
|
|
71
60
|
"@nestjs/jwt": "8.0.0",
|
|
72
|
-
"@nestjs/mongoose": "9.0.
|
|
73
|
-
"@nestjs/passport": "8.0
|
|
74
|
-
"@nestjs/platform-express": "8.
|
|
61
|
+
"@nestjs/mongoose": "9.0.2",
|
|
62
|
+
"@nestjs/passport": "8.1.0",
|
|
63
|
+
"@nestjs/platform-express": "8.2.6",
|
|
64
|
+
"@nestjs/testing": "8.2.6",
|
|
75
65
|
"@types/ejs": "3.1.0",
|
|
76
|
-
"@types/jest": "27.0
|
|
77
|
-
"@types/lodash": "4.14.
|
|
66
|
+
"@types/jest": "27.4.0",
|
|
67
|
+
"@types/lodash": "4.14.178",
|
|
78
68
|
"@types/multer": "1.4.7",
|
|
79
|
-
"@types/node": "16.11.
|
|
69
|
+
"@types/node": "16.11.21",
|
|
80
70
|
"@types/nodemailer": "6.4.4",
|
|
81
71
|
"@types/passport": "1.0.7",
|
|
82
72
|
"@types/supertest": "2.0.11",
|
|
83
|
-
"@typescript-eslint/eslint-plugin": "5.
|
|
84
|
-
"@typescript-eslint/parser": "5.
|
|
85
|
-
"apollo-server-core": "3.
|
|
86
|
-
"apollo-server-express": "3.
|
|
73
|
+
"@typescript-eslint/eslint-plugin": "5.10.0",
|
|
74
|
+
"@typescript-eslint/parser": "5.10.0",
|
|
75
|
+
"apollo-server-core": "3.6.2",
|
|
76
|
+
"apollo-server-express": "3.6.2",
|
|
87
77
|
"bcrypt": "5.0.1",
|
|
88
|
-
"class-transformer": "0.
|
|
89
|
-
"class-validator": "0.13.
|
|
78
|
+
"class-transformer": "0.5.1",
|
|
79
|
+
"class-validator": "0.13.2",
|
|
90
80
|
"coffeescript": "2.6.1",
|
|
91
81
|
"ejs": "3.1.6",
|
|
92
|
-
"fastify": "3.
|
|
93
|
-
"graphql": "15.
|
|
82
|
+
"fastify": "3.27.0",
|
|
83
|
+
"graphql": "15.8.0",
|
|
94
84
|
"graphql-subscriptions": "2.0.0",
|
|
95
85
|
"grunt": "1.4.1",
|
|
96
86
|
"grunt-bg-shell": "2.3.3",
|
|
@@ -98,33 +88,33 @@
|
|
|
98
88
|
"grunt-contrib-watch": "1.1.0",
|
|
99
89
|
"grunt-sync": "0.8.2",
|
|
100
90
|
"husky": "7.0.4",
|
|
101
|
-
"jest": "27.
|
|
102
|
-
"json-to-graphql-query": "2.
|
|
103
|
-
"light-my-request": "4.
|
|
91
|
+
"jest": "27.4.7",
|
|
92
|
+
"json-to-graphql-query": "2.2.0",
|
|
93
|
+
"light-my-request": "4.7.0",
|
|
104
94
|
"lodash": "4.17.21",
|
|
105
|
-
"mongoose": "6.
|
|
106
|
-
"multer": "1.4.
|
|
107
|
-
"nodemailer": "6.7.
|
|
108
|
-
"nodemon": "2.0.
|
|
109
|
-
"passport": "0.
|
|
95
|
+
"mongoose": "6.1.7",
|
|
96
|
+
"multer": "1.4.4",
|
|
97
|
+
"nodemailer": "6.7.2",
|
|
98
|
+
"nodemon": "2.0.15",
|
|
99
|
+
"passport": "0.5.2",
|
|
110
100
|
"passport-jwt": "4.0.0",
|
|
111
101
|
"reflect-metadata": "0.1.13",
|
|
112
102
|
"rimraf": "3.0.2",
|
|
113
|
-
"rxjs": "7.
|
|
114
|
-
"supertest": "6.
|
|
115
|
-
"ts-morph": "
|
|
103
|
+
"rxjs": "7.5.2",
|
|
104
|
+
"supertest": "6.2.2",
|
|
105
|
+
"ts-morph": "13.0.3",
|
|
116
106
|
"ts-node": "10.4.0",
|
|
117
|
-
"tsconfig-paths": "3.
|
|
107
|
+
"tsconfig-paths": "3.12.0"
|
|
118
108
|
},
|
|
119
109
|
"devDependencies": {
|
|
120
|
-
"eslint": "8.
|
|
110
|
+
"eslint": "8.7.0",
|
|
121
111
|
"eslint-config-prettier": "8.3.0",
|
|
122
112
|
"find-file-up": "2.0.1",
|
|
123
113
|
"pm2": "5.1.2",
|
|
124
|
-
"prettier": "2.
|
|
125
|
-
"pretty-quick": "3.1.
|
|
126
|
-
"ts-jest": "27.
|
|
127
|
-
"typescript": "4.
|
|
114
|
+
"prettier": "2.5.1",
|
|
115
|
+
"pretty-quick": "3.1.3",
|
|
116
|
+
"ts-jest": "27.1.3",
|
|
117
|
+
"typescript": "4.5.5"
|
|
128
118
|
},
|
|
129
119
|
"jest": {
|
|
130
120
|
"collectCoverage": true,
|
|
@@ -1,4 +1,7 @@
|
|
|
1
|
+
import { UnauthorizedException } from '@nestjs/common';
|
|
1
2
|
import * as bcrypt from 'bcrypt';
|
|
3
|
+
import * as _ from 'lodash';
|
|
4
|
+
import { RoleEnum } from '../enums/role.enum';
|
|
2
5
|
|
|
3
6
|
/**
|
|
4
7
|
* Helper class for services
|
|
@@ -9,13 +12,15 @@ export class ServiceHelper {
|
|
|
9
12
|
*/
|
|
10
13
|
static async prepareInput(
|
|
11
14
|
input: { [key: string]: any },
|
|
12
|
-
currentUser: { id: string },
|
|
15
|
+
currentUser: { [key: string]: any; id: string },
|
|
13
16
|
options: { [key: string]: any; create?: boolean; clone?: boolean } = {},
|
|
14
17
|
...args: any[]
|
|
15
18
|
) {
|
|
16
19
|
// Configuration
|
|
17
20
|
const config = {
|
|
21
|
+
checkRoles: true,
|
|
18
22
|
clone: false,
|
|
23
|
+
create: false,
|
|
19
24
|
...options,
|
|
20
25
|
};
|
|
21
26
|
|
|
@@ -24,7 +29,21 @@ export class ServiceHelper {
|
|
|
24
29
|
input = JSON.parse(JSON.stringify(input));
|
|
25
30
|
}
|
|
26
31
|
|
|
27
|
-
//
|
|
32
|
+
// Process roles
|
|
33
|
+
if (input.roles && config.checkRoles && (!currentUser?.hasRole || !currentUser.hasRole(RoleEnum.ADMIN))) {
|
|
34
|
+
if (!(currentUser as any)?.roles) {
|
|
35
|
+
throw new UnauthorizedException('Missing roles of current user');
|
|
36
|
+
} else {
|
|
37
|
+
const allowedRoles = _.intersection(input.roles, (currentUser as any).roles);
|
|
38
|
+
if (allowedRoles.length !== input.roles.length) {
|
|
39
|
+
const missingRoles = _.difference(input.roles, (currentUser as any).roles);
|
|
40
|
+
throw new UnauthorizedException('Current user not allowed setting roles: ' + missingRoles);
|
|
41
|
+
}
|
|
42
|
+
input.roles = allowedRoles;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// Hash password
|
|
28
47
|
if (input.password) {
|
|
29
48
|
input.password = await bcrypt.hash((input as any).password, 10);
|
|
30
49
|
}
|
|
@@ -16,9 +16,9 @@ const pubSub = new PubSub();
|
|
|
16
16
|
* User service
|
|
17
17
|
*/
|
|
18
18
|
export abstract class CoreBasicUserService<
|
|
19
|
-
TUser
|
|
20
|
-
TUserInput
|
|
21
|
-
TUserCreateInput
|
|
19
|
+
TUser extends CoreUserModel,
|
|
20
|
+
TUserInput extends CoreUserInput,
|
|
21
|
+
TUserCreateInput extends CoreUserCreateInput
|
|
22
22
|
> {
|
|
23
23
|
protected readonly model: ICorePersistenceModel;
|
|
24
24
|
|
|
@@ -1,13 +1,20 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
BadRequestException,
|
|
3
|
+
NotFoundException,
|
|
4
|
+
UnauthorizedException,
|
|
5
|
+
UnprocessableEntityException,
|
|
6
|
+
} from '@nestjs/common';
|
|
2
7
|
import * as bcrypt from 'bcrypt';
|
|
3
8
|
import { PubSub } from 'graphql-subscriptions';
|
|
4
9
|
import { FilterArgs } from '../../common/args/filter.args';
|
|
10
|
+
import { RoleEnum } from '../../common/enums/role.enum';
|
|
5
11
|
import { Filter } from '../../common/helpers/filter.helper';
|
|
6
12
|
import { CoreBasicUserService } from './core-basic-user.service';
|
|
7
13
|
import { CoreUserModel } from './core-user.model';
|
|
8
14
|
import { CoreUserCreateInput } from './inputs/core-user-create.input';
|
|
9
15
|
import { CoreUserInput } from './inputs/core-user.input';
|
|
10
16
|
import { Model } from 'mongoose';
|
|
17
|
+
import * as _ from 'lodash';
|
|
11
18
|
|
|
12
19
|
// Subscription
|
|
13
20
|
const pubSub = new PubSub();
|
|
@@ -16,9 +23,9 @@ const pubSub = new PubSub();
|
|
|
16
23
|
* User service
|
|
17
24
|
*/
|
|
18
25
|
export abstract class CoreUserService<
|
|
19
|
-
TUser
|
|
20
|
-
TUserInput
|
|
21
|
-
TUserCreateInput
|
|
26
|
+
TUser extends CoreUserModel,
|
|
27
|
+
TUserInput extends CoreUserInput,
|
|
28
|
+
TUserCreateInput extends CoreUserCreateInput
|
|
22
29
|
> extends CoreBasicUserService<TUser, TUserInput, TUserCreateInput> {
|
|
23
30
|
protected constructor(protected readonly userModel: Model<any>) {
|
|
24
31
|
super(userModel);
|
|
@@ -108,6 +115,24 @@ export abstract class CoreUserService<
|
|
|
108
115
|
);
|
|
109
116
|
}
|
|
110
117
|
|
|
118
|
+
/**
|
|
119
|
+
* Set roles for specified user
|
|
120
|
+
*/
|
|
121
|
+
async setRoles(userId: string, roles: string[]): Promise<TUser> {
|
|
122
|
+
// Check roles
|
|
123
|
+
if (!Array.isArray(roles)) {
|
|
124
|
+
throw new BadRequestException('Missing roles');
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// Check roles values
|
|
128
|
+
if (roles.some((role) => typeof role !== 'string')) {
|
|
129
|
+
throw new BadRequestException('roles contains invalid values');
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// Update and return user
|
|
133
|
+
return this.userModel.findByIdAndUpdate(userId, { roles }).exec();
|
|
134
|
+
}
|
|
135
|
+
|
|
111
136
|
/**
|
|
112
137
|
* Update user via ID
|
|
113
138
|
*/
|
|
@@ -144,22 +169,37 @@ export abstract class CoreUserService<
|
|
|
144
169
|
*/
|
|
145
170
|
protected async prepareInput(
|
|
146
171
|
input: { [key: string]: any },
|
|
147
|
-
currentUser
|
|
148
|
-
options: { [key: string]: any;
|
|
172
|
+
currentUser?: TUser,
|
|
173
|
+
options: { [key: string]: any; checkRoles?: boolean; clone?: boolean } = {},
|
|
149
174
|
...args: any[]
|
|
150
175
|
) {
|
|
151
176
|
// Configuration
|
|
152
177
|
const config = {
|
|
178
|
+
checkRoles: true,
|
|
153
179
|
clone: false,
|
|
154
180
|
...options,
|
|
155
181
|
};
|
|
156
182
|
|
|
157
|
-
// Clone
|
|
183
|
+
// Clone input
|
|
158
184
|
if (config.clone) {
|
|
159
185
|
input = JSON.parse(JSON.stringify(input));
|
|
160
186
|
}
|
|
161
187
|
|
|
162
|
-
//
|
|
188
|
+
// Process roles
|
|
189
|
+
if (input.roles && config.checkRoles && (!currentUser?.hasRole || !currentUser.hasRole(RoleEnum.ADMIN))) {
|
|
190
|
+
if (!(currentUser as any)?.roles) {
|
|
191
|
+
throw new UnauthorizedException('Missing roles of current user');
|
|
192
|
+
} else {
|
|
193
|
+
const allowedRoles = _.intersection(input.roles, (currentUser as any).roles);
|
|
194
|
+
if (allowedRoles.length !== input.roles.length) {
|
|
195
|
+
const missingRoles = _.difference(input.roles, (currentUser as any).roles);
|
|
196
|
+
throw new UnauthorizedException('Current user not allowed setting roles: ' + missingRoles);
|
|
197
|
+
}
|
|
198
|
+
input.roles = allowedRoles;
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
// Hash password
|
|
163
203
|
if (input.password) {
|
|
164
204
|
input.password = await bcrypt.hash((input as any).password, 10);
|
|
165
205
|
}
|
|
@@ -4,7 +4,6 @@ import { CoreModule } from '../core.module';
|
|
|
4
4
|
import { AuthModule } from './modules/auth/auth.module';
|
|
5
5
|
import { FileController } from './modules/file/file.controller';
|
|
6
6
|
import { ServerController } from './server.controller';
|
|
7
|
-
import { PubSub } from 'graphql-subscriptions';
|
|
8
7
|
|
|
9
8
|
/**
|
|
10
9
|
* Server module (dynamic)
|