432 lines
13 KiB
JavaScript
Raw Normal View History

'use strict';
2017-11-16 17:59:41 +01:00
const _ = require('lodash');
const request = require('request');
2021-07-08 18:15:32 +02:00
const { getService } = require('../utils');
const DEFAULT_PERMISSIONS = [
{ action: 'admincallback', controller: 'auth', type: 'users-permissions', roleType: 'public' },
{ action: 'adminregister', controller: 'auth', type: 'users-permissions', roleType: 'public' },
{ action: 'callback', controller: 'auth', type: 'users-permissions', roleType: 'public' },
{ action: 'connect', controller: 'auth', type: 'users-permissions', roleType: null },
{ action: 'forgotpassword', controller: 'auth', type: 'users-permissions', roleType: 'public' },
2021-08-02 08:28:10 +02:00
{ action: 'resetpassword', controller: 'auth', type: 'users-permissions', roleType: 'public' },
{ action: 'register', controller: 'auth', type: 'users-permissions', roleType: 'public' },
{
action: 'emailconfirmation',
controller: 'auth',
type: 'users-permissions',
roleType: 'public',
},
{ action: 'me', controller: 'user', type: 'users-permissions', roleType: null },
];
2021-08-02 08:28:10 +02:00
const isEnabledByDefault = (permission, role) => {
return DEFAULT_PERMISSIONS.some(
defaultPerm =>
(defaultPerm.action === null || permission.action === defaultPerm.action) &&
(defaultPerm.controller === null || permission.controller === defaultPerm.controller) &&
(defaultPerm.type === null || permission.type === defaultPerm.type) &&
(defaultPerm.roleType === null || role.type === defaultPerm.roleType)
);
2021-08-02 08:28:10 +02:00
};
2021-07-08 11:20:13 +02:00
module.exports = ({ strapi }) => ({
async createRole(params) {
if (!params.type) {
params.type = _.snakeCase(_.deburr(_.toLower(params.name)));
}
const role = await strapi
2021-08-06 18:09:49 +02:00
.query('plugin::users-permissions.role')
2021-07-08 18:15:32 +02:00
.create({ data: _.omit(params, ['users', 'permissions']) });
const arrayOfPromises = Object.keys(params.permissions || {}).reduce((acc, type) => {
Object.keys(params.permissions[type].controllers).forEach(controller => {
Object.keys(params.permissions[type].controllers[controller]).forEach(action => {
acc.push(
2021-08-06 18:09:49 +02:00
strapi.query('plugin::users-permissions.permission').create({
2021-07-08 18:15:32 +02:00
data: {
role: role.id,
type,
controller,
action: action.toLowerCase(),
...params.permissions[type].controllers[controller][action],
},
})
);
});
});
2017-11-27 16:49:56 +01:00
return acc;
}, []);
// Use Content Manager business logic to handle relation.
2019-07-16 20:52:31 +02:00
if (params.users && params.users.length > 0)
arrayOfPromises.push(
2021-08-06 18:09:49 +02:00
strapi.query('plugin::users-permissions.role').update({
2021-07-08 18:15:32 +02:00
where: {
2019-07-16 20:52:31 +02:00
id: role.id,
},
2021-07-08 18:15:32 +02:00
data: { users: params.users },
})
2019-07-16 20:52:31 +02:00
);
2017-12-01 16:06:16 +01:00
return await Promise.all(arrayOfPromises);
2017-11-27 17:02:45 +01:00
},
async deleteRole(roleID, publicRoleID) {
const role = await strapi
2021-08-06 18:09:49 +02:00
.query('plugin::users-permissions.role')
2021-07-08 18:15:32 +02:00
.findOne({ where: { id: roleID }, populate: ['users', 'permissions'] });
if (!role) {
2021-03-22 16:49:54 +01:00
throw new Error('Cannot find this role');
}
// Move users to guest role.
const arrayOfPromises = role.users.reduce((acc, user) => {
acc.push(
2021-08-06 18:09:49 +02:00
strapi.query('plugin::users-permissions.user').update({
2021-07-08 18:15:32 +02:00
where: {
id: user.id,
},
2021-07-08 18:15:32 +02:00
data: {
role: publicRoleID,
2021-07-08 18:15:32 +02:00
},
})
);
return acc;
}, []);
2017-11-27 17:50:51 +01:00
// Remove permissions related to this role.
role.permissions.forEach(permission => {
arrayOfPromises.push(
2021-08-06 18:09:49 +02:00
strapi.query('plugin::users-permissions.permission').delete({
2021-07-08 18:15:32 +02:00
where: { id: permission.id },
})
);
});
2017-12-01 16:06:16 +01:00
// Delete the role.
2021-07-08 18:15:32 +02:00
arrayOfPromises.push(
2021-08-06 18:09:49 +02:00
strapi.query('plugin::users-permissions.role').delete({ where: { id: roleID } })
2021-07-08 18:15:32 +02:00
);
2017-12-01 16:06:16 +01:00
return await Promise.all(arrayOfPromises);
2017-11-27 16:49:56 +01:00
},
getPlugins(lang = 'en') {
return new Promise(resolve => {
request(
{
uri: `https://marketplace.strapi.io/plugins?lang=${lang}`,
json: true,
timeout: 3000,
headers: {
'cache-control': 'max-age=3600',
},
},
(err, response, body) => {
if (err || response.statusCode !== 200) {
return resolve([]);
}
resolve(body);
2019-06-08 16:23:52 +02:00
}
);
});
},
getActions() {
const generateActions = data =>
2017-11-17 14:22:59 +01:00
Object.keys(data).reduce((acc, key) => {
if (_.isFunction(data[key])) {
acc[key] = { enabled: false, policy: '' };
}
2017-11-17 14:22:59 +01:00
return acc;
}, {});
2017-11-17 14:22:59 +01:00
const appControllers = Object.keys(strapi.api || {})
.filter(key => !!strapi.api[key].controllers)
.reduce(
(acc, key) => {
Object.keys(strapi.api[key].controllers).forEach(controller => {
acc.controllers[controller] = generateActions(strapi.api[key].controllers[controller]);
});
return acc;
},
2019-06-08 16:23:52 +02:00
{ controllers: {} }
);
2017-11-16 17:59:41 +01:00
const pluginsPermissions = Object.keys(strapi.plugins).reduce((acc, key) => {
const initialState = {
controllers: {},
};
2021-08-19 22:27:00 +02:00
const pluginControllers = strapi.plugin(key).controllers;
acc[key] = Object.keys(pluginControllers).reduce((obj, k) => {
obj.controllers[k] = generateActions(pluginControllers[k]);
return obj;
}, initialState);
return acc;
}, {});
2017-11-16 17:59:41 +01:00
const permissions = {
application: {
controllers: appControllers.controllers,
},
2017-11-16 17:59:41 +01:00
};
return _.merge(permissions, pluginsPermissions);
2017-11-17 16:36:57 +01:00
},
2017-11-17 14:22:59 +01:00
async getRole(roleID, plugins) {
const role = await strapi
2021-08-06 18:09:49 +02:00
.query('plugin::users-permissions.role')
2021-07-08 18:15:32 +02:00
.findOne({ where: { id: roleID }, populate: ['permissions'] });
if (!role) {
throw new Error('Cannot find this role');
}
2017-11-27 17:50:51 +01:00
2018-01-22 18:19:44 +01:00
// Group by `type`.
2019-07-18 15:49:24 +02:00
const permissions = role.permissions.reduce((acc, permission) => {
_.set(acc, `${permission.type}.controllers.${permission.controller}.${permission.action}`, {
enabled: _.toNumber(permission.enabled) == true,
policy: permission.policy,
});
if (permission.type !== 'application' && !acc[permission.type].information) {
acc[permission.type].information =
plugins.find(plugin => plugin.id === permission.type) || {};
2018-01-22 18:19:44 +01:00
}
return acc;
}, {});
2019-07-18 15:49:24 +02:00
return {
...role,
permissions,
};
2017-11-27 17:50:51 +01:00
},
async getRoles() {
2021-08-06 18:09:49 +02:00
const roles = await strapi.query('plugin::users-permissions.role').findMany({ sort: ['name'] });
2017-11-27 16:04:57 +01:00
for (let i = 0; i < roles.length; ++i) {
roles[i].nb_users = await strapi
2021-08-06 18:09:49 +02:00
.query('plugin::users-permissions.user')
2021-07-08 18:15:32 +02:00
.count({ where: { role: { id: roles[i].id } } });
}
2017-11-27 16:04:57 +01:00
return roles;
2017-11-27 16:04:57 +01:00
},
async getRoutes() {
const routes = Object.keys(strapi.api || {}).reduce((acc, current) => {
return acc.concat(_.get(strapi.api[current].config, 'routes', []));
}, []);
2021-07-29 16:39:26 +02:00
const pluginsRoutes = Object.keys(strapi.plugins).reduce((acc, current) => {
2021-08-11 10:05:20 +02:00
const routes = strapi.plugin(current).routes.reduce((acc, curr) => {
const prefix = curr.config.prefix;
const path = prefix !== undefined ? `${prefix}${curr.path}` : `/${current}${curr.path}`;
_.set(curr, 'path', path);
2017-11-30 16:34:43 +01:00
return acc.concat(curr);
}, []);
acc[current] = routes;
return acc;
}, {});
2017-12-07 18:16:18 +01:00
return _.merge({ application: routes }, pluginsRoutes);
2017-11-30 16:34:43 +01:00
},
async updatePermissions() {
2021-08-06 18:09:49 +02:00
const roles = await strapi.query('plugin::users-permissions.role').findMany();
2021-07-08 18:15:32 +02:00
2021-08-02 08:28:10 +02:00
const rolesMap = _.keyBy(roles, 'id');
const dbPermissions = await strapi
2021-08-06 18:09:49 +02:00
.query('plugin::users-permissions.permission')
2021-07-08 18:15:32 +02:00
.findMany({ populate: ['role'] });
let permissionsFoundInDB = dbPermissions.map(permission => {
const { type, controller, action, role } = permission;
return `${type}.${controller}.${action}.${role.id}`;
});
permissionsFoundInDB = _.uniq(permissionsFoundInDB);
// Aggregate first level actions.
const appActions = Object.keys(strapi.api || {}).reduce((acc, api) => {
Object.keys(_.get(strapi.api[api], 'controllers', {})).forEach(controller => {
const actions = Object.keys(strapi.api[api].controllers[controller])
.filter(action => _.isFunction(strapi.api[api].controllers[controller][action]))
.map(action => `application.${controller}.${action.toLowerCase()}`);
acc = acc.concat(actions);
});
2017-11-17 16:36:57 +01:00
return acc;
}, []);
2017-11-17 16:36:57 +01:00
// Aggregate plugins' actions.
const pluginsActions = Object.keys(strapi.plugins).reduce((acc, plugin) => {
2021-08-19 22:27:00 +02:00
const pluginControllers = strapi.plugin(plugin).controllers;
Object.keys(pluginControllers).forEach(controller => {
const controllerActions = pluginControllers[controller];
const actions = Object.keys(controllerActions)
.filter(action => _.isFunction(controllerActions[action]))
.map(action => `${plugin}.${controller}.${action.toLowerCase()}`);
acc = acc.concat(actions);
});
2017-12-07 10:16:36 +01:00
return acc;
}, []);
2017-11-17 16:36:57 +01:00
const actionsFoundInFiles = appActions.concat(pluginsActions);
2021-07-08 18:15:32 +02:00
const permissionsFoundInFiles = [];
for (const role of roles) {
actionsFoundInFiles.forEach(action => {
permissionsFoundInFiles.push(`${action}.${role.id}`);
});
}
// Compare to know if actions have been added or removed from controllers.
if (!_.isEqual(permissionsFoundInDB.sort(), permissionsFoundInFiles.sort())) {
const splitted = str => {
const [type, controller, action, roleId] = str.split('.');
return { type, controller, action, roleId };
};
// We have to know the difference to add or remove the permissions entries in the database.
const toRemove = _.difference(permissionsFoundInDB, permissionsFoundInFiles).map(splitted);
const toAdd = _.difference(permissionsFoundInFiles, permissionsFoundInDB).map(splitted);
2021-08-06 18:09:49 +02:00
const query = strapi.query('plugin::users-permissions.permission');
// Execute request to update entries in database for each role.
await Promise.all(
2021-08-02 08:28:10 +02:00
toAdd.map(permission => {
return query.create({
2021-07-08 18:15:32 +02:00
data: {
type: permission.type,
controller: permission.controller,
action: permission.action,
2021-08-02 08:28:10 +02:00
enabled: isEnabledByDefault(permission, rolesMap[permission.roleId]),
2021-07-08 18:15:32 +02:00
policy: '',
role: permission.roleId,
},
2021-08-02 08:28:10 +02:00
});
})
);
await Promise.all(
toRemove.map(permission => {
2021-07-08 18:15:32 +02:00
const { type, controller, action, roleId } = permission;
return query.delete({ where: { type, controller, action, role: { id: roleId } } });
})
);
2017-11-17 14:22:59 +01:00
}
2017-11-17 16:36:57 +01:00
},
2017-11-17 14:22:59 +01:00
2019-08-12 15:35:40 +02:00
async initialize() {
2021-08-06 18:09:49 +02:00
const roleCount = await strapi.query('plugin::users-permissions.role').count();
if (roleCount === 0) {
2021-08-06 18:09:49 +02:00
await strapi.query('plugin::users-permissions.role').create({
2021-07-08 18:15:32 +02:00
data: {
name: 'Authenticated',
description: 'Default role given to authenticated user.',
type: 'authenticated',
},
});
2021-08-06 18:09:49 +02:00
await strapi.query('plugin::users-permissions.role').create({
2021-07-08 18:15:32 +02:00
data: {
name: 'Public',
description: 'Default role given to unauthenticated user.',
type: 'public',
},
});
}
2021-07-08 21:53:30 +02:00
return getService('users-permissions').updatePermissions();
},
async updateRole(roleID, body) {
const [role, authenticated] = await Promise.all([
2018-01-22 18:19:44 +01:00
this.getRole(roleID, []),
2021-08-06 18:09:49 +02:00
strapi.query('plugin::users-permissions.role').findOne({ where: { type: 'authenticated' } }),
2018-01-22 18:19:44 +01:00
]);
2017-11-27 17:50:51 +01:00
2021-08-06 18:09:49 +02:00
await strapi.query('plugin::users-permissions.role').update({
2021-07-08 18:15:32 +02:00
where: { id: roleID },
data: _.pick(body, ['name', 'description']),
});
2019-07-16 20:52:31 +02:00
await Promise.all(
Object.keys(body.permissions || {}).reduce((acc, type) => {
Object.keys(body.permissions[type].controllers).forEach(controller => {
Object.keys(body.permissions[type].controllers[controller]).forEach(action => {
const bodyAction = body.permissions[type].controllers[controller][action];
const currentAction = _.get(
role.permissions,
`${type}.controllers.${controller}.${action}`,
{}
);
if (!_.isEqual(bodyAction, currentAction)) {
acc.push(
2021-08-06 18:09:49 +02:00
strapi.query('plugin::users-permissions.permission').update({
2021-07-08 18:15:32 +02:00
where: {
role: roleID,
type,
controller,
action: action.toLowerCase(),
},
2021-07-08 18:15:32 +02:00
data: bodyAction,
})
);
2019-06-08 16:23:52 +02:00
}
});
2018-01-22 18:19:44 +01:00
});
return acc;
2019-07-16 20:52:31 +02:00
}, [])
);
2018-01-22 18:19:44 +01:00
// Add user to this role.
2019-07-16 20:52:31 +02:00
const newUsers = _.differenceBy(body.users, role.users, 'id');
await Promise.all(newUsers.map(user => this.updateUserRole(user, roleID)));
2017-12-05 16:44:54 +01:00
2019-07-16 20:52:31 +02:00
const oldUsers = _.differenceBy(role.users, body.users, 'id');
await Promise.all(oldUsers.map(user => this.updateUserRole(user, authenticated.id)));
2017-11-27 17:50:51 +01:00
},
async updateUserRole(user, role) {
2021-07-08 18:15:32 +02:00
return strapi
2021-08-06 18:09:49 +02:00
.query('plugin::users-permissions.user')
2021-07-08 18:15:32 +02:00
.update({ where: { id: user.id }, data: { role } });
2017-12-07 10:16:36 +01:00
},
template(layout, data) {
2018-01-25 08:38:46 +01:00
const compiledObject = _.template(layout);
return compiledObject(data);
},
2021-07-08 11:20:13 +02:00
});