@lenne.tech/nest-server 8.1.0 → 8.3.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/config.env.js +3 -2
- package/dist/config.env.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/db.helper.d.ts +2 -0
- package/dist/core/common/helpers/db.helper.js +13 -2
- package/dist/core/common/helpers/db.helper.js.map +1 -1
- package/dist/core/common/helpers/input.helper.d.ts +14 -2
- package/dist/core/common/helpers/input.helper.js +53 -11
- package/dist/core/common/helpers/input.helper.js.map +1 -1
- package/dist/core/common/interfaces/service-options.interface.d.ts +6 -0
- package/dist/core/common/models/core-model.model.d.ts +1 -1
- package/dist/core/common/models/core-model.model.js.map +1 -1
- package/dist/core/common/pipes/check-input.pipe.js +1 -1
- package/dist/core/common/pipes/check-input.pipe.js.map +1 -1
- package/dist/core/common/services/crud.service.js +17 -19
- package/dist/core/common/services/crud.service.js.map +1 -1
- package/dist/core/common/services/module.service.d.ts +14 -1
- package/dist/core/common/services/module.service.js +43 -4
- package/dist/core/common/services/module.service.js.map +1 -1
- 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/modules/auth/guards/roles.guard.js +1 -2
- package/dist/core/modules/auth/guards/roles.guard.js.map +1 -1
- package/dist/core/modules/user/core-user.service.js +34 -36
- package/dist/core/modules/user/core-user.service.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/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.model.d.ts +1 -1
- package/dist/server/modules/user/user.resolver.d.ts +2 -2
- package/dist/server/modules/user/user.resolver.js +30 -14
- package/dist/server/modules/user/user.resolver.js.map +1 -1
- package/dist/server/modules/user/user.service.js +5 -1
- package/dist/server/modules/user/user.service.js.map +1 -1
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/package.json +39 -39
- package/src/config.env.ts +3 -2
- package/src/core/common/decorators/restricted.decorator.ts +24 -12
- package/src/core/common/enums/role.enum.ts +24 -6
- package/src/core/common/helpers/db.helper.ts +16 -1
- package/src/core/common/helpers/input.helper.ts +65 -14
- package/src/core/common/interfaces/service-options.interface.ts +19 -1
- package/src/core/common/models/core-model.model.ts +1 -1
- package/src/core/common/pipes/check-input.pipe.ts +1 -1
- package/src/core/common/services/crud.service.ts +17 -22
- package/src/core/common/services/module.service.ts +83 -9
- package/src/core/common/types/ids.type.ts +7 -0
- package/src/core/modules/auth/guards/roles.guard.ts +5 -7
- package/src/core/modules/user/core-user.service.ts +38 -45
- package/src/index.ts +1 -0
- package/src/server/modules/user/avatar.controller.ts +1 -1
- package/src/server/modules/user/user.resolver.ts +26 -20
- package/src/server/modules/user/user.service.ts +8 -1
|
@@ -1,9 +1,11 @@
|
|
|
1
|
-
import { Document, Model } from 'mongoose';
|
|
2
|
-
import { popAndMap } from '../helpers/db.helper';
|
|
1
|
+
import { Document, Model, Types } from 'mongoose';
|
|
2
|
+
import { getStringIds, popAndMap } from '../helpers/db.helper';
|
|
3
|
+
import { check } from '../helpers/input.helper';
|
|
3
4
|
import { prepareInput, prepareOutput } from '../helpers/service.helper';
|
|
4
5
|
import { ServiceOptions } from '../interfaces/service-options.interface';
|
|
5
6
|
import { CoreModel } from '../models/core-model.model';
|
|
6
7
|
import { FieldSelection } from '../types/field-selection.type';
|
|
8
|
+
import { IdsType } from '../types/ids.type';
|
|
7
9
|
|
|
8
10
|
/**
|
|
9
11
|
* Module service class to be extended by concrete module services
|
|
@@ -30,17 +32,49 @@ export abstract class ModuleService<T extends CoreModel = any> {
|
|
|
30
32
|
this.mainModelConstructor = options?.mainModelConstructor;
|
|
31
33
|
}
|
|
32
34
|
|
|
35
|
+
/**
|
|
36
|
+
* Check rights of current user for input
|
|
37
|
+
*/
|
|
38
|
+
checkRights(
|
|
39
|
+
input: any,
|
|
40
|
+
currentUser: { id: any; hasRole: (roles: string[]) => boolean },
|
|
41
|
+
options?: {
|
|
42
|
+
creator?: IdsType;
|
|
43
|
+
metatype?: any;
|
|
44
|
+
ownerIds?: IdsType;
|
|
45
|
+
roles?: string | string[];
|
|
46
|
+
throwError?: boolean;
|
|
47
|
+
}
|
|
48
|
+
): Promise<any> {
|
|
49
|
+
const config = {
|
|
50
|
+
metatype: this.mainModelConstructor,
|
|
51
|
+
...options,
|
|
52
|
+
};
|
|
53
|
+
return check(input, currentUser, config);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Get function to get Object via ID, necessary for checkInput
|
|
58
|
+
*/
|
|
59
|
+
abstract get(id: any, ...args: any[]): any;
|
|
60
|
+
|
|
33
61
|
/**
|
|
34
62
|
* Run service function with pre- and post-functions
|
|
35
63
|
*/
|
|
36
64
|
async process(
|
|
37
65
|
serviceFunc: (options?: { [key: string]: any; input?: any; serviceOptions?: ServiceOptions }) => any,
|
|
38
|
-
options?: {
|
|
66
|
+
options?: {
|
|
67
|
+
[key: string]: any;
|
|
68
|
+
dbObject?: string | Types.ObjectId | any;
|
|
69
|
+
input?: any;
|
|
70
|
+
serviceOptions?: ServiceOptions;
|
|
71
|
+
}
|
|
39
72
|
) {
|
|
40
73
|
// Configuration with default values
|
|
41
74
|
const config = {
|
|
42
|
-
|
|
43
|
-
|
|
75
|
+
checkRights: true,
|
|
76
|
+
dbObject: options?.dbObject,
|
|
77
|
+
input: options?.input,
|
|
44
78
|
processFieldSelection: {},
|
|
45
79
|
prepareInput: {},
|
|
46
80
|
prepareOutput: {},
|
|
@@ -50,11 +84,42 @@ export abstract class ModuleService<T extends CoreModel = any> {
|
|
|
50
84
|
|
|
51
85
|
// Prepare input
|
|
52
86
|
if (config.prepareInput && this.prepareInput) {
|
|
53
|
-
await this.prepareInput(
|
|
87
|
+
await this.prepareInput(config.input, config.prepareInput);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// Get DB object
|
|
91
|
+
const getDbObject = async () => {
|
|
92
|
+
if (config.dbObject) {
|
|
93
|
+
if (typeof config.dbObject === 'string' || config.dbObject instanceof Types.ObjectId) {
|
|
94
|
+
const dbObject = await this.get(getStringIds(config.dbObject));
|
|
95
|
+
if (dbObject) {
|
|
96
|
+
config.dbObject = dbObject;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
return config.dbObject;
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
// Get owner IDs
|
|
104
|
+
let ownerIds = undefined;
|
|
105
|
+
if (config.checkRights && this.checkRights) {
|
|
106
|
+
ownerIds = getStringIds(config.ownerIds);
|
|
107
|
+
if (!ownerIds?.length) {
|
|
108
|
+
ownerIds = (await getDbObject())?.ownerIds;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// Check rights for input
|
|
113
|
+
if (config.input && config.checkRights && this.checkRights) {
|
|
114
|
+
const opts: any = { creator: (await getDbObject())?.createdBy, ownerIds, roles: config.roles };
|
|
115
|
+
if (config.inputType) {
|
|
116
|
+
opts.metatype = config.resultType;
|
|
117
|
+
}
|
|
118
|
+
config.input = await this.checkRights(config.input, config.currentUser as any, opts);
|
|
54
119
|
}
|
|
55
120
|
|
|
56
121
|
// Run service function
|
|
57
|
-
|
|
122
|
+
let result = await serviceFunc(config);
|
|
58
123
|
|
|
59
124
|
// Pop and map main model
|
|
60
125
|
if (config.processFieldSelection && config.fieldSelection && this.processFieldSelection) {
|
|
@@ -67,10 +132,19 @@ export abstract class ModuleService<T extends CoreModel = any> {
|
|
|
67
132
|
if (config.processFieldSelection && config.fieldSelection && this.processFieldSelection) {
|
|
68
133
|
config.prepareOutput.targetModel = null;
|
|
69
134
|
}
|
|
70
|
-
|
|
135
|
+
result = await this.prepareOutput(result, config.prepareOutput);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// Check output rights
|
|
139
|
+
if (config.checkRights && this.checkRights) {
|
|
140
|
+
const opts: any = { creator: (await getDbObject())?.createdBy, ownerIds, roles: config.roles, throwError: false };
|
|
141
|
+
if (config.resultType) {
|
|
142
|
+
opts.metatype = config.resultType;
|
|
143
|
+
}
|
|
144
|
+
result = await this.checkRights(result, config.currentUser as any, opts);
|
|
71
145
|
}
|
|
72
146
|
|
|
73
|
-
// Return result
|
|
147
|
+
// Return (prepared) result
|
|
74
148
|
return result;
|
|
75
149
|
}
|
|
76
150
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ExecutionContext, Injectable, UnauthorizedException } from '@nestjs/common';
|
|
1
|
+
import { ExecutionContext, Inject, Injectable, UnauthorizedException } from '@nestjs/common';
|
|
2
2
|
import { Reflector } from '@nestjs/core';
|
|
3
3
|
import { GqlExecutionContext } from '@nestjs/graphql';
|
|
4
4
|
import { RoleEnum } from '../../../common/enums/role.enum';
|
|
@@ -8,7 +8,8 @@ import { AuthGuard } from './auth.guard';
|
|
|
8
8
|
* Role guard
|
|
9
9
|
*
|
|
10
10
|
* The RoleGuard is activated by the Role decorator. It checks whether the current user has at least one of the
|
|
11
|
-
* specified roles
|
|
11
|
+
* specified roles or is logged in when the S_USER role is set.
|
|
12
|
+
* If this is not the case, an UnauthorizedException is thrown.
|
|
12
13
|
*/
|
|
13
14
|
@Injectable()
|
|
14
15
|
export class RolesGuard extends AuthGuard('jwt') {
|
|
@@ -41,11 +42,8 @@ export class RolesGuard extends AuthGuard('jwt') {
|
|
|
41
42
|
// Get args
|
|
42
43
|
const args: any = GqlExecutionContext.create(context).getArgs();
|
|
43
44
|
|
|
44
|
-
// Check special role
|
|
45
|
-
if (
|
|
46
|
-
user &&
|
|
47
|
-
(roles.includes(RoleEnum.USER) || (roles.includes(RoleEnum.OWNER) && user.id.toString() === args.id))
|
|
48
|
-
) {
|
|
45
|
+
// Check special user role (user is logged in)
|
|
46
|
+
if (user && roles.includes(RoleEnum.S_USER)) {
|
|
49
47
|
return user;
|
|
50
48
|
}
|
|
51
49
|
|
|
@@ -35,7 +35,7 @@ export abstract class CoreUserService<
|
|
|
35
35
|
* Create user
|
|
36
36
|
*/
|
|
37
37
|
async create(input: any, serviceOptions?: ServiceOptions): Promise<TUser> {
|
|
38
|
-
merge({ prepareInput: { create: true } }, serviceOptions);
|
|
38
|
+
serviceOptions = merge({ prepareInput: { create: true } }, serviceOptions);
|
|
39
39
|
return this.process(
|
|
40
40
|
async (data) => {
|
|
41
41
|
// Create user with verification token
|
|
@@ -68,16 +68,11 @@ export abstract class CoreUserService<
|
|
|
68
68
|
* Get user via email
|
|
69
69
|
*/
|
|
70
70
|
async getViaEmail(email: string, serviceOptions?: ServiceOptions): Promise<TUser> {
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
}
|
|
77
|
-
return user;
|
|
78
|
-
},
|
|
79
|
-
{ serviceOptions }
|
|
80
|
-
);
|
|
71
|
+
const dbObject = await this.mainDbModel.findOne({ email }).exec();
|
|
72
|
+
if (!dbObject) {
|
|
73
|
+
throw new NotFoundException(`No user found with email: ${email}`);
|
|
74
|
+
}
|
|
75
|
+
return this.process(async () => dbObject, { dbObject, serviceOptions });
|
|
81
76
|
}
|
|
82
77
|
|
|
83
78
|
/**
|
|
@@ -97,30 +92,29 @@ export abstract class CoreUserService<
|
|
|
97
92
|
* Verify user with token
|
|
98
93
|
*/
|
|
99
94
|
async verify(token: string, serviceOptions?: ServiceOptions): Promise<TUser> {
|
|
95
|
+
// Get user
|
|
96
|
+
const dbObject = await this.mainDbModel.findOne({ verificationToken: token }).exec();
|
|
97
|
+
if (!dbObject) {
|
|
98
|
+
throw new NotFoundException(`No user found with verify token: ${token}`);
|
|
99
|
+
}
|
|
100
|
+
if (!dbObject.verificationToken) {
|
|
101
|
+
throw new Error('User has no token');
|
|
102
|
+
}
|
|
103
|
+
if (dbObject.verified) {
|
|
104
|
+
throw new Error('User already verified');
|
|
105
|
+
}
|
|
100
106
|
return this.process(
|
|
101
107
|
async () => {
|
|
102
|
-
// Get user
|
|
103
|
-
const user = await this.mainDbModel.findOne({ verificationToken: token }).exec();
|
|
104
|
-
if (!user) {
|
|
105
|
-
throw new NotFoundException(`No user found with verify token: ${token}`);
|
|
106
|
-
}
|
|
107
|
-
if (!user.verificationToken) {
|
|
108
|
-
throw new Error('User has no token');
|
|
109
|
-
}
|
|
110
|
-
if (user.verified) {
|
|
111
|
-
throw new Error('User already verified');
|
|
112
|
-
}
|
|
113
|
-
|
|
114
108
|
// Update user
|
|
115
|
-
await Object.assign(
|
|
109
|
+
await Object.assign(dbObject, {
|
|
116
110
|
verified: true,
|
|
117
111
|
verificationToken: null,
|
|
118
112
|
}).save();
|
|
119
113
|
|
|
120
114
|
// Return prepared user
|
|
121
|
-
return
|
|
115
|
+
return dbObject;
|
|
122
116
|
},
|
|
123
|
-
{ serviceOptions }
|
|
117
|
+
{ dbObject, serviceOptions }
|
|
124
118
|
);
|
|
125
119
|
}
|
|
126
120
|
|
|
@@ -128,24 +122,24 @@ export abstract class CoreUserService<
|
|
|
128
122
|
* Set newpassword for user with token
|
|
129
123
|
*/
|
|
130
124
|
async resetPassword(token: string, newPassword: string, serviceOptions?: ServiceOptions): Promise<TUser> {
|
|
125
|
+
// Get user
|
|
126
|
+
const dbObject = await this.mainDbModel.findOne({ passwordResetToken: token }).exec();
|
|
127
|
+
if (!dbObject) {
|
|
128
|
+
throw new NotFoundException(`No user found with password reset token: ${token}`);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
131
|
return this.process(
|
|
132
132
|
async () => {
|
|
133
|
-
// Get user
|
|
134
|
-
const user = await this.mainDbModel.findOne({ passwordResetToken: token }).exec();
|
|
135
|
-
if (!user) {
|
|
136
|
-
throw new NotFoundException(`No user found with password reset token: ${token}`);
|
|
137
|
-
}
|
|
138
|
-
|
|
139
133
|
// Update user
|
|
140
|
-
await Object.assign(
|
|
134
|
+
await Object.assign(dbObject, {
|
|
141
135
|
password: await bcrypt.hash(newPassword, 10),
|
|
142
136
|
passwordResetToken: null,
|
|
143
137
|
}).save();
|
|
144
138
|
|
|
145
139
|
// Return user
|
|
146
|
-
return
|
|
140
|
+
return dbObject;
|
|
147
141
|
},
|
|
148
|
-
{ serviceOptions }
|
|
142
|
+
{ dbObject, serviceOptions }
|
|
149
143
|
);
|
|
150
144
|
}
|
|
151
145
|
|
|
@@ -153,23 +147,22 @@ export abstract class CoreUserService<
|
|
|
153
147
|
* Set password rest token for email
|
|
154
148
|
*/
|
|
155
149
|
async setPasswordResetTokenForEmail(email: string, serviceOptions?: ServiceOptions): Promise<TUser> {
|
|
150
|
+
// Get user
|
|
151
|
+
const dbObject = await this.mainDbModel.findOne({ email }).exec();
|
|
152
|
+
if (!dbObject) {
|
|
153
|
+
throw new NotFoundException(`No user found with email: ${email}`);
|
|
154
|
+
}
|
|
156
155
|
return this.process(
|
|
157
156
|
async () => {
|
|
158
|
-
// Get user
|
|
159
|
-
const user = await this.mainDbModel.findOne({ email }).exec();
|
|
160
|
-
if (!user) {
|
|
161
|
-
throw new NotFoundException(`No user found with email: ${email}`);
|
|
162
|
-
}
|
|
163
|
-
|
|
164
157
|
// Set reset token
|
|
165
158
|
const resetToken = crypto.randomBytes(32).toString('hex');
|
|
166
|
-
|
|
167
|
-
await
|
|
159
|
+
dbObject.passwordResetToken = resetToken;
|
|
160
|
+
await dbObject.save();
|
|
168
161
|
|
|
169
162
|
// Return user
|
|
170
|
-
return
|
|
163
|
+
return dbObject;
|
|
171
164
|
},
|
|
172
|
-
{ serviceOptions }
|
|
165
|
+
{ dbObject, serviceOptions }
|
|
173
166
|
);
|
|
174
167
|
}
|
|
175
168
|
|
package/src/index.ts
CHANGED
|
@@ -52,6 +52,7 @@ export * from './core/common/services/module.service';
|
|
|
52
52
|
export * from './core/common/services/template.service';
|
|
53
53
|
export * from './core/common/types/core-model-constructor.type';
|
|
54
54
|
export * from './core/common/types/field-selection.type';
|
|
55
|
+
export * from './core/common/types/ids.type';
|
|
55
56
|
export * from './core/common/types/plain-input.type';
|
|
56
57
|
export * from './core/common/types/string-or-object-id.type';
|
|
57
58
|
|
|
@@ -6,7 +6,6 @@ import { FilterArgs } from '../../../core/common/args/filter.args';
|
|
|
6
6
|
import { GraphQLUser } from '../../../core/common/decorators/graphql-user.decorator';
|
|
7
7
|
import { Roles } from '../../../core/common/decorators/roles.decorator';
|
|
8
8
|
import { RoleEnum } from '../../../core/common/enums/role.enum';
|
|
9
|
-
import { check } from '../../../core/common/helpers/input.helper';
|
|
10
9
|
import { UserCreateInput } from './inputs/user-create.input';
|
|
11
10
|
import { UserInput } from './inputs/user.input';
|
|
12
11
|
import { User } from './user.model';
|
|
@@ -32,16 +31,23 @@ export class UserResolver {
|
|
|
32
31
|
@Roles(RoleEnum.ADMIN)
|
|
33
32
|
@Query((returns) => [User], { description: 'Find users (via filter)' })
|
|
34
33
|
async findUsers(@Info() info: GraphQLResolveInfo, @Args() args?: FilterArgs) {
|
|
35
|
-
return await this.userService.find(args, {
|
|
34
|
+
return await this.userService.find(args, {
|
|
35
|
+
fieldSelection: { info, select: 'findUsers' },
|
|
36
|
+
inputType: FilterArgs,
|
|
37
|
+
});
|
|
36
38
|
}
|
|
37
39
|
|
|
38
40
|
/**
|
|
39
41
|
* Get user via ID
|
|
40
42
|
*/
|
|
41
|
-
@Roles(RoleEnum.
|
|
43
|
+
@Roles(RoleEnum.S_USER)
|
|
42
44
|
@Query((returns) => User, { description: 'Get user with specified ID' })
|
|
43
|
-
async getUser(@Args('id') id: string, @Info() info: GraphQLResolveInfo): Promise<User> {
|
|
44
|
-
return await this.userService.get(id, {
|
|
45
|
+
async getUser(@Args('id') id: string, @Info() info: GraphQLResolveInfo, @GraphQLUser() user: User): Promise<User> {
|
|
46
|
+
return await this.userService.get(id, {
|
|
47
|
+
currentUser: user,
|
|
48
|
+
fieldSelection: { info, select: 'getUser' },
|
|
49
|
+
roles: [RoleEnum.ADMIN, RoleEnum.S_CREATOR],
|
|
50
|
+
});
|
|
45
51
|
}
|
|
46
52
|
|
|
47
53
|
/**
|
|
@@ -73,21 +79,24 @@ export class UserResolver {
|
|
|
73
79
|
@GraphQLUser() user: User,
|
|
74
80
|
@Info() info: GraphQLResolveInfo
|
|
75
81
|
): Promise<User> {
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
return await this.userService.create(input, { currentUser: user, fieldSelection: { info, select: 'createUser' } });
|
|
82
|
+
return await this.userService.create(input, {
|
|
83
|
+
currentUser: user,
|
|
84
|
+
fieldSelection: { info, select: 'createUser' },
|
|
85
|
+
inputType: UserCreateInput,
|
|
86
|
+
});
|
|
82
87
|
}
|
|
83
88
|
|
|
84
89
|
/**
|
|
85
90
|
* Delete existing user
|
|
86
91
|
*/
|
|
87
|
-
@Roles(RoleEnum.
|
|
92
|
+
@Roles(RoleEnum.S_USER)
|
|
88
93
|
@Mutation((returns) => User, { description: 'Delete existing user' })
|
|
89
|
-
async deleteUser(@Args('id') id: string, @Info() info: GraphQLResolveInfo): Promise<User> {
|
|
90
|
-
return await this.userService.delete(id, {
|
|
94
|
+
async deleteUser(@Args('id') id: string, @Info() info: GraphQLResolveInfo, @GraphQLUser() user: User): Promise<User> {
|
|
95
|
+
return await this.userService.delete(id, {
|
|
96
|
+
currentUser: user,
|
|
97
|
+
fieldSelection: { info, select: 'deleteUser' },
|
|
98
|
+
roles: [RoleEnum.ADMIN, RoleEnum.S_CREATOR],
|
|
99
|
+
});
|
|
91
100
|
}
|
|
92
101
|
|
|
93
102
|
/**
|
|
@@ -101,7 +110,7 @@ export class UserResolver {
|
|
|
101
110
|
/**
|
|
102
111
|
* Update existing user
|
|
103
112
|
*/
|
|
104
|
-
@Roles(RoleEnum.
|
|
113
|
+
@Roles(RoleEnum.S_USER)
|
|
105
114
|
@Mutation((returns) => User, { description: 'Update existing user' })
|
|
106
115
|
async updateUser(
|
|
107
116
|
@Args('input') input: UserInput,
|
|
@@ -109,15 +118,12 @@ export class UserResolver {
|
|
|
109
118
|
@GraphQLUser() user: User,
|
|
110
119
|
@Info() info: GraphQLResolveInfo
|
|
111
120
|
): Promise<User> {
|
|
112
|
-
// Check input
|
|
113
|
-
// Hint: necessary as long as global CheckInputPipe can't access context for current user
|
|
114
|
-
// (see https://github.com/nestjs/graphql/issues/325)
|
|
115
|
-
input = await check(input, user, UserInput);
|
|
116
|
-
|
|
117
121
|
// Update user
|
|
118
122
|
return await this.userService.update(id, input, {
|
|
119
123
|
currentUser: user,
|
|
120
124
|
fieldSelection: { info, select: 'updateUser' },
|
|
125
|
+
inputType: UserInput,
|
|
126
|
+
roles: [RoleEnum.ADMIN, RoleEnum.S_CREATOR],
|
|
121
127
|
});
|
|
122
128
|
}
|
|
123
129
|
|
|
@@ -44,7 +44,14 @@ export class UserService extends CoreUserService<User, UserInput, UserCreateInpu
|
|
|
44
44
|
*/
|
|
45
45
|
async create(input: UserCreateInput, serviceOptions?: ServiceOptions): Promise<User> {
|
|
46
46
|
// Get prepared user
|
|
47
|
-
|
|
47
|
+
let user = await super.create(input, serviceOptions);
|
|
48
|
+
|
|
49
|
+
// Add the createdBy information in an additional step if it was not set by the system,
|
|
50
|
+
// because the user created himself and could not exist as currentUser before
|
|
51
|
+
if (!user.createdBy) {
|
|
52
|
+
await this.mainDbModel.findByIdAndUpdate(user.id, { createdBy: user.id });
|
|
53
|
+
user = await this.get(user.id, serviceOptions);
|
|
54
|
+
}
|
|
48
55
|
|
|
49
56
|
// Publish action
|
|
50
57
|
if (serviceOptions?.pubSub === undefined || serviceOptions.pubSub) {
|