@strapi/plugin-users-permissions 4.0.0-next.7 → 4.0.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/admin/src/components/BoundRoute/getMethodColor.js +41 -0
- package/admin/src/components/BoundRoute/index.js +40 -24
- package/admin/src/components/FormModal/Input/index.js +121 -0
- package/admin/src/components/FormModal/index.js +123 -0
- package/admin/src/components/Permissions/PermissionRow/CheckboxWrapper.js +19 -26
- package/admin/src/components/Permissions/PermissionRow/SubCategory.js +118 -0
- package/admin/src/components/Permissions/PermissionRow/index.js +9 -48
- package/admin/src/components/Permissions/index.js +36 -24
- package/admin/src/components/Permissions/init.js +1 -6
- package/admin/src/components/Policies/index.js +46 -47
- package/admin/src/components/UsersPermissions/index.js +29 -26
- package/admin/src/components/UsersPermissions/init.js +1 -2
- package/admin/src/hooks/useFetchRole/index.js +17 -7
- package/admin/src/hooks/useForm/index.js +3 -29
- package/admin/src/hooks/useForm/reducer.js +2 -21
- package/admin/src/hooks/usePlugins/index.js +12 -21
- package/admin/src/hooks/usePlugins/reducer.js +0 -3
- package/admin/src/index.js +29 -34
- package/admin/src/pages/AdvancedSettings/index.js +210 -193
- package/admin/src/pages/AdvancedSettings/utils/api.js +13 -0
- package/admin/src/pages/AdvancedSettings/utils/layout.js +96 -0
- package/admin/src/pages/AdvancedSettings/utils/schema.js +21 -0
- package/admin/src/pages/EmailTemplates/components/EmailForm.js +173 -0
- package/admin/src/pages/EmailTemplates/components/EmailTable.js +116 -0
- package/admin/src/pages/EmailTemplates/index.js +125 -198
- package/admin/src/pages/EmailTemplates/utils/api.js +13 -0
- package/admin/src/pages/Providers/index.js +208 -216
- package/admin/src/pages/Providers/utils/api.js +21 -0
- package/admin/src/pages/Providers/utils/forms.js +168 -126
- package/admin/src/pages/Roles/CreatePage/index.js +155 -147
- package/admin/src/pages/Roles/EditPage/index.js +162 -134
- package/admin/src/pages/Roles/ListPage/components/TableBody.js +96 -0
- package/admin/src/pages/Roles/ListPage/index.js +176 -156
- package/admin/src/pages/Roles/ListPage/utils/api.js +28 -0
- package/admin/src/pages/Roles/index.js +14 -8
- package/admin/src/translations/ar.json +0 -8
- package/admin/src/translations/cs.json +0 -8
- package/admin/src/translations/de.json +0 -8
- package/admin/src/translations/dk.json +0 -8
- package/admin/src/translations/en.json +33 -12
- package/admin/src/translations/es.json +0 -8
- package/admin/src/translations/fr.json +0 -8
- package/admin/src/translations/id.json +0 -8
- package/admin/src/translations/it.json +0 -8
- package/admin/src/translations/ja.json +0 -8
- package/admin/src/translations/ko.json +93 -54
- package/admin/src/translations/ms.json +0 -8
- package/admin/src/translations/nl.json +0 -8
- package/admin/src/translations/pl.json +0 -8
- package/admin/src/translations/pt-BR.json +0 -8
- package/admin/src/translations/pt.json +0 -8
- package/admin/src/translations/ru.json +0 -8
- package/admin/src/translations/sk.json +0 -8
- package/admin/src/translations/sv.json +0 -8
- package/admin/src/translations/th.json +0 -8
- package/admin/src/translations/tr.json +0 -8
- package/admin/src/translations/uk.json +0 -8
- package/admin/src/translations/vi.json +0 -8
- package/admin/src/translations/zh-Hans.json +5 -14
- package/admin/src/translations/zh.json +0 -8
- package/admin/src/utils/axiosInstance.js +36 -0
- package/admin/src/utils/formatPluginName.js +26 -0
- package/admin/src/utils/index.js +1 -0
- package/documentation/1.0.0/overrides/users-permissions-Role.json +6 -6
- package/documentation/1.0.0/overrides/users-permissions-User.json +7 -7
- package/jest.config.front.js +10 -0
- package/package.json +35 -32
- package/server/bootstrap/index.js +20 -25
- package/server/config.js +3 -3
- package/server/content-types/index.js +3 -3
- package/server/content-types/permission/index.js +30 -3
- package/server/content-types/role/index.js +47 -3
- package/server/content-types/user/index.js +65 -4
- package/server/controllers/auth.js +85 -237
- package/server/controllers/content-manager-user.js +183 -0
- package/server/controllers/index.js +12 -6
- package/server/controllers/permissions.js +26 -0
- package/server/controllers/role.js +77 -0
- package/server/controllers/settings.js +85 -0
- package/server/controllers/user.js +119 -45
- package/server/controllers/validation/auth.js +29 -0
- package/server/controllers/validation/user.js +38 -0
- package/server/graphql/index.js +44 -0
- package/server/graphql/mutations/auth/email-confirmation.js +39 -0
- package/server/graphql/mutations/auth/forgot-password.js +38 -0
- package/server/graphql/mutations/auth/login.js +38 -0
- package/server/graphql/mutations/auth/register.js +39 -0
- package/server/graphql/mutations/auth/reset-password.js +41 -0
- package/server/graphql/mutations/crud/role/create-role.js +37 -0
- package/server/graphql/mutations/crud/role/delete-role.js +28 -0
- package/server/graphql/mutations/crud/role/update-role.js +38 -0
- package/server/graphql/mutations/crud/user/create-user.js +48 -0
- package/server/graphql/mutations/crud/user/delete-user.js +42 -0
- package/server/graphql/mutations/crud/user/update-user.js +49 -0
- package/server/graphql/mutations/index.js +42 -0
- package/server/graphql/queries/index.js +13 -0
- package/server/graphql/queries/me.js +17 -0
- package/server/graphql/resolvers-configs.js +37 -0
- package/server/graphql/types/create-role-payload.js +11 -0
- package/server/graphql/types/delete-role-payload.js +11 -0
- package/server/graphql/types/index.js +21 -0
- package/server/graphql/types/login-input.js +13 -0
- package/server/graphql/types/login-payload.js +12 -0
- package/server/graphql/types/me-role.js +14 -0
- package/server/graphql/types/me.js +16 -0
- package/server/graphql/types/password-payload.js +11 -0
- package/server/graphql/types/register-input.js +13 -0
- package/server/graphql/types/update-role-payload.js +11 -0
- package/server/graphql/utils.js +27 -0
- package/server/index.js +21 -0
- package/server/middlewares/index.js +2 -2
- package/server/{policies → middlewares}/rateLimit.js +3 -7
- package/server/register.js +11 -0
- package/server/routes/admin/index.js +10 -0
- package/server/routes/admin/permissions.js +20 -0
- package/server/routes/admin/role.js +79 -0
- package/server/routes/admin/settings.js +95 -0
- package/server/routes/content-api/auth.js +73 -0
- package/server/routes/content-api/index.js +11 -0
- package/server/routes/content-api/permissions.js +9 -0
- package/server/routes/content-api/role.js +29 -0
- package/server/routes/content-api/user.js +61 -0
- package/server/routes/index.js +4 -3
- package/server/services/index.js +10 -8
- package/server/services/jwt.js +9 -17
- package/server/services/providers.js +32 -33
- package/server/services/role.js +177 -0
- package/server/services/user.js +9 -15
- package/server/services/users-permissions.js +140 -338
- package/server/strategies/users-permissions.js +123 -0
- package/server/utils/index.d.ts +2 -0
- package/strapi-admin.js +3 -0
- package/strapi-server.js +1 -19
- package/admin/src/assets/images/logo.svg +0 -1
- package/admin/src/components/BaselineAlignement/index.js +0 -33
- package/admin/src/components/Bloc/index.js +0 -10
- package/admin/src/components/BoundRoute/Components.js +0 -78
- package/admin/src/components/ContainerFluid/index.js +0 -13
- package/admin/src/components/FormBloc/index.js +0 -61
- package/admin/src/components/IntlInput/index.js +0 -38
- package/admin/src/components/ListBaselineAlignment/index.js +0 -8
- package/admin/src/components/ListRow/Components.js +0 -74
- package/admin/src/components/ListRow/index.js +0 -35
- package/admin/src/components/ModalForm/Wrapper.js +0 -12
- package/admin/src/components/ModalForm/index.js +0 -59
- package/admin/src/components/Permissions/ListWrapper.js +0 -9
- package/admin/src/components/Permissions/PermissionRow/BaselineAlignment.js +0 -7
- package/admin/src/components/Permissions/PermissionRow/RowStyle.js +0 -28
- package/admin/src/components/Permissions/PermissionRow/SubCategory/ConditionsButtonWrapper.js +0 -13
- package/admin/src/components/Permissions/PermissionRow/SubCategory/PolicyWrapper.js +0 -8
- package/admin/src/components/Permissions/PermissionRow/SubCategory/SubCategoryWrapper.js +0 -26
- package/admin/src/components/Permissions/PermissionRow/SubCategory/index.js +0 -116
- package/admin/src/components/Policies/Components.js +0 -26
- package/admin/src/components/PrefixedIcon/index.js +0 -27
- package/admin/src/components/Roles/EmptyRole/BaselineAlignment.js +0 -7
- package/admin/src/components/Roles/EmptyRole/index.js +0 -27
- package/admin/src/components/Roles/RoleListWrapper/index.js +0 -17
- package/admin/src/components/Roles/RoleRow/RoleDescription.js +0 -9
- package/admin/src/components/Roles/RoleRow/index.js +0 -45
- package/admin/src/components/Roles/index.js +0 -3
- package/admin/src/components/SizedInput/index.js +0 -24
- package/admin/src/pages/AdvancedSettings/reducer.js +0 -65
- package/admin/src/pages/AdvancedSettings/utils/form.js +0 -52
- package/admin/src/pages/EmailTemplates/CustomTextInput.js +0 -105
- package/admin/src/pages/EmailTemplates/Wrapper.js +0 -36
- package/admin/src/pages/EmailTemplates/reducer.js +0 -58
- package/admin/src/pages/EmailTemplates/utils/forms.js +0 -81
- package/admin/src/pages/Roles/ListPage/BaselineAlignment.js +0 -8
- package/server/content-types/permission/schema.json +0 -48
- package/server/content-types/role/schema.json +0 -46
- package/server/content-types/user/schema.json +0 -66
- package/server/controllers/user/admin.js +0 -230
- package/server/controllers/user/api.js +0 -174
- package/server/controllers/users-permissions.js +0 -271
- package/server/middlewares/users-permissions.js +0 -36
- package/server/policies/index.js +0 -11
- package/server/policies/isAuthenticated.js +0 -9
- package/server/policies/permissions.js +0 -94
- package/server/routes/routes.json +0 -381
- package/server/schema.graphql.js +0 -317
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const _ = require('lodash');
|
|
4
|
+
const { contentTypes: contentTypesUtils } = require('@strapi/utils');
|
|
5
|
+
const {
|
|
6
|
+
ApplicationError,
|
|
7
|
+
ValidationError,
|
|
8
|
+
NotFoundError,
|
|
9
|
+
ForbiddenError,
|
|
10
|
+
} = require('@strapi/utils').errors;
|
|
11
|
+
const { validateCreateUserBody, validateUpdateUserBody } = require('./validation/user');
|
|
12
|
+
|
|
13
|
+
const { UPDATED_BY_ATTRIBUTE, CREATED_BY_ATTRIBUTE } = contentTypesUtils.constants;
|
|
14
|
+
|
|
15
|
+
const userModel = 'plugin::users-permissions.user';
|
|
16
|
+
const ACTIONS = {
|
|
17
|
+
read: 'plugin::content-manager.explorer.read',
|
|
18
|
+
create: 'plugin::content-manager.explorer.create',
|
|
19
|
+
edit: 'plugin::content-manager.explorer.update',
|
|
20
|
+
delete: 'plugin::content-manager.explorer.delete',
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
const findEntityAndCheckPermissions = async (ability, action, model, id) => {
|
|
24
|
+
const entity = await strapi.query(userModel).findOne({
|
|
25
|
+
where: { id },
|
|
26
|
+
populate: [`${CREATED_BY_ATTRIBUTE}.roles`],
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
if (_.isNil(entity)) {
|
|
30
|
+
throw new NotFoundError();
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const pm = strapi.admin.services.permission.createPermissionsManager({ ability, action, model });
|
|
34
|
+
|
|
35
|
+
if (pm.ability.cannot(pm.action, pm.toSubject(entity))) {
|
|
36
|
+
throw new ForbiddenError();
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const entityWithoutCreatorRoles = _.omit(entity, `${CREATED_BY_ATTRIBUTE}.roles`);
|
|
40
|
+
|
|
41
|
+
return { pm, entity: entityWithoutCreatorRoles };
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
module.exports = {
|
|
45
|
+
/**
|
|
46
|
+
* Create a/an user record.
|
|
47
|
+
* @return {Object}
|
|
48
|
+
*/
|
|
49
|
+
async create(ctx) {
|
|
50
|
+
const { body } = ctx.request;
|
|
51
|
+
const { user: admin, userAbility } = ctx.state;
|
|
52
|
+
|
|
53
|
+
const { email, username } = body;
|
|
54
|
+
|
|
55
|
+
const pm = strapi.admin.services.permission.createPermissionsManager({
|
|
56
|
+
ability: userAbility,
|
|
57
|
+
action: ACTIONS.create,
|
|
58
|
+
model: userModel,
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
if (!pm.isAllowed) {
|
|
62
|
+
return ctx.forbidden();
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const sanitizedBody = await pm.pickPermittedFieldsOf(body, { subject: userModel });
|
|
66
|
+
|
|
67
|
+
const advanced = await strapi
|
|
68
|
+
.store({ type: 'plugin', name: 'users-permissions', key: 'advanced' })
|
|
69
|
+
.get();
|
|
70
|
+
|
|
71
|
+
await validateCreateUserBody(ctx.request.body);
|
|
72
|
+
|
|
73
|
+
const userWithSameUsername = await strapi
|
|
74
|
+
.query('plugin::users-permissions.user')
|
|
75
|
+
.findOne({ where: { username } });
|
|
76
|
+
|
|
77
|
+
if (userWithSameUsername) {
|
|
78
|
+
throw new ApplicationError('Username already taken');
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
if (advanced.unique_email) {
|
|
82
|
+
const userWithSameEmail = await strapi
|
|
83
|
+
.query('plugin::users-permissions.user')
|
|
84
|
+
.findOne({ where: { email: email.toLowerCase() } });
|
|
85
|
+
|
|
86
|
+
if (userWithSameEmail) {
|
|
87
|
+
throw new ApplicationError('Email already taken');
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
const user = {
|
|
92
|
+
...sanitizedBody,
|
|
93
|
+
provider: 'local',
|
|
94
|
+
[CREATED_BY_ATTRIBUTE]: admin.id,
|
|
95
|
+
[UPDATED_BY_ATTRIBUTE]: admin.id,
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
user.email = _.toLower(user.email);
|
|
99
|
+
|
|
100
|
+
if (!user.role) {
|
|
101
|
+
const defaultRole = await strapi
|
|
102
|
+
.query('plugin::users-permissions.role')
|
|
103
|
+
.findOne({ where: { type: advanced.default_role } });
|
|
104
|
+
|
|
105
|
+
user.role = defaultRole.id;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
try {
|
|
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 });
|
|
113
|
+
|
|
114
|
+
ctx.created(sanitizedData);
|
|
115
|
+
} catch (error) {
|
|
116
|
+
throw new ApplicationError(error.message);
|
|
117
|
+
}
|
|
118
|
+
},
|
|
119
|
+
/**
|
|
120
|
+
* Update a/an user record.
|
|
121
|
+
* @return {Object}
|
|
122
|
+
*/
|
|
123
|
+
|
|
124
|
+
async update(ctx) {
|
|
125
|
+
const { id } = ctx.params;
|
|
126
|
+
const { body } = ctx.request;
|
|
127
|
+
const { user: admin, userAbility } = ctx.state;
|
|
128
|
+
|
|
129
|
+
const advancedConfigs = await strapi
|
|
130
|
+
.store({ type: 'plugin', name: 'users-permissions', key: 'advanced' })
|
|
131
|
+
.get();
|
|
132
|
+
|
|
133
|
+
const { email, username, password } = body;
|
|
134
|
+
|
|
135
|
+
let pm;
|
|
136
|
+
let user;
|
|
137
|
+
|
|
138
|
+
const { pm: permissionManager, entity } = await findEntityAndCheckPermissions(
|
|
139
|
+
userAbility,
|
|
140
|
+
ACTIONS.edit,
|
|
141
|
+
userModel,
|
|
142
|
+
id
|
|
143
|
+
);
|
|
144
|
+
pm = permissionManager;
|
|
145
|
+
user = entity;
|
|
146
|
+
|
|
147
|
+
await validateUpdateUserBody(ctx.request.body);
|
|
148
|
+
|
|
149
|
+
if (_.has(body, 'password') && !password && user.provider === 'local') {
|
|
150
|
+
throw new ValidationError('password.notNull');
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
if (_.has(body, 'username')) {
|
|
154
|
+
const userWithSameUsername = await strapi
|
|
155
|
+
.query('plugin::users-permissions.user')
|
|
156
|
+
.findOne({ where: { username } });
|
|
157
|
+
|
|
158
|
+
if (userWithSameUsername && userWithSameUsername.id != id) {
|
|
159
|
+
throw new ApplicationError('Username already taken');
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
if (_.has(body, 'email') && advancedConfigs.unique_email) {
|
|
164
|
+
const userWithSameEmail = await strapi
|
|
165
|
+
.query('plugin::users-permissions.user')
|
|
166
|
+
.findOne({ where: { email: _.toLower(email) } });
|
|
167
|
+
|
|
168
|
+
if (userWithSameEmail && userWithSameEmail.id != id) {
|
|
169
|
+
throw new ApplicationError('Email already taken');
|
|
170
|
+
}
|
|
171
|
+
body.email = _.toLower(body.email);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
const sanitizedData = await pm.pickPermittedFieldsOf(body, { subject: pm.toSubject(user) });
|
|
175
|
+
const updateData = _.omit({ ...sanitizedData, updatedBy: admin.id }, 'createdBy');
|
|
176
|
+
|
|
177
|
+
const data = await strapi
|
|
178
|
+
.service('plugin::content-manager.entity-manager')
|
|
179
|
+
.update({ id }, updateData, userModel);
|
|
180
|
+
|
|
181
|
+
ctx.body = await pm.sanitizeOutput(data, { action: ACTIONS.read });
|
|
182
|
+
},
|
|
183
|
+
};
|
|
@@ -1,11 +1,17 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
const
|
|
4
|
-
const
|
|
5
|
-
const
|
|
3
|
+
const auth = require('./auth');
|
|
4
|
+
const user = require('./user');
|
|
5
|
+
const role = require('./role');
|
|
6
|
+
const permissions = require('./permissions');
|
|
7
|
+
const settings = require('./settings');
|
|
8
|
+
const contentmanageruser = require('./content-manager-user');
|
|
6
9
|
|
|
7
10
|
module.exports = {
|
|
8
|
-
auth
|
|
9
|
-
user
|
|
10
|
-
|
|
11
|
+
auth,
|
|
12
|
+
user,
|
|
13
|
+
role,
|
|
14
|
+
permissions,
|
|
15
|
+
settings,
|
|
16
|
+
contentmanageruser,
|
|
11
17
|
};
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const _ = require('lodash');
|
|
4
|
+
const { getService } = require('../utils');
|
|
5
|
+
|
|
6
|
+
module.exports = {
|
|
7
|
+
async getPermissions(ctx) {
|
|
8
|
+
const permissions = await getService('users-permissions').getActions();
|
|
9
|
+
|
|
10
|
+
ctx.send({ permissions });
|
|
11
|
+
},
|
|
12
|
+
|
|
13
|
+
async getPolicies(ctx) {
|
|
14
|
+
const policies = _.keys(strapi.plugin('users-permissions').policies);
|
|
15
|
+
|
|
16
|
+
ctx.send({
|
|
17
|
+
policies: _.without(policies, 'permissions'),
|
|
18
|
+
});
|
|
19
|
+
},
|
|
20
|
+
|
|
21
|
+
async getRoutes(ctx) {
|
|
22
|
+
const routes = await getService('users-permissions').getRoutes();
|
|
23
|
+
|
|
24
|
+
ctx.send({ routes });
|
|
25
|
+
},
|
|
26
|
+
};
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const _ = require('lodash');
|
|
4
|
+
const { ApplicationError, ValidationError } = require('@strapi/utils').errors;
|
|
5
|
+
const { getService } = require('../utils');
|
|
6
|
+
const { validateDeleteRoleBody } = require('./validation/user');
|
|
7
|
+
|
|
8
|
+
module.exports = {
|
|
9
|
+
/**
|
|
10
|
+
* Default action.
|
|
11
|
+
*
|
|
12
|
+
* @return {Object}
|
|
13
|
+
*/
|
|
14
|
+
async createRole(ctx) {
|
|
15
|
+
if (_.isEmpty(ctx.request.body)) {
|
|
16
|
+
throw new ValidationError('Request body cannot be empty');
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
await getService('role').createRole(ctx.request.body);
|
|
20
|
+
|
|
21
|
+
ctx.send({ ok: true });
|
|
22
|
+
},
|
|
23
|
+
|
|
24
|
+
async getRole(ctx) {
|
|
25
|
+
const { id } = ctx.params;
|
|
26
|
+
|
|
27
|
+
const role = await getService('role').getRole(id);
|
|
28
|
+
|
|
29
|
+
if (!role) {
|
|
30
|
+
return ctx.notFound();
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
ctx.send({ role });
|
|
34
|
+
},
|
|
35
|
+
|
|
36
|
+
async getRoles(ctx) {
|
|
37
|
+
const roles = await getService('role').getRoles();
|
|
38
|
+
|
|
39
|
+
ctx.send({ roles });
|
|
40
|
+
},
|
|
41
|
+
|
|
42
|
+
async updateRole(ctx) {
|
|
43
|
+
const roleID = ctx.params.role;
|
|
44
|
+
|
|
45
|
+
if (_.isEmpty(ctx.request.body)) {
|
|
46
|
+
throw new ValidationError('Request body cannot be empty');
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
await getService('role').updateRole(roleID, ctx.request.body);
|
|
50
|
+
|
|
51
|
+
ctx.send({ ok: true });
|
|
52
|
+
},
|
|
53
|
+
|
|
54
|
+
async deleteRole(ctx) {
|
|
55
|
+
const roleID = ctx.params.role;
|
|
56
|
+
|
|
57
|
+
if (!roleID) {
|
|
58
|
+
await validateDeleteRoleBody(ctx.params);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// Fetch public role.
|
|
62
|
+
const publicRole = await strapi
|
|
63
|
+
.query('plugin::users-permissions.role')
|
|
64
|
+
.findOne({ where: { type: 'public' } });
|
|
65
|
+
|
|
66
|
+
const publicRoleID = publicRole.id;
|
|
67
|
+
|
|
68
|
+
// Prevent from removing the public role.
|
|
69
|
+
if (roleID.toString() === publicRoleID.toString()) {
|
|
70
|
+
throw new ApplicationError('Cannot delete public role');
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
await getService('role').deleteRole(roleID, publicRoleID);
|
|
74
|
+
|
|
75
|
+
ctx.send({ ok: true });
|
|
76
|
+
},
|
|
77
|
+
};
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const _ = require('lodash');
|
|
4
|
+
const { ValidationError } = require('@strapi/utils').errors;
|
|
5
|
+
const { getService } = require('../utils');
|
|
6
|
+
const { isValidEmailTemplate } = require('./validation/email-template');
|
|
7
|
+
|
|
8
|
+
module.exports = {
|
|
9
|
+
async getEmailTemplate(ctx) {
|
|
10
|
+
ctx.send(await strapi.store({ type: 'plugin', name: 'users-permissions', key: 'email' }).get());
|
|
11
|
+
},
|
|
12
|
+
|
|
13
|
+
async updateEmailTemplate(ctx) {
|
|
14
|
+
if (_.isEmpty(ctx.request.body)) {
|
|
15
|
+
throw new ValidationError('Request body cannot be empty');
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const emailTemplates = ctx.request.body['email-templates'];
|
|
19
|
+
|
|
20
|
+
for (let key in emailTemplates) {
|
|
21
|
+
const template = emailTemplates[key].options.message;
|
|
22
|
+
|
|
23
|
+
if (!isValidEmailTemplate(template)) {
|
|
24
|
+
throw new ValidationError('Invalid template');
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
await strapi
|
|
29
|
+
.store({ type: 'plugin', name: 'users-permissions', key: 'email' })
|
|
30
|
+
.set({ value: emailTemplates });
|
|
31
|
+
|
|
32
|
+
ctx.send({ ok: true });
|
|
33
|
+
},
|
|
34
|
+
|
|
35
|
+
async getAdvancedSettings(ctx) {
|
|
36
|
+
const settings = await strapi
|
|
37
|
+
.store({ type: 'plugin', name: 'users-permissions', key: 'advanced' })
|
|
38
|
+
.get();
|
|
39
|
+
|
|
40
|
+
const roles = await getService('role').getRoles();
|
|
41
|
+
|
|
42
|
+
ctx.send({ settings, roles });
|
|
43
|
+
},
|
|
44
|
+
|
|
45
|
+
async updateAdvancedSettings(ctx) {
|
|
46
|
+
if (_.isEmpty(ctx.request.body)) {
|
|
47
|
+
throw new ValidationError('Request body cannot be empty');
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
await strapi
|
|
51
|
+
.store({ type: 'plugin', name: 'users-permissions', key: 'advanced' })
|
|
52
|
+
.set({ value: ctx.request.body });
|
|
53
|
+
|
|
54
|
+
ctx.send({ ok: true });
|
|
55
|
+
},
|
|
56
|
+
|
|
57
|
+
async getProviders(ctx) {
|
|
58
|
+
const providers = await strapi
|
|
59
|
+
.store({ type: 'plugin', name: 'users-permissions', key: 'grant' })
|
|
60
|
+
.get();
|
|
61
|
+
|
|
62
|
+
for (const provider in providers) {
|
|
63
|
+
if (provider !== 'email') {
|
|
64
|
+
providers[provider].redirectUri = strapi
|
|
65
|
+
.plugin('users-permissions')
|
|
66
|
+
.service('providers')
|
|
67
|
+
.buildRedirectUri(provider);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
ctx.send(providers);
|
|
72
|
+
},
|
|
73
|
+
|
|
74
|
+
async updateProviders(ctx) {
|
|
75
|
+
if (_.isEmpty(ctx.request.body)) {
|
|
76
|
+
throw new ValidationError('Request body cannot be empty');
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
await strapi
|
|
80
|
+
.store({ type: 'plugin', name: 'users-permissions', key: 'grant' })
|
|
81
|
+
.set({ value: ctx.request.body.providers });
|
|
82
|
+
|
|
83
|
+
ctx.send({ ok: true });
|
|
84
|
+
},
|
|
85
|
+
};
|
|
@@ -7,47 +7,136 @@
|
|
|
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.
|
|
45
134
|
* @return {Object|Array}
|
|
46
135
|
*/
|
|
47
136
|
async find(ctx, next, { populate } = {}) {
|
|
48
|
-
const users = await getService('user').fetchAll(ctx.query, populate);
|
|
137
|
+
const users = await getService('user').fetchAll(ctx.query.filters, 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,10 +148,9 @@ 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
|
-
// Send 200 `ok`
|
|
66
154
|
ctx.body = data;
|
|
67
155
|
},
|
|
68
156
|
|
|
@@ -82,23 +170,9 @@ module.exports = {
|
|
|
82
170
|
const { id } = ctx.params;
|
|
83
171
|
|
|
84
172
|
const data = await getService('user').remove({ id });
|
|
173
|
+
const sanitizedUser = await sanitizeOutput(data, ctx);
|
|
85
174
|
|
|
86
|
-
ctx.send(
|
|
87
|
-
},
|
|
88
|
-
|
|
89
|
-
async destroyAll(ctx) {
|
|
90
|
-
const {
|
|
91
|
-
request: { query },
|
|
92
|
-
} = ctx;
|
|
93
|
-
|
|
94
|
-
const toRemove = Object.values(_.omit(query, 'source'));
|
|
95
|
-
|
|
96
|
-
// FIXME: delete many
|
|
97
|
-
const finalQuery = { id: toRemove };
|
|
98
|
-
|
|
99
|
-
const data = await getService('user').removeAll(finalQuery);
|
|
100
|
-
|
|
101
|
-
ctx.send(data);
|
|
175
|
+
ctx.send(sanitizedUser);
|
|
102
176
|
},
|
|
103
177
|
|
|
104
178
|
/**
|
|
@@ -109,9 +183,9 @@ module.exports = {
|
|
|
109
183
|
const user = ctx.state.user;
|
|
110
184
|
|
|
111
185
|
if (!user) {
|
|
112
|
-
return ctx.
|
|
186
|
+
return ctx.unauthorized();
|
|
113
187
|
}
|
|
114
188
|
|
|
115
|
-
ctx.body =
|
|
189
|
+
ctx.body = await sanitizeOutput(user, ctx);
|
|
116
190
|
},
|
|
117
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
|
+
};
|