@strapi/plugin-users-permissions 4.0.0-beta.2 → 4.0.0-beta.20
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/admin/src/components/BoundRoute/index.js +23 -27
- package/admin/src/components/FormModal/Input/index.js +2 -2
- package/admin/src/components/FormModal/index.js +10 -5
- package/admin/src/components/Permissions/PermissionRow/CheckboxWrapper.js +1 -1
- package/admin/src/components/Permissions/PermissionRow/SubCategory.js +12 -10
- package/admin/src/components/Permissions/PermissionRow/index.js +1 -1
- package/admin/src/components/Permissions/index.js +12 -8
- package/admin/src/components/Policies/index.js +12 -9
- package/admin/src/components/UsersPermissions/index.js +12 -15
- package/admin/src/index.js +0 -8
- package/admin/src/pages/AdvancedSettings/index.js +13 -13
- package/admin/src/pages/EmailTemplates/components/EmailForm.js +10 -5
- package/admin/src/pages/EmailTemplates/components/EmailTable.js +16 -16
- package/admin/src/pages/EmailTemplates/index.js +3 -3
- package/admin/src/pages/Providers/index.js +21 -21
- package/admin/src/pages/Providers/utils/api.js +1 -1
- package/admin/src/pages/Roles/CreatePage/index.js +13 -13
- package/admin/src/pages/Roles/EditPage/index.js +23 -13
- package/admin/src/pages/Roles/ListPage/components/TableBody.js +14 -10
- package/admin/src/pages/Roles/ListPage/index.js +19 -25
- package/documentation/1.0.0/overrides/users-permissions-User.json +7 -7
- package/package.json +29 -30
- package/server/bootstrap/index.js +17 -17
- package/server/config.js +2 -2
- package/server/content-types/permission/index.js +3 -0
- package/server/content-types/role/index.js +3 -0
- package/server/controllers/auth.js +73 -215
- package/server/controllers/{user/admin.js → content-manager-user.js} +44 -75
- package/server/controllers/index.js +2 -0
- package/server/controllers/role.js +7 -7
- package/server/controllers/settings.js +5 -4
- package/server/controllers/user.js +118 -28
- package/server/controllers/validation/auth.js +29 -0
- package/server/controllers/validation/user.js +38 -0
- package/server/middlewares/rateLimit.js +1 -1
- package/server/routes/admin/role.js +5 -5
- package/server/routes/admin/settings.js +6 -6
- package/server/routes/content-api/auth.js +5 -7
- package/server/services/jwt.js +9 -17
- package/server/services/providers.js +13 -10
- package/server/services/role.js +5 -10
- package/server/services/user.js +8 -6
- package/server/services/users-permissions.js +56 -45
- package/server/strategies/users-permissions.js +23 -22
- package/admin/src/assets/images/logo.svg +0 -1
- package/server/controllers/user/api.js +0 -158
|
@@ -2,15 +2,16 @@
|
|
|
2
2
|
|
|
3
3
|
const _ = require('lodash');
|
|
4
4
|
const { contentTypes: contentTypesUtils } = require('@strapi/utils');
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
const {
|
|
6
|
+
ApplicationError,
|
|
7
|
+
ValidationError,
|
|
8
|
+
NotFoundError,
|
|
9
|
+
ForbiddenError,
|
|
10
|
+
} = require('@strapi/utils').errors;
|
|
11
|
+
const { validateCreateUserBody, validateUpdateUserBody } = require('./validation/user');
|
|
7
12
|
|
|
8
13
|
const { UPDATED_BY_ATTRIBUTE, CREATED_BY_ATTRIBUTE } = contentTypesUtils.constants;
|
|
9
14
|
|
|
10
|
-
const formatError = error => [
|
|
11
|
-
{ messages: [{ id: error.id, message: error.message, field: error.field }] },
|
|
12
|
-
];
|
|
13
|
-
|
|
14
15
|
const userModel = 'plugin::users-permissions.user';
|
|
15
16
|
const ACTIONS = {
|
|
16
17
|
read: 'plugin::content-manager.explorer.read',
|
|
@@ -20,29 +21,24 @@ const ACTIONS = {
|
|
|
20
21
|
};
|
|
21
22
|
|
|
22
23
|
const findEntityAndCheckPermissions = async (ability, action, model, id) => {
|
|
23
|
-
const entity = await strapi.query(
|
|
24
|
+
const entity = await strapi.query(userModel).findOne({
|
|
25
|
+
where: { id },
|
|
26
|
+
populate: [`${CREATED_BY_ATTRIBUTE}.roles`],
|
|
27
|
+
});
|
|
24
28
|
|
|
25
29
|
if (_.isNil(entity)) {
|
|
26
|
-
throw
|
|
30
|
+
throw new NotFoundError();
|
|
27
31
|
}
|
|
28
32
|
|
|
29
33
|
const pm = strapi.admin.services.permission.createPermissionsManager({ ability, action, model });
|
|
30
34
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
where: {
|
|
34
|
-
users: { id: entity[CREATED_BY_ATTRIBUTE].id },
|
|
35
|
-
},
|
|
36
|
-
})
|
|
37
|
-
: [];
|
|
38
|
-
|
|
39
|
-
const entityWithRoles = _.set(_.cloneDeep(entity), `${CREATED_BY_ATTRIBUTE}.roles`, roles);
|
|
40
|
-
|
|
41
|
-
if (pm.ability.cannot(pm.action, pm.toSubject(entityWithRoles))) {
|
|
42
|
-
throw strapi.errors.forbidden();
|
|
35
|
+
if (pm.ability.cannot(pm.action, pm.toSubject(entity))) {
|
|
36
|
+
throw new ForbiddenError();
|
|
43
37
|
}
|
|
44
38
|
|
|
45
|
-
|
|
39
|
+
const entityWithoutCreatorRoles = _.omit(entity, `${CREATED_BY_ATTRIBUTE}.roles`);
|
|
40
|
+
|
|
41
|
+
return { pm, entity: entityWithoutCreatorRoles };
|
|
46
42
|
};
|
|
47
43
|
|
|
48
44
|
module.exports = {
|
|
@@ -54,7 +50,7 @@ module.exports = {
|
|
|
54
50
|
const { body } = ctx.request;
|
|
55
51
|
const { user: admin, userAbility } = ctx.state;
|
|
56
52
|
|
|
57
|
-
const { email, username
|
|
53
|
+
const { email, username } = body;
|
|
58
54
|
|
|
59
55
|
const pm = strapi.admin.services.permission.createPermissionsManager({
|
|
60
56
|
ability: userAbility,
|
|
@@ -63,32 +59,23 @@ module.exports = {
|
|
|
63
59
|
});
|
|
64
60
|
|
|
65
61
|
if (!pm.isAllowed) {
|
|
66
|
-
|
|
62
|
+
return ctx.forbidden();
|
|
67
63
|
}
|
|
68
64
|
|
|
69
|
-
const sanitizedBody = pm.pickPermittedFieldsOf(body, { subject: userModel });
|
|
65
|
+
const sanitizedBody = await pm.pickPermittedFieldsOf(body, { subject: userModel });
|
|
70
66
|
|
|
71
67
|
const advanced = await strapi
|
|
72
68
|
.store({ type: 'plugin', name: 'users-permissions', key: 'advanced' })
|
|
73
69
|
.get();
|
|
74
70
|
|
|
75
|
-
|
|
76
|
-
if (!username) return ctx.badRequest('missing.username');
|
|
77
|
-
if (!password) return ctx.badRequest('missing.password');
|
|
71
|
+
await validateCreateUserBody(ctx.request.body);
|
|
78
72
|
|
|
79
73
|
const userWithSameUsername = await strapi
|
|
80
74
|
.query('plugin::users-permissions.user')
|
|
81
75
|
.findOne({ where: { username } });
|
|
82
76
|
|
|
83
77
|
if (userWithSameUsername) {
|
|
84
|
-
|
|
85
|
-
null,
|
|
86
|
-
formatError({
|
|
87
|
-
id: 'Auth.form.error.username.taken',
|
|
88
|
-
message: 'Username already taken.',
|
|
89
|
-
field: ['username'],
|
|
90
|
-
})
|
|
91
|
-
);
|
|
78
|
+
throw new ApplicationError('Username already taken');
|
|
92
79
|
}
|
|
93
80
|
|
|
94
81
|
if (advanced.unique_email) {
|
|
@@ -97,15 +84,7 @@ module.exports = {
|
|
|
97
84
|
.findOne({ where: { email: email.toLowerCase() } });
|
|
98
85
|
|
|
99
86
|
if (userWithSameEmail) {
|
|
100
|
-
|
|
101
|
-
null,
|
|
102
|
-
|
|
103
|
-
formatError({
|
|
104
|
-
id: 'Auth.form.error.email.taken',
|
|
105
|
-
message: 'Email already taken.',
|
|
106
|
-
field: ['email'],
|
|
107
|
-
})
|
|
108
|
-
);
|
|
87
|
+
throw new ApplicationError('Email already taken');
|
|
109
88
|
}
|
|
110
89
|
}
|
|
111
90
|
|
|
@@ -127,11 +106,14 @@ module.exports = {
|
|
|
127
106
|
}
|
|
128
107
|
|
|
129
108
|
try {
|
|
130
|
-
const data = await
|
|
109
|
+
const data = await strapi
|
|
110
|
+
.service('plugin::content-manager.entity-manager')
|
|
111
|
+
.create(user, userModel);
|
|
112
|
+
const sanitizedData = await pm.sanitizeOutput(data, { action: ACTIONS.read });
|
|
131
113
|
|
|
132
|
-
ctx.created(
|
|
114
|
+
ctx.created(sanitizedData);
|
|
133
115
|
} catch (error) {
|
|
134
|
-
|
|
116
|
+
throw new ApplicationError(error.message);
|
|
135
117
|
}
|
|
136
118
|
},
|
|
137
119
|
/**
|
|
@@ -150,23 +132,22 @@ module.exports = {
|
|
|
150
132
|
|
|
151
133
|
const { email, username, password } = body;
|
|
152
134
|
|
|
153
|
-
|
|
135
|
+
let pm;
|
|
136
|
+
let user;
|
|
137
|
+
|
|
138
|
+
const { pm: permissionManager, entity } = await findEntityAndCheckPermissions(
|
|
154
139
|
userAbility,
|
|
155
140
|
ACTIONS.edit,
|
|
156
141
|
userModel,
|
|
157
142
|
id
|
|
158
143
|
);
|
|
144
|
+
pm = permissionManager;
|
|
145
|
+
user = entity;
|
|
159
146
|
|
|
160
|
-
|
|
161
|
-
return ctx.badRequest('email.notNull');
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
if (_.has(body, 'username') && !username) {
|
|
165
|
-
return ctx.badRequest('username.notNull');
|
|
166
|
-
}
|
|
147
|
+
await validateUpdateUserBody(ctx.request.body);
|
|
167
148
|
|
|
168
149
|
if (_.has(body, 'password') && !password && user.provider === 'local') {
|
|
169
|
-
|
|
150
|
+
throw new ValidationError('password.notNull');
|
|
170
151
|
}
|
|
171
152
|
|
|
172
153
|
if (_.has(body, 'username')) {
|
|
@@ -175,14 +156,7 @@ module.exports = {
|
|
|
175
156
|
.findOne({ where: { username } });
|
|
176
157
|
|
|
177
158
|
if (userWithSameUsername && userWithSameUsername.id != id) {
|
|
178
|
-
|
|
179
|
-
null,
|
|
180
|
-
formatError({
|
|
181
|
-
id: 'Auth.form.error.username.taken',
|
|
182
|
-
message: 'username.alreadyTaken.',
|
|
183
|
-
field: ['username'],
|
|
184
|
-
})
|
|
185
|
-
);
|
|
159
|
+
throw new ApplicationError('Username already taken');
|
|
186
160
|
}
|
|
187
161
|
}
|
|
188
162
|
|
|
@@ -192,23 +166,18 @@ module.exports = {
|
|
|
192
166
|
.findOne({ where: { email: _.toLower(email) } });
|
|
193
167
|
|
|
194
168
|
if (userWithSameEmail && userWithSameEmail.id != id) {
|
|
195
|
-
|
|
196
|
-
null,
|
|
197
|
-
formatError({
|
|
198
|
-
id: 'Auth.form.error.email.taken',
|
|
199
|
-
message: 'Email already taken',
|
|
200
|
-
field: ['email'],
|
|
201
|
-
})
|
|
202
|
-
);
|
|
169
|
+
throw new ApplicationError('Email already taken');
|
|
203
170
|
}
|
|
204
171
|
body.email = _.toLower(body.email);
|
|
205
172
|
}
|
|
206
173
|
|
|
207
|
-
const sanitizedData = pm.pickPermittedFieldsOf(body, { subject: pm.toSubject(user) });
|
|
174
|
+
const sanitizedData = await pm.pickPermittedFieldsOf(body, { subject: pm.toSubject(user) });
|
|
208
175
|
const updateData = _.omit({ ...sanitizedData, updatedBy: admin.id }, 'createdBy');
|
|
209
176
|
|
|
210
|
-
const data = await
|
|
177
|
+
const data = await strapi
|
|
178
|
+
.service('plugin::content-manager.entity-manager')
|
|
179
|
+
.update({ id }, updateData, userModel);
|
|
211
180
|
|
|
212
|
-
ctx.body = pm.
|
|
181
|
+
ctx.body = await pm.sanitizeOutput(data, { action: ACTIONS.read });
|
|
213
182
|
},
|
|
214
183
|
};
|
|
@@ -5,6 +5,7 @@ const user = require('./user');
|
|
|
5
5
|
const role = require('./role');
|
|
6
6
|
const permissions = require('./permissions');
|
|
7
7
|
const settings = require('./settings');
|
|
8
|
+
const contentmanageruser = require('./content-manager-user');
|
|
8
9
|
|
|
9
10
|
module.exports = {
|
|
10
11
|
auth,
|
|
@@ -12,4 +13,5 @@ module.exports = {
|
|
|
12
13
|
role,
|
|
13
14
|
permissions,
|
|
14
15
|
settings,
|
|
16
|
+
contentmanageruser,
|
|
15
17
|
};
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
const _ = require('lodash');
|
|
4
|
+
const { ApplicationError, ValidationError } = require('@strapi/utils').errors;
|
|
4
5
|
const { getService } = require('../utils');
|
|
6
|
+
const { validateDeleteRoleBody } = require('./validation/user');
|
|
5
7
|
|
|
6
8
|
module.exports = {
|
|
7
9
|
/**
|
|
@@ -11,7 +13,7 @@ module.exports = {
|
|
|
11
13
|
*/
|
|
12
14
|
async createRole(ctx) {
|
|
13
15
|
if (_.isEmpty(ctx.request.body)) {
|
|
14
|
-
|
|
16
|
+
throw new ValidationError('Request body cannot be empty');
|
|
15
17
|
}
|
|
16
18
|
|
|
17
19
|
await getService('role').createRole(ctx.request.body);
|
|
@@ -21,10 +23,8 @@ module.exports = {
|
|
|
21
23
|
|
|
22
24
|
async getRole(ctx) {
|
|
23
25
|
const { id } = ctx.params;
|
|
24
|
-
const { lang } = ctx.query;
|
|
25
26
|
|
|
26
|
-
const
|
|
27
|
-
const role = await getService('role').getRole(id, plugins);
|
|
27
|
+
const role = await getService('role').getRole(id);
|
|
28
28
|
|
|
29
29
|
if (!role) {
|
|
30
30
|
return ctx.notFound();
|
|
@@ -43,7 +43,7 @@ module.exports = {
|
|
|
43
43
|
const roleID = ctx.params.role;
|
|
44
44
|
|
|
45
45
|
if (_.isEmpty(ctx.request.body)) {
|
|
46
|
-
|
|
46
|
+
throw new ValidationError('Request body cannot be empty');
|
|
47
47
|
}
|
|
48
48
|
|
|
49
49
|
await getService('role').updateRole(roleID, ctx.request.body);
|
|
@@ -55,7 +55,7 @@ module.exports = {
|
|
|
55
55
|
const roleID = ctx.params.role;
|
|
56
56
|
|
|
57
57
|
if (!roleID) {
|
|
58
|
-
|
|
58
|
+
await validateDeleteRoleBody(ctx.params);
|
|
59
59
|
}
|
|
60
60
|
|
|
61
61
|
// Fetch public role.
|
|
@@ -67,7 +67,7 @@ module.exports = {
|
|
|
67
67
|
|
|
68
68
|
// Prevent from removing the public role.
|
|
69
69
|
if (roleID.toString() === publicRoleID.toString()) {
|
|
70
|
-
|
|
70
|
+
throw new ApplicationError('Cannot delete public role');
|
|
71
71
|
}
|
|
72
72
|
|
|
73
73
|
await getService('role').deleteRole(roleID, publicRoleID);
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
const _ = require('lodash');
|
|
4
|
+
const { ValidationError } = require('@strapi/utils').errors;
|
|
4
5
|
const { getService } = require('../utils');
|
|
5
6
|
const { isValidEmailTemplate } = require('./validation/email-template');
|
|
6
7
|
|
|
@@ -11,7 +12,7 @@ module.exports = {
|
|
|
11
12
|
|
|
12
13
|
async updateEmailTemplate(ctx) {
|
|
13
14
|
if (_.isEmpty(ctx.request.body)) {
|
|
14
|
-
|
|
15
|
+
throw new ValidationError('Request body cannot be empty');
|
|
15
16
|
}
|
|
16
17
|
|
|
17
18
|
const emailTemplates = ctx.request.body['email-templates'];
|
|
@@ -20,7 +21,7 @@ module.exports = {
|
|
|
20
21
|
const template = emailTemplates[key].options.message;
|
|
21
22
|
|
|
22
23
|
if (!isValidEmailTemplate(template)) {
|
|
23
|
-
|
|
24
|
+
throw new ValidationError('Invalid template');
|
|
24
25
|
}
|
|
25
26
|
}
|
|
26
27
|
|
|
@@ -43,7 +44,7 @@ module.exports = {
|
|
|
43
44
|
|
|
44
45
|
async updateAdvancedSettings(ctx) {
|
|
45
46
|
if (_.isEmpty(ctx.request.body)) {
|
|
46
|
-
|
|
47
|
+
throw new ValidationError('Request body cannot be empty');
|
|
47
48
|
}
|
|
48
49
|
|
|
49
50
|
await strapi
|
|
@@ -72,7 +73,7 @@ module.exports = {
|
|
|
72
73
|
|
|
73
74
|
async updateProviders(ctx) {
|
|
74
75
|
if (_.isEmpty(ctx.request.body)) {
|
|
75
|
-
|
|
76
|
+
throw new ValidationError('Request body cannot be empty');
|
|
76
77
|
}
|
|
77
78
|
|
|
78
79
|
await strapi
|
|
@@ -7,38 +7,127 @@
|
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
9
|
const _ = require('lodash');
|
|
10
|
-
const
|
|
10
|
+
const utils = require('@strapi/utils');
|
|
11
11
|
const { getService } = require('../utils');
|
|
12
|
-
const
|
|
13
|
-
const apiUserController = require('./user/api');
|
|
12
|
+
const { validateCreateUserBody, validateUpdateUserBody } = require('./validation/user');
|
|
14
13
|
|
|
15
|
-
const
|
|
16
|
-
|
|
17
|
-
model: strapi.getModel('plugin::users-permissions.user'),
|
|
18
|
-
});
|
|
14
|
+
const { sanitize } = utils;
|
|
15
|
+
const { ApplicationError, ValidationError } = utils.errors;
|
|
19
16
|
|
|
20
|
-
const
|
|
21
|
-
const
|
|
22
|
-
|
|
23
|
-
} = ctx;
|
|
17
|
+
const sanitizeOutput = (user, ctx) => {
|
|
18
|
+
const schema = strapi.getModel('plugin::users-permissions.user');
|
|
19
|
+
const { auth } = ctx.state;
|
|
24
20
|
|
|
25
|
-
return
|
|
21
|
+
return sanitize.contentAPI.output(user, schema, { auth });
|
|
26
22
|
};
|
|
27
23
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
24
|
+
module.exports = {
|
|
25
|
+
/**
|
|
26
|
+
* Create a/an user record.
|
|
27
|
+
* @return {Object}
|
|
28
|
+
*/
|
|
29
|
+
async create(ctx) {
|
|
30
|
+
const advanced = await strapi
|
|
31
|
+
.store({ type: 'plugin', name: 'users-permissions', key: 'advanced' })
|
|
32
|
+
.get();
|
|
31
33
|
|
|
32
|
-
|
|
33
|
-
return ctx.notFound();
|
|
34
|
-
}
|
|
34
|
+
await validateCreateUserBody(ctx.request.body);
|
|
35
35
|
|
|
36
|
-
|
|
37
|
-
};
|
|
36
|
+
const { email, username, role } = ctx.request.body;
|
|
38
37
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
38
|
+
const userWithSameUsername = await strapi
|
|
39
|
+
.query('plugin::users-permissions.user')
|
|
40
|
+
.findOne({ where: { username } });
|
|
41
|
+
|
|
42
|
+
if (userWithSameUsername) {
|
|
43
|
+
if (!email) throw new ApplicationError('Username already taken');
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
if (advanced.unique_email) {
|
|
47
|
+
const userWithSameEmail = await strapi
|
|
48
|
+
.query('plugin::users-permissions.user')
|
|
49
|
+
.findOne({ where: { email: email.toLowerCase() } });
|
|
50
|
+
|
|
51
|
+
if (userWithSameEmail) {
|
|
52
|
+
throw new ApplicationError('Email already taken');
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const user = {
|
|
57
|
+
...ctx.request.body,
|
|
58
|
+
provider: 'local',
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
user.email = _.toLower(user.email);
|
|
62
|
+
|
|
63
|
+
if (!role) {
|
|
64
|
+
const defaultRole = await strapi
|
|
65
|
+
.query('plugin::users-permissions.role')
|
|
66
|
+
.findOne({ where: { type: advanced.default_role } });
|
|
67
|
+
|
|
68
|
+
user.role = defaultRole.id;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
try {
|
|
72
|
+
const data = await getService('user').add(user);
|
|
73
|
+
const sanitizedData = await sanitizeOutput(data, ctx);
|
|
74
|
+
|
|
75
|
+
ctx.created(sanitizedData);
|
|
76
|
+
} catch (error) {
|
|
77
|
+
throw new ApplicationError(error.message);
|
|
78
|
+
}
|
|
79
|
+
},
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Update a/an user record.
|
|
83
|
+
* @return {Object}
|
|
84
|
+
*/
|
|
85
|
+
async update(ctx) {
|
|
86
|
+
const advancedConfigs = await strapi
|
|
87
|
+
.store({ type: 'plugin', name: 'users-permissions', key: 'advanced' })
|
|
88
|
+
.get();
|
|
89
|
+
|
|
90
|
+
const { id } = ctx.params;
|
|
91
|
+
const { email, username, password } = ctx.request.body;
|
|
92
|
+
|
|
93
|
+
const user = await getService('user').fetch({ id });
|
|
94
|
+
|
|
95
|
+
await validateUpdateUserBody(ctx.request.body);
|
|
96
|
+
|
|
97
|
+
if (user.provider === 'local' && _.has(ctx.request.body, 'password') && !password) {
|
|
98
|
+
throw new ValidationError('password.notNull');
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
if (_.has(ctx.request.body, 'username')) {
|
|
102
|
+
const userWithSameUsername = await strapi
|
|
103
|
+
.query('plugin::users-permissions.user')
|
|
104
|
+
.findOne({ where: { username } });
|
|
105
|
+
|
|
106
|
+
if (userWithSameUsername && userWithSameUsername.id != id) {
|
|
107
|
+
throw new ApplicationError('Username already taken');
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
if (_.has(ctx.request.body, 'email') && advancedConfigs.unique_email) {
|
|
112
|
+
const userWithSameEmail = await strapi
|
|
113
|
+
.query('plugin::users-permissions.user')
|
|
114
|
+
.findOne({ where: { email: email.toLowerCase() } });
|
|
115
|
+
|
|
116
|
+
if (userWithSameEmail && userWithSameEmail.id != id) {
|
|
117
|
+
throw new ApplicationError('Email already taken');
|
|
118
|
+
}
|
|
119
|
+
ctx.request.body.email = ctx.request.body.email.toLowerCase();
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
let updateData = {
|
|
123
|
+
...ctx.request.body,
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
const data = await getService('user').edit({ id }, updateData);
|
|
127
|
+
const sanitizedData = await sanitizeOutput(data, ctx);
|
|
128
|
+
|
|
129
|
+
ctx.send(sanitizedData);
|
|
130
|
+
},
|
|
42
131
|
|
|
43
132
|
/**
|
|
44
133
|
* Retrieve user records.
|
|
@@ -47,7 +136,7 @@ module.exports = {
|
|
|
47
136
|
async find(ctx, next, { populate } = {}) {
|
|
48
137
|
const users = await getService('user').fetchAll(ctx.query, populate);
|
|
49
138
|
|
|
50
|
-
ctx.body = users.map(
|
|
139
|
+
ctx.body = await Promise.all(users.map(user => sanitizeOutput(user, ctx)));
|
|
51
140
|
},
|
|
52
141
|
|
|
53
142
|
/**
|
|
@@ -59,7 +148,7 @@ module.exports = {
|
|
|
59
148
|
let data = await getService('user').fetch({ id });
|
|
60
149
|
|
|
61
150
|
if (data) {
|
|
62
|
-
data =
|
|
151
|
+
data = await sanitizeOutput(data, ctx);
|
|
63
152
|
}
|
|
64
153
|
|
|
65
154
|
ctx.body = data;
|
|
@@ -81,8 +170,9 @@ module.exports = {
|
|
|
81
170
|
const { id } = ctx.params;
|
|
82
171
|
|
|
83
172
|
const data = await getService('user').remove({ id });
|
|
173
|
+
const sanitizedUser = await sanitizeOutput(data, ctx);
|
|
84
174
|
|
|
85
|
-
ctx.send(
|
|
175
|
+
ctx.send(sanitizedUser);
|
|
86
176
|
},
|
|
87
177
|
|
|
88
178
|
/**
|
|
@@ -93,9 +183,9 @@ module.exports = {
|
|
|
93
183
|
const user = ctx.state.user;
|
|
94
184
|
|
|
95
185
|
if (!user) {
|
|
96
|
-
return ctx.
|
|
186
|
+
return ctx.unauthorized();
|
|
97
187
|
}
|
|
98
188
|
|
|
99
|
-
ctx.body =
|
|
189
|
+
ctx.body = await sanitizeOutput(user, ctx);
|
|
100
190
|
},
|
|
101
191
|
};
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { yup, validateYupSchema } = require('@strapi/utils');
|
|
4
|
+
|
|
5
|
+
const callbackBodySchema = yup.object().shape({
|
|
6
|
+
identifier: yup.string().required(),
|
|
7
|
+
password: yup.string().required(),
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
const registerBodySchema = yup.object().shape({
|
|
11
|
+
email: yup
|
|
12
|
+
.string()
|
|
13
|
+
.email()
|
|
14
|
+
.required(),
|
|
15
|
+
password: yup.string().required(),
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
const sendEmailConfirmationBodySchema = yup.object().shape({
|
|
19
|
+
email: yup
|
|
20
|
+
.string()
|
|
21
|
+
.email()
|
|
22
|
+
.required(),
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
module.exports = {
|
|
26
|
+
validateCallbackBody: validateYupSchema(callbackBodySchema),
|
|
27
|
+
validateRegisterBody: validateYupSchema(registerBodySchema),
|
|
28
|
+
validateSendEmailConfirmationBody: validateYupSchema(sendEmailConfirmationBodySchema),
|
|
29
|
+
};
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { yup, validateYupSchema } = require('@strapi/utils');
|
|
4
|
+
|
|
5
|
+
const deleteRoleSchema = yup.object().shape({
|
|
6
|
+
role: yup.strapiID().required(),
|
|
7
|
+
});
|
|
8
|
+
|
|
9
|
+
const createUserBodySchema = yup.object().shape({
|
|
10
|
+
email: yup
|
|
11
|
+
.string()
|
|
12
|
+
.email()
|
|
13
|
+
.required(),
|
|
14
|
+
username: yup
|
|
15
|
+
.string()
|
|
16
|
+
.min(1)
|
|
17
|
+
.required(),
|
|
18
|
+
password: yup
|
|
19
|
+
.string()
|
|
20
|
+
.min(1)
|
|
21
|
+
.required(),
|
|
22
|
+
role: yup.strapiID(),
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
const updateUserBodySchema = yup.object().shape({
|
|
26
|
+
email: yup
|
|
27
|
+
.string()
|
|
28
|
+
.email()
|
|
29
|
+
.min(1),
|
|
30
|
+
username: yup.string().min(1),
|
|
31
|
+
password: yup.string().min(1),
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
module.exports = {
|
|
35
|
+
validateCreateUserBody: validateYupSchema(createUserBodySchema),
|
|
36
|
+
validateUpdateUserBody: validateYupSchema(updateUserBodySchema),
|
|
37
|
+
validateDeleteRoleBody: validateYupSchema(deleteRoleSchema),
|
|
38
|
+
};
|
|
@@ -9,7 +9,7 @@ module.exports = [
|
|
|
9
9
|
policies: [
|
|
10
10
|
{
|
|
11
11
|
name: 'admin::hasPermissions',
|
|
12
|
-
|
|
12
|
+
config: {
|
|
13
13
|
actions: ['plugin::users-permissions.roles.read'],
|
|
14
14
|
},
|
|
15
15
|
},
|
|
@@ -24,7 +24,7 @@ module.exports = [
|
|
|
24
24
|
policies: [
|
|
25
25
|
{
|
|
26
26
|
name: 'admin::hasPermissions',
|
|
27
|
-
|
|
27
|
+
config: {
|
|
28
28
|
actions: ['plugin::users-permissions.roles.read'],
|
|
29
29
|
},
|
|
30
30
|
},
|
|
@@ -39,7 +39,7 @@ module.exports = [
|
|
|
39
39
|
policies: [
|
|
40
40
|
{
|
|
41
41
|
name: 'admin::hasPermissions',
|
|
42
|
-
|
|
42
|
+
config: {
|
|
43
43
|
actions: ['plugin::users-permissions.roles.create'],
|
|
44
44
|
},
|
|
45
45
|
},
|
|
@@ -54,7 +54,7 @@ module.exports = [
|
|
|
54
54
|
policies: [
|
|
55
55
|
{
|
|
56
56
|
name: 'admin::hasPermissions',
|
|
57
|
-
|
|
57
|
+
config: {
|
|
58
58
|
actions: ['plugin::users-permissions.roles.update'],
|
|
59
59
|
},
|
|
60
60
|
},
|
|
@@ -69,7 +69,7 @@ module.exports = [
|
|
|
69
69
|
policies: [
|
|
70
70
|
{
|
|
71
71
|
name: 'admin::hasPermissions',
|
|
72
|
-
|
|
72
|
+
config: {
|
|
73
73
|
actions: ['plugin::users-permissions.roles.delete'],
|
|
74
74
|
},
|
|
75
75
|
},
|