@akemona-org/strapi-plugin-users-permissions 3.7.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.
Files changed (143) hide show
  1. package/LICENSE +22 -0
  2. package/README.md +19 -0
  3. package/admin/src/assets/images/logo.svg +1 -0
  4. package/admin/src/components/BaselineAlignement/index.js +33 -0
  5. package/admin/src/components/Bloc/index.js +10 -0
  6. package/admin/src/components/BoundRoute/Components.js +78 -0
  7. package/admin/src/components/BoundRoute/index.js +56 -0
  8. package/admin/src/components/ContainerFluid/index.js +13 -0
  9. package/admin/src/components/FormBloc/index.js +61 -0
  10. package/admin/src/components/IntlInput/index.js +38 -0
  11. package/admin/src/components/ListBaselineAlignment/index.js +8 -0
  12. package/admin/src/components/ListRow/Components.js +74 -0
  13. package/admin/src/components/ListRow/index.js +35 -0
  14. package/admin/src/components/ModalForm/Wrapper.js +12 -0
  15. package/admin/src/components/ModalForm/index.js +59 -0
  16. package/admin/src/components/Permissions/ListWrapper.js +9 -0
  17. package/admin/src/components/Permissions/PermissionRow/BaselineAlignment.js +7 -0
  18. package/admin/src/components/Permissions/PermissionRow/CheckboxWrapper.js +37 -0
  19. package/admin/src/components/Permissions/PermissionRow/RowStyle.js +28 -0
  20. package/admin/src/components/Permissions/PermissionRow/SubCategory/ConditionsButtonWrapper.js +13 -0
  21. package/admin/src/components/Permissions/PermissionRow/SubCategory/PolicyWrapper.js +8 -0
  22. package/admin/src/components/Permissions/PermissionRow/SubCategory/SubCategoryWrapper.js +26 -0
  23. package/admin/src/components/Permissions/PermissionRow/SubCategory/index.js +116 -0
  24. package/admin/src/components/Permissions/PermissionRow/index.js +92 -0
  25. package/admin/src/components/Permissions/index.js +44 -0
  26. package/admin/src/components/Permissions/init.js +14 -0
  27. package/admin/src/components/Permissions/reducer.js +27 -0
  28. package/admin/src/components/Policies/Components.js +26 -0
  29. package/admin/src/components/Policies/index.js +61 -0
  30. package/admin/src/components/PrefixedIcon/index.js +27 -0
  31. package/admin/src/components/Roles/EmptyRole/BaselineAlignment.js +7 -0
  32. package/admin/src/components/Roles/EmptyRole/index.js +27 -0
  33. package/admin/src/components/Roles/RoleListWrapper/index.js +17 -0
  34. package/admin/src/components/Roles/RoleRow/RoleDescription.js +9 -0
  35. package/admin/src/components/Roles/RoleRow/index.js +45 -0
  36. package/admin/src/components/Roles/index.js +3 -0
  37. package/admin/src/components/SizedInput/index.js +24 -0
  38. package/admin/src/components/UsersPermissions/index.js +91 -0
  39. package/admin/src/components/UsersPermissions/init.js +11 -0
  40. package/admin/src/components/UsersPermissions/reducer.js +60 -0
  41. package/admin/src/containers/AdvancedSettings/index.js +218 -0
  42. package/admin/src/containers/AdvancedSettings/reducer.js +65 -0
  43. package/admin/src/containers/AdvancedSettings/utils/form.js +52 -0
  44. package/admin/src/containers/EmailTemplates/CustomTextInput.js +105 -0
  45. package/admin/src/containers/EmailTemplates/Wrapper.js +36 -0
  46. package/admin/src/containers/EmailTemplates/index.js +222 -0
  47. package/admin/src/containers/EmailTemplates/reducer.js +58 -0
  48. package/admin/src/containers/EmailTemplates/utils/forms.js +81 -0
  49. package/admin/src/containers/EmailTemplates/utils/schema.js +25 -0
  50. package/admin/src/containers/Providers/index.js +283 -0
  51. package/admin/src/containers/Providers/reducer.js +54 -0
  52. package/admin/src/containers/Providers/utils/createProvidersArray.js +21 -0
  53. package/admin/src/containers/Providers/utils/forms.js +205 -0
  54. package/admin/src/containers/Roles/CreatePage/index.js +167 -0
  55. package/admin/src/containers/Roles/CreatePage/utils/schema.js +9 -0
  56. package/admin/src/containers/Roles/EditPage/index.js +161 -0
  57. package/admin/src/containers/Roles/EditPage/utils/schema.js +9 -0
  58. package/admin/src/containers/Roles/ListPage/BaselineAlignment.js +8 -0
  59. package/admin/src/containers/Roles/ListPage/index.js +188 -0
  60. package/admin/src/containers/Roles/ProtectedCreatePage/index.js +12 -0
  61. package/admin/src/containers/Roles/ProtectedEditPage/index.js +12 -0
  62. package/admin/src/containers/Roles/ProtectedListPage/index.js +15 -0
  63. package/admin/src/containers/Roles/index.js +35 -0
  64. package/admin/src/contexts/EditPage/index.js +26 -0
  65. package/admin/src/contexts/HomePage/index.js +27 -0
  66. package/admin/src/contexts/UsersPermissionsContext/index.js +17 -0
  67. package/admin/src/hooks/index.js +5 -0
  68. package/admin/src/hooks/useFetchRole/index.js +55 -0
  69. package/admin/src/hooks/useFetchRole/reducer.js +31 -0
  70. package/admin/src/hooks/useForm/index.js +96 -0
  71. package/admin/src/hooks/useForm/reducer.js +59 -0
  72. package/admin/src/hooks/usePlugins/index.js +73 -0
  73. package/admin/src/hooks/usePlugins/init.js +5 -0
  74. package/admin/src/hooks/usePlugins/reducer.js +37 -0
  75. package/admin/src/hooks/useRolesList/index.js +62 -0
  76. package/admin/src/hooks/useRolesList/init.js +5 -0
  77. package/admin/src/hooks/useRolesList/reducer.js +31 -0
  78. package/admin/src/index.js +109 -0
  79. package/admin/src/permissions.js +33 -0
  80. package/admin/src/pluginId.js +5 -0
  81. package/admin/src/translations/ar.json +49 -0
  82. package/admin/src/translations/cs.json +55 -0
  83. package/admin/src/translations/de.json +68 -0
  84. package/admin/src/translations/dk.json +116 -0
  85. package/admin/src/translations/en.json +104 -0
  86. package/admin/src/translations/es.json +70 -0
  87. package/admin/src/translations/fr.json +55 -0
  88. package/admin/src/translations/id.json +69 -0
  89. package/admin/src/translations/index.js +55 -0
  90. package/admin/src/translations/it.json +68 -0
  91. package/admin/src/translations/ja.json +53 -0
  92. package/admin/src/translations/ko.json +55 -0
  93. package/admin/src/translations/ms.json +54 -0
  94. package/admin/src/translations/nl.json +53 -0
  95. package/admin/src/translations/pl.json +55 -0
  96. package/admin/src/translations/pt-BR.json +49 -0
  97. package/admin/src/translations/pt.json +53 -0
  98. package/admin/src/translations/ru.json +68 -0
  99. package/admin/src/translations/sk.json +57 -0
  100. package/admin/src/translations/sv.json +68 -0
  101. package/admin/src/translations/th.json +66 -0
  102. package/admin/src/translations/tr.json +53 -0
  103. package/admin/src/translations/uk.json +54 -0
  104. package/admin/src/translations/vi.json +55 -0
  105. package/admin/src/translations/zh-Hans.json +104 -0
  106. package/admin/src/translations/zh.json +53 -0
  107. package/admin/src/utils/cleanPermissions.js +25 -0
  108. package/admin/src/utils/formatPolicies.js +8 -0
  109. package/admin/src/utils/getRequestURL.js +5 -0
  110. package/admin/src/utils/getTrad.js +5 -0
  111. package/admin/src/utils/index.js +4 -0
  112. package/config/functions/bootstrap.js +234 -0
  113. package/config/layout.js +10 -0
  114. package/config/policies/isAuthenticated.js +9 -0
  115. package/config/policies/permissions.js +93 -0
  116. package/config/policies/rateLimit.js +33 -0
  117. package/config/request.json +6 -0
  118. package/config/routes.json +397 -0
  119. package/config/schema.graphql.js +280 -0
  120. package/config/security.json +5 -0
  121. package/config/users-permissions-actions.js +80 -0
  122. package/controllers/Auth.js +612 -0
  123. package/controllers/User.js +125 -0
  124. package/controllers/UsersPermissions.js +291 -0
  125. package/controllers/user/admin.js +224 -0
  126. package/controllers/user/api.js +173 -0
  127. package/controllers/validation/email-template.js +40 -0
  128. package/documentation/1.0.0/overrides/users-permissions-Role.json +281 -0
  129. package/documentation/1.0.0/overrides/users-permissions-User.json +325 -0
  130. package/middlewares/users-permissions/defaults.json +5 -0
  131. package/middlewares/users-permissions/index.js +40 -0
  132. package/models/Permission.js +7 -0
  133. package/models/Permission.settings.json +43 -0
  134. package/models/Role.js +7 -0
  135. package/models/Role.settings.json +42 -0
  136. package/models/User.config.js +15 -0
  137. package/models/User.js +7 -0
  138. package/models/User.settings.json +62 -0
  139. package/package.json +70 -0
  140. package/services/Jwt.js +65 -0
  141. package/services/Providers.js +596 -0
  142. package/services/User.js +167 -0
  143. package/services/UsersPermissions.js +416 -0
@@ -0,0 +1,167 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * User.js service
5
+ *
6
+ * @description: A set of functions similar to controller's actions to avoid code duplication.
7
+ */
8
+
9
+ const crypto = require('crypto');
10
+ const bcrypt = require('bcryptjs');
11
+
12
+ const { sanitizeEntity, getAbsoluteServerUrl } = require('@akemona-org/strapi-utils');
13
+
14
+ module.exports = {
15
+ /**
16
+ * Promise to count users
17
+ *
18
+ * @return {Promise}
19
+ */
20
+
21
+ count(params) {
22
+ return strapi.query('user', 'users-permissions').count(params);
23
+ },
24
+
25
+ /**
26
+ * Promise to search count users
27
+ *
28
+ * @return {Promise}
29
+ */
30
+
31
+ countSearch(params) {
32
+ return strapi.query('user', 'users-permissions').countSearch(params);
33
+ },
34
+
35
+ /**
36
+ * Promise to add a/an user.
37
+ * @return {Promise}
38
+ */
39
+ async add(values) {
40
+ if (values.password) {
41
+ values.password = await strapi.plugins['users-permissions'].services.user.hashPassword(
42
+ values
43
+ );
44
+ }
45
+
46
+ return strapi.query('user', 'users-permissions').create(values);
47
+ },
48
+
49
+ /**
50
+ * Promise to edit a/an user.
51
+ * @return {Promise}
52
+ */
53
+ async edit(params, values) {
54
+ if (values.password) {
55
+ values.password = await strapi.plugins['users-permissions'].services.user.hashPassword(
56
+ values
57
+ );
58
+ }
59
+
60
+ return strapi.query('user', 'users-permissions').update(params, values);
61
+ },
62
+
63
+ /**
64
+ * Promise to fetch a/an user.
65
+ * @return {Promise}
66
+ */
67
+ fetch(params, populate) {
68
+ return strapi.query('user', 'users-permissions').findOne(params, populate);
69
+ },
70
+
71
+ /**
72
+ * Promise to fetch authenticated user.
73
+ * @return {Promise}
74
+ */
75
+ fetchAuthenticatedUser(id) {
76
+ return strapi.query('user', 'users-permissions').findOne({ id }, ['role']);
77
+ },
78
+
79
+ /**
80
+ * Promise to fetch all users.
81
+ * @return {Promise}
82
+ */
83
+ fetchAll(params, populate) {
84
+ return strapi.query('user', 'users-permissions').find(params, populate);
85
+ },
86
+
87
+ hashPassword(user = {}) {
88
+ return new Promise((resolve, reject) => {
89
+ if (!user.password || this.isHashed(user.password)) {
90
+ resolve(null);
91
+ } else {
92
+ bcrypt.hash(`${user.password}`, 10, (err, hash) => {
93
+ if (err) {
94
+ return reject(err);
95
+ }
96
+ resolve(hash);
97
+ });
98
+ }
99
+ });
100
+ },
101
+
102
+ isHashed(password) {
103
+ if (typeof password !== 'string' || !password) {
104
+ return false;
105
+ }
106
+
107
+ return password.split('$').length === 4;
108
+ },
109
+
110
+ /**
111
+ * Promise to remove a/an user.
112
+ * @return {Promise}
113
+ */
114
+ async remove(params) {
115
+ return strapi.query('user', 'users-permissions').delete(params);
116
+ },
117
+
118
+ async removeAll(params) {
119
+ return strapi.query('user', 'users-permissions').delete(params);
120
+ },
121
+
122
+ validatePassword(password, hash) {
123
+ return bcrypt.compare(password, hash);
124
+ },
125
+
126
+ async sendConfirmationEmail(user) {
127
+ const userPermissionService = strapi.plugins['users-permissions'].services.userspermissions;
128
+ const pluginStore = await strapi.store({
129
+ environment: '',
130
+ type: 'plugin',
131
+ name: 'users-permissions',
132
+ });
133
+
134
+ const settings = await pluginStore
135
+ .get({ key: 'email' })
136
+ .then((storeEmail) => storeEmail['email_confirmation'].options);
137
+
138
+ const userInfo = sanitizeEntity(user, {
139
+ model: strapi.query('user', 'users-permissions').model,
140
+ });
141
+
142
+ const confirmationToken = crypto.randomBytes(20).toString('hex');
143
+
144
+ await this.edit({ id: user.id }, { confirmationToken });
145
+
146
+ settings.message = await userPermissionService.template(settings.message, {
147
+ URL: `${getAbsoluteServerUrl(strapi.config)}/auth/email-confirmation`,
148
+ USER: userInfo,
149
+ CODE: confirmationToken,
150
+ });
151
+
152
+ settings.object = await userPermissionService.template(settings.object, { USER: userInfo });
153
+
154
+ // Send an email to the user.
155
+ await strapi.plugins['email'].services.email.send({
156
+ to: user.email,
157
+ from:
158
+ settings.from.email && settings.from.name
159
+ ? `${settings.from.name} <${settings.from.email}>`
160
+ : undefined,
161
+ replyTo: settings.response_email,
162
+ subject: settings.object,
163
+ text: settings.message,
164
+ html: settings.message,
165
+ });
166
+ },
167
+ };
@@ -0,0 +1,416 @@
1
+ 'use strict';
2
+
3
+ const _ = require('lodash');
4
+ const request = require('request');
5
+
6
+ /**
7
+ * UsersPermissions.js service
8
+ *
9
+ * @description: A set of functions similar to controller's actions to avoid code duplication.
10
+ */
11
+
12
+ const DEFAULT_PERMISSIONS = [
13
+ { action: 'admincallback', controller: 'auth', type: 'users-permissions', roleType: 'public' },
14
+ { action: 'adminregister', controller: 'auth', type: 'users-permissions', roleType: 'public' },
15
+ { action: 'callback', controller: 'auth', type: 'users-permissions', roleType: 'public' },
16
+ { action: 'connect', controller: 'auth', type: 'users-permissions', roleType: null },
17
+ { action: 'forgotpassword', controller: 'auth', type: 'users-permissions', roleType: 'public' },
18
+ { action: 'register', controller: 'auth', type: 'users-permissions', roleType: 'public' },
19
+ {
20
+ action: 'emailconfirmation',
21
+ controller: 'auth',
22
+ type: 'users-permissions',
23
+ roleType: 'public',
24
+ },
25
+ { action: 'resetpassword', controller: 'auth', type: 'users-permissions', roleType: 'public' },
26
+ { action: 'init', controller: 'userspermissions', type: null, roleType: null },
27
+ { action: 'me', controller: 'user', type: 'users-permissions', roleType: null },
28
+ { action: 'autoreload', controller: null, type: null, roleType: null },
29
+ ];
30
+
31
+ const isPermissionEnabled = (permission, role) =>
32
+ DEFAULT_PERMISSIONS.some(
33
+ defaultPerm =>
34
+ (defaultPerm.action === null || permission.action === defaultPerm.action) &&
35
+ (defaultPerm.controller === null || permission.controller === defaultPerm.controller) &&
36
+ (defaultPerm.type === null || permission.type === defaultPerm.type) &&
37
+ (defaultPerm.roleType === null || role.type === defaultPerm.roleType)
38
+ );
39
+
40
+ module.exports = {
41
+ async createRole(params) {
42
+ if (!params.type) {
43
+ params.type = _.snakeCase(_.deburr(_.toLower(params.name)));
44
+ }
45
+
46
+ const role = await strapi
47
+ .query('role', 'users-permissions')
48
+ .create(_.omit(params, ['users', 'permissions']));
49
+
50
+ const arrayOfPromises = Object.keys(params.permissions || {}).reduce((acc, type) => {
51
+ Object.keys(params.permissions[type].controllers).forEach(controller => {
52
+ Object.keys(params.permissions[type].controllers[controller]).forEach(action => {
53
+ acc.push(
54
+ strapi.query('permission', 'users-permissions').create({
55
+ role: role.id,
56
+ type,
57
+ controller,
58
+ action: action.toLowerCase(),
59
+ ...params.permissions[type].controllers[controller][action],
60
+ })
61
+ );
62
+ });
63
+ });
64
+
65
+ return acc;
66
+ }, []);
67
+
68
+ // Use Content Manager business logic to handle relation.
69
+ if (params.users && params.users.length > 0)
70
+ arrayOfPromises.push(
71
+ strapi.query('role', 'users-permissions').update(
72
+ {
73
+ id: role.id,
74
+ },
75
+ { users: params.users }
76
+ )
77
+ );
78
+
79
+ return await Promise.all(arrayOfPromises);
80
+ },
81
+
82
+ async deleteRole(roleID, publicRoleID) {
83
+ const role = await strapi
84
+ .query('role', 'users-permissions')
85
+ .findOne({ id: roleID }, ['users', 'permissions']);
86
+
87
+ if (!role) {
88
+ throw new Error('Cannot find this role');
89
+ }
90
+
91
+ // Move users to guest role.
92
+ const arrayOfPromises = role.users.reduce((acc, user) => {
93
+ acc.push(
94
+ strapi.query('user', 'users-permissions').update(
95
+ {
96
+ id: user.id,
97
+ },
98
+ {
99
+ role: publicRoleID,
100
+ }
101
+ )
102
+ );
103
+
104
+ return acc;
105
+ }, []);
106
+
107
+ // Remove permissions related to this role.
108
+ role.permissions.forEach(permission => {
109
+ arrayOfPromises.push(
110
+ strapi.query('permission', 'users-permissions').delete({
111
+ id: permission.id,
112
+ })
113
+ );
114
+ });
115
+
116
+ // Delete the role.
117
+ arrayOfPromises.push(strapi.query('role', 'users-permissions').delete({ id: roleID }));
118
+
119
+ return await Promise.all(arrayOfPromises);
120
+ },
121
+
122
+ getPlugins(lang = 'en') {
123
+ return new Promise(resolve => {
124
+ request(
125
+ {
126
+ uri: `https://marketplace.strapi.io/plugins?lang=${lang}`,
127
+ json: true,
128
+ timeout: 3000,
129
+ headers: {
130
+ 'cache-control': 'max-age=3600',
131
+ },
132
+ },
133
+ (err, response, body) => {
134
+ if (err || response.statusCode !== 200) {
135
+ return resolve([]);
136
+ }
137
+
138
+ resolve(body);
139
+ }
140
+ );
141
+ });
142
+ },
143
+
144
+ getActions() {
145
+ const generateActions = data =>
146
+ Object.keys(data).reduce((acc, key) => {
147
+ if (_.isFunction(data[key])) {
148
+ acc[key] = { enabled: false, policy: '' };
149
+ }
150
+
151
+ return acc;
152
+ }, {});
153
+
154
+ const appControllers = Object.keys(strapi.api || {})
155
+ .filter(key => !!strapi.api[key].controllers)
156
+ .reduce(
157
+ (acc, key) => {
158
+ Object.keys(strapi.api[key].controllers).forEach(controller => {
159
+ acc.controllers[controller] = generateActions(strapi.api[key].controllers[controller]);
160
+ });
161
+
162
+ return acc;
163
+ },
164
+ { controllers: {} }
165
+ );
166
+
167
+ const pluginsPermissions = Object.keys(strapi.plugins).reduce((acc, key) => {
168
+ const initialState = {
169
+ controllers: {},
170
+ };
171
+
172
+ acc[key] = Object.keys(strapi.plugins[key].controllers).reduce((obj, k) => {
173
+ obj.controllers[k] = generateActions(strapi.plugins[key].controllers[k]);
174
+
175
+ return obj;
176
+ }, initialState);
177
+
178
+ return acc;
179
+ }, {});
180
+
181
+ const permissions = {
182
+ application: {
183
+ controllers: appControllers.controllers,
184
+ },
185
+ };
186
+
187
+ return _.merge(permissions, pluginsPermissions);
188
+ },
189
+
190
+ async getRole(roleID, plugins) {
191
+ const role = await strapi
192
+ .query('role', 'users-permissions')
193
+ .findOne({ id: roleID }, ['permissions']);
194
+
195
+ if (!role) {
196
+ throw new Error('Cannot find this role');
197
+ }
198
+
199
+ // Group by `type`.
200
+ const permissions = role.permissions.reduce((acc, permission) => {
201
+ _.set(acc, `${permission.type}.controllers.${permission.controller}.${permission.action}`, {
202
+ enabled: _.toNumber(permission.enabled) == true,
203
+ policy: permission.policy,
204
+ });
205
+
206
+ if (permission.type !== 'application' && !acc[permission.type].information) {
207
+ acc[permission.type].information =
208
+ plugins.find(plugin => plugin.id === permission.type) || {};
209
+ }
210
+
211
+ return acc;
212
+ }, {});
213
+
214
+ return {
215
+ ...role,
216
+ permissions,
217
+ };
218
+ },
219
+
220
+ async getRoles() {
221
+ const roles = await strapi.query('role', 'users-permissions').find({ _sort: 'name' }, []);
222
+
223
+ for (let i = 0; i < roles.length; ++i) {
224
+ roles[i].nb_users = await strapi
225
+ .query('user', 'users-permissions')
226
+ .count({ role: roles[i].id });
227
+ }
228
+
229
+ return roles;
230
+ },
231
+
232
+ async getRoutes() {
233
+ const routes = Object.keys(strapi.api || {}).reduce((acc, current) => {
234
+ return acc.concat(_.get(strapi.api[current].config, 'routes', []));
235
+ }, []);
236
+ const clonedPlugins = _.cloneDeep(strapi.plugins);
237
+ const pluginsRoutes = Object.keys(clonedPlugins || {}).reduce((acc, current) => {
238
+ const routes = _.get(clonedPlugins, [current, 'config', 'routes'], []).reduce((acc, curr) => {
239
+ const prefix = curr.config.prefix;
240
+ const path = prefix !== undefined ? `${prefix}${curr.path}` : `/${current}${curr.path}`;
241
+ _.set(curr, 'path', path);
242
+
243
+ return acc.concat(curr);
244
+ }, []);
245
+
246
+ acc[current] = routes;
247
+
248
+ return acc;
249
+ }, {});
250
+
251
+ return _.merge({ application: routes }, pluginsRoutes);
252
+ },
253
+
254
+ async updatePermissions() {
255
+ const { primaryKey } = strapi.query('permission', 'users-permissions');
256
+ const roles = await strapi.query('role', 'users-permissions').find({}, []);
257
+ const rolesMap = roles.reduce((map, role) => ({ ...map, [role[primaryKey]]: role }), {});
258
+
259
+ const dbPermissions = await strapi
260
+ .query('permission', 'users-permissions')
261
+ .find({ _limit: -1 });
262
+ let permissionsFoundInDB = dbPermissions.map(
263
+ p => `${p.type}.${p.controller}.${p.action}.${p.role[primaryKey]}`
264
+ );
265
+ permissionsFoundInDB = _.uniq(permissionsFoundInDB);
266
+
267
+ // Aggregate first level actions.
268
+ const appActions = Object.keys(strapi.api || {}).reduce((acc, api) => {
269
+ Object.keys(_.get(strapi.api[api], 'controllers', {})).forEach(controller => {
270
+ const actions = Object.keys(strapi.api[api].controllers[controller])
271
+ .filter(action => _.isFunction(strapi.api[api].controllers[controller][action]))
272
+ .map(action => `application.${controller}.${action.toLowerCase()}`);
273
+
274
+ acc = acc.concat(actions);
275
+ });
276
+
277
+ return acc;
278
+ }, []);
279
+
280
+ // Aggregate plugins' actions.
281
+ const pluginsActions = Object.keys(strapi.plugins).reduce((acc, plugin) => {
282
+ Object.keys(strapi.plugins[plugin].controllers).forEach(controller => {
283
+ const actions = Object.keys(strapi.plugins[plugin].controllers[controller])
284
+ .filter(action => _.isFunction(strapi.plugins[plugin].controllers[controller][action]))
285
+ .map(action => `${plugin}.${controller}.${action.toLowerCase()}`);
286
+
287
+ acc = acc.concat(actions);
288
+ });
289
+
290
+ return acc;
291
+ }, []);
292
+
293
+ const actionsFoundInFiles = appActions.concat(pluginsActions);
294
+
295
+ // create permissions for each role
296
+ let permissionsFoundInFiles = actionsFoundInFiles.reduce(
297
+ (acc, action) => [...acc, ...roles.map(role => `${action}.${role[primaryKey]}`)],
298
+ []
299
+ );
300
+ permissionsFoundInFiles = _.uniq(permissionsFoundInFiles);
301
+
302
+ // Compare to know if actions have been added or removed from controllers.
303
+ if (!_.isEqual(permissionsFoundInDB.sort(), permissionsFoundInFiles.sort())) {
304
+ const splitted = str => {
305
+ const [type, controller, action, roleId] = str.split('.');
306
+
307
+ return { type, controller, action, roleId };
308
+ };
309
+
310
+ // We have to know the difference to add or remove the permissions entries in the database.
311
+ const toRemove = _.difference(permissionsFoundInDB, permissionsFoundInFiles).map(splitted);
312
+ const toAdd = _.difference(permissionsFoundInFiles, permissionsFoundInDB).map(splitted);
313
+
314
+ const query = strapi.query('permission', 'users-permissions');
315
+
316
+ // Execute request to update entries in database for each role.
317
+ await Promise.all(
318
+ toAdd.map(permission =>
319
+ query.create({
320
+ type: permission.type,
321
+ controller: permission.controller,
322
+ action: permission.action,
323
+ enabled: isPermissionEnabled(permission, rolesMap[permission.roleId]),
324
+ policy: '',
325
+ role: permission.roleId,
326
+ })
327
+ )
328
+ );
329
+
330
+ await Promise.all(
331
+ toRemove.map(permission => {
332
+ const { type, controller, action, roleId: role } = permission;
333
+ return query.delete({ type, controller, action, role });
334
+ })
335
+ );
336
+ }
337
+ },
338
+
339
+ async initialize() {
340
+ const roleCount = await strapi.query('role', 'users-permissions').count();
341
+
342
+ if (roleCount === 0) {
343
+ await strapi.query('role', 'users-permissions').create({
344
+ name: 'Authenticated',
345
+ description: 'Default role given to authenticated user.',
346
+ type: 'authenticated',
347
+ });
348
+
349
+ await strapi.query('role', 'users-permissions').create({
350
+ name: 'Public',
351
+ description: 'Default role given to unauthenticated user.',
352
+ type: 'public',
353
+ });
354
+ }
355
+
356
+ return this.updatePermissions();
357
+ },
358
+
359
+ async updateRole(roleID, body) {
360
+ const [role, authenticated] = await Promise.all([
361
+ this.getRole(roleID, []),
362
+ strapi.query('role', 'users-permissions').findOne({ type: 'authenticated' }, []),
363
+ ]);
364
+
365
+ await strapi
366
+ .query('role', 'users-permissions')
367
+ .update({ id: roleID }, _.pick(body, ['name', 'description']));
368
+
369
+ await Promise.all(
370
+ Object.keys(body.permissions || {}).reduce((acc, type) => {
371
+ Object.keys(body.permissions[type].controllers).forEach(controller => {
372
+ Object.keys(body.permissions[type].controllers[controller]).forEach(action => {
373
+ const bodyAction = body.permissions[type].controllers[controller][action];
374
+ const currentAction = _.get(
375
+ role.permissions,
376
+ `${type}.controllers.${controller}.${action}`,
377
+ {}
378
+ );
379
+
380
+ if (!_.isEqual(bodyAction, currentAction)) {
381
+ acc.push(
382
+ strapi.query('permission', 'users-permissions').update(
383
+ {
384
+ role: roleID,
385
+ type,
386
+ controller,
387
+ action: action.toLowerCase(),
388
+ },
389
+ bodyAction
390
+ )
391
+ );
392
+ }
393
+ });
394
+ });
395
+
396
+ return acc;
397
+ }, [])
398
+ );
399
+
400
+ // Add user to this role.
401
+ const newUsers = _.differenceBy(body.users, role.users, 'id');
402
+ await Promise.all(newUsers.map(user => this.updateUserRole(user, roleID)));
403
+
404
+ const oldUsers = _.differenceBy(role.users, body.users, 'id');
405
+ await Promise.all(oldUsers.map(user => this.updateUserRole(user, authenticated.id)));
406
+ },
407
+
408
+ async updateUserRole(user, role) {
409
+ return strapi.query('user', 'users-permissions').update({ id: user.id }, { role });
410
+ },
411
+
412
+ template(layout, data) {
413
+ const compiledObject = _.template(layout);
414
+ return compiledObject(data);
415
+ },
416
+ };