2020-05-29 17:23:42 +02:00
|
|
|
'use strict';
|
|
|
|
|
2020-05-22 12:58:14 +02:00
|
|
|
const _ = require('lodash');
|
2020-08-14 16:50:29 +02:00
|
|
|
const { set } = require('lodash/fp');
|
2020-06-23 16:31:16 +02:00
|
|
|
const { generateTimestampCode, stringIncludes } = require('strapi-utils');
|
2020-06-18 11:40:50 +02:00
|
|
|
const { SUPER_ADMIN_CODE } = require('./constants');
|
2020-06-24 14:09:43 +02:00
|
|
|
const { createPermission } = require('../domain/permission');
|
2020-05-22 12:58:14 +02:00
|
|
|
|
2020-08-14 16:31:36 +02:00
|
|
|
const ACTIONS = {
|
|
|
|
publish: 'plugins::content-manager.explorer.publish',
|
|
|
|
};
|
|
|
|
|
2020-05-22 12:58:14 +02:00
|
|
|
const sanitizeRole = role => {
|
2020-05-29 11:09:17 +02:00
|
|
|
return _.omit(role, ['users', 'permissions']);
|
2020-05-22 12:58:14 +02:00
|
|
|
};
|
|
|
|
|
2020-05-19 14:51:08 +02:00
|
|
|
/**
|
|
|
|
* Create and save a role in database
|
|
|
|
* @param attributes A partial role object
|
|
|
|
* @returns {Promise<role>}
|
|
|
|
*/
|
2020-05-22 12:58:14 +02:00
|
|
|
const create = async attributes => {
|
2020-05-25 11:22:35 +02:00
|
|
|
const alreadyExists = await exists({ name: attributes.name });
|
2020-06-19 18:54:37 +02:00
|
|
|
|
2020-05-25 11:22:35 +02:00
|
|
|
if (alreadyExists) {
|
|
|
|
throw strapi.errors.badRequest('ValidationError', {
|
|
|
|
name: [`The name must be unique and a role with name \`${attributes.name}\` already exists.`],
|
|
|
|
});
|
2020-05-22 12:58:14 +02:00
|
|
|
}
|
|
|
|
|
2020-06-23 16:31:16 +02:00
|
|
|
const autoGeneratedCode = `${_.kebabCase(attributes.name)}-${generateTimestampCode()}`;
|
2020-06-19 18:54:37 +02:00
|
|
|
|
|
|
|
const rolesWithCode = {
|
|
|
|
...attributes,
|
|
|
|
code: attributes.code || autoGeneratedCode,
|
|
|
|
};
|
|
|
|
|
|
|
|
return strapi.query('role', 'admin').create(rolesWithCode);
|
2020-05-19 14:51:08 +02:00
|
|
|
};
|
2020-05-19 11:53:34 +02:00
|
|
|
|
2020-05-19 14:51:08 +02:00
|
|
|
/**
|
|
|
|
* Find a role in database
|
|
|
|
* @param params query params to find the role
|
2020-07-06 16:21:31 +02:00
|
|
|
* @param populate
|
2020-05-19 14:51:08 +02:00
|
|
|
* @returns {Promise<role>}
|
|
|
|
*/
|
2020-05-29 17:23:42 +02:00
|
|
|
const findOne = (params = {}, populate = []) => {
|
2020-05-29 11:09:17 +02:00
|
|
|
return strapi.query('role', 'admin').findOne(params, populate);
|
2020-05-19 14:51:08 +02:00
|
|
|
};
|
|
|
|
|
2020-05-29 18:19:12 +02:00
|
|
|
/**
|
|
|
|
* Find a role in database with usersCounts
|
|
|
|
* @param params query params to find the role
|
2020-07-06 16:21:31 +02:00
|
|
|
* @param populate
|
2020-05-29 18:19:12 +02:00
|
|
|
* @returns {Promise<role>}
|
|
|
|
*/
|
2020-06-01 09:56:53 +02:00
|
|
|
const findOneWithUsersCount = async (params = {}, populate = []) => {
|
2020-05-29 18:19:12 +02:00
|
|
|
const role = await strapi.query('role', 'admin').findOne(params, populate);
|
|
|
|
|
|
|
|
if (role) {
|
2020-07-06 16:21:31 +02:00
|
|
|
role.usersCount = await getUsersCount(role.id);
|
2020-05-29 18:19:12 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return role;
|
|
|
|
};
|
|
|
|
|
2020-05-18 16:29:32 +02:00
|
|
|
/**
|
|
|
|
* Find roles in database
|
|
|
|
* @param params query params to find the roles
|
2020-07-06 16:21:31 +02:00
|
|
|
* @param populate
|
2020-05-19 15:34:33 +02:00
|
|
|
* @returns {Promise<array>}
|
2020-05-18 16:29:32 +02:00
|
|
|
*/
|
2020-05-29 17:23:42 +02:00
|
|
|
const find = (params = {}, populate = []) => {
|
2020-05-29 11:09:17 +02:00
|
|
|
return strapi.query('role', 'admin').find(params, populate);
|
2020-05-18 16:29:32 +02:00
|
|
|
};
|
|
|
|
|
2020-05-19 15:40:04 +02:00
|
|
|
/**
|
|
|
|
* Find all roles in database
|
|
|
|
* @returns {Promise<array>}
|
|
|
|
*/
|
2020-05-29 18:19:12 +02:00
|
|
|
const findAllWithUsersCount = async (populate = []) => {
|
|
|
|
const roles = await strapi.query('role', 'admin').find({ _limit: -1 }, populate);
|
2020-05-29 18:59:47 +02:00
|
|
|
for (let role of roles) {
|
2020-07-06 16:21:31 +02:00
|
|
|
role.usersCount = await getUsersCount(role.id);
|
2020-05-29 18:59:47 +02:00
|
|
|
}
|
2020-05-29 18:19:12 +02:00
|
|
|
|
|
|
|
return roles;
|
2020-05-19 15:40:04 +02:00
|
|
|
};
|
|
|
|
|
2020-05-19 16:11:19 +02:00
|
|
|
/**
|
|
|
|
* Update a role in database
|
|
|
|
* @param params query params to find the role to update
|
|
|
|
* @param attributes A partial role object
|
|
|
|
* @returns {Promise<role>}
|
|
|
|
*/
|
2020-05-22 12:58:14 +02:00
|
|
|
const update = async (params, attributes) => {
|
2020-06-18 18:10:12 +02:00
|
|
|
const sanitizedAttributes = _.omit(attributes, ['code']);
|
2020-06-15 11:54:44 +02:00
|
|
|
|
2020-06-18 18:10:12 +02:00
|
|
|
if (_.has(params, 'id') && _.has(sanitizedAttributes, 'name')) {
|
|
|
|
const alreadyExists = await exists({
|
|
|
|
name: sanitizedAttributes.name,
|
|
|
|
id_ne: params.id,
|
|
|
|
});
|
2020-05-25 11:22:35 +02:00
|
|
|
if (alreadyExists) {
|
|
|
|
throw strapi.errors.badRequest('ValidationError', {
|
|
|
|
name: [
|
2020-06-18 18:10:12 +02:00
|
|
|
`The name must be unique and a role with name \`${sanitizedAttributes.name}\` already exists.`,
|
2020-05-25 11:22:35 +02:00
|
|
|
],
|
|
|
|
});
|
2020-05-22 12:58:14 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-06-18 18:10:12 +02:00
|
|
|
return strapi.query('role', 'admin').update(params, sanitizedAttributes);
|
2020-05-19 16:11:19 +02:00
|
|
|
};
|
|
|
|
|
2020-05-25 11:22:35 +02:00
|
|
|
/**
|
|
|
|
* Check if a role exists in database
|
|
|
|
* @param params query params to find the role
|
|
|
|
* @returns {Promise<boolean>}
|
|
|
|
*/
|
|
|
|
const exists = async params => {
|
|
|
|
const foundCount = await strapi.query('role', 'admin').count(params);
|
|
|
|
|
|
|
|
return foundCount > 0;
|
|
|
|
};
|
|
|
|
|
2020-08-03 11:20:42 +02:00
|
|
|
/**
|
2020-08-03 12:27:42 +02:00
|
|
|
* Count the number of roles based on search params
|
|
|
|
* @param params params used for the query
|
|
|
|
* @returns {Promise<number>}
|
2020-08-03 11:20:42 +02:00
|
|
|
*/
|
|
|
|
const count = async (params = {}) => {
|
|
|
|
return strapi.query('role', 'admin').count(params);
|
|
|
|
};
|
|
|
|
|
2020-05-27 13:15:52 +02:00
|
|
|
/**
|
|
|
|
* Delete roles in database if they have no user assigned
|
2020-05-29 17:23:42 +02:00
|
|
|
* @param ids query params to find the roles
|
|
|
|
* @returns {Promise<array>}
|
2020-05-27 13:15:52 +02:00
|
|
|
*/
|
2020-05-28 17:32:44 +02:00
|
|
|
const deleteByIds = async (ids = []) => {
|
2020-06-18 11:40:50 +02:00
|
|
|
const superAdminRole = await getSuperAdmin();
|
2020-06-23 16:31:16 +02:00
|
|
|
if (superAdminRole && stringIncludes(ids, superAdminRole.id)) {
|
2020-06-15 11:54:44 +02:00
|
|
|
throw strapi.errors.badRequest('ValidationError', {
|
|
|
|
ids: ['You cannot delete the super admin role'],
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2020-05-29 18:59:47 +02:00
|
|
|
for (let roleId of ids) {
|
|
|
|
const usersCount = await getUsersCount(roleId);
|
|
|
|
if (usersCount !== 0) {
|
|
|
|
throw strapi.errors.badRequest('ValidationError', {
|
|
|
|
ids: ['Some roles are still assigned to some users.'],
|
|
|
|
});
|
|
|
|
}
|
2020-05-27 13:15:52 +02:00
|
|
|
}
|
|
|
|
|
2020-05-29 11:09:17 +02:00
|
|
|
await strapi.admin.services.permission.deleteByRolesIds(ids);
|
2020-05-27 13:15:52 +02:00
|
|
|
|
2020-05-28 17:32:44 +02:00
|
|
|
let deletedRoles = await strapi.query('role', 'admin').delete({ id_in: ids });
|
2020-05-27 13:15:52 +02:00
|
|
|
|
|
|
|
if (!Array.isArray(deletedRoles)) {
|
|
|
|
deletedRoles = [deletedRoles];
|
|
|
|
}
|
|
|
|
|
|
|
|
return deletedRoles;
|
|
|
|
};
|
|
|
|
|
2020-05-29 18:19:12 +02:00
|
|
|
/** Count the number of users for some roles
|
2020-06-01 09:56:53 +02:00
|
|
|
* @returns {Promise<integer>}
|
2020-07-06 16:21:31 +02:00
|
|
|
* @param roleId
|
2020-05-29 18:19:12 +02:00
|
|
|
*/
|
2020-05-29 18:59:47 +02:00
|
|
|
const getUsersCount = async roleId => {
|
2020-06-12 18:42:07 +02:00
|
|
|
return strapi.query('user', 'admin').count({ roles: [roleId] });
|
2020-05-29 18:19:12 +02:00
|
|
|
};
|
|
|
|
|
2020-06-12 18:42:07 +02:00
|
|
|
/** Returns admin role
|
|
|
|
* @returns {Promise<role>}
|
|
|
|
*/
|
2020-06-18 11:40:50 +02:00
|
|
|
const getSuperAdmin = () => findOne({ code: SUPER_ADMIN_CODE });
|
2020-06-12 18:42:07 +02:00
|
|
|
|
|
|
|
/** Returns admin role with userCount
|
|
|
|
* @returns {Promise<role>}
|
|
|
|
*/
|
2020-06-18 11:40:50 +02:00
|
|
|
const getSuperAdminWithUsersCount = () => findOneWithUsersCount({ code: SUPER_ADMIN_CODE });
|
2020-06-12 18:42:07 +02:00
|
|
|
|
2020-06-24 14:09:43 +02:00
|
|
|
/** Create superAdmin, Author and Editor role is no role already exist
|
|
|
|
* @returns {Promise<>}
|
|
|
|
*/
|
|
|
|
const createRolesIfNoneExist = async ({ createPermissionsForAdmin = false } = {}) => {
|
|
|
|
const someRolesExist = await exists();
|
|
|
|
if (someRolesExist) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
const allActions = strapi.admin.services.permission.actionProvider.getAll();
|
|
|
|
const contentTypesActions = allActions.filter(a => a.section === 'contentTypes');
|
|
|
|
|
|
|
|
// create 3 roles
|
|
|
|
const superAdminRole = await create({
|
|
|
|
name: 'Super Admin',
|
|
|
|
code: 'strapi-super-admin',
|
|
|
|
description: 'Super Admins can access and manage all features and settings.',
|
|
|
|
});
|
|
|
|
|
|
|
|
await strapi.admin.services.user.assignARoleToAll(superAdminRole.id);
|
|
|
|
|
|
|
|
const editorRole = await create({
|
|
|
|
name: 'Editor',
|
|
|
|
code: 'strapi-editor',
|
|
|
|
description: 'Editors can manage and publish contents including those of other users.',
|
|
|
|
});
|
|
|
|
|
|
|
|
const authorRole = await create({
|
|
|
|
name: 'Author',
|
|
|
|
code: 'strapi-author',
|
2020-08-12 14:51:38 +02:00
|
|
|
description: 'Authors can manage the content they have created.',
|
2020-06-24 14:09:43 +02:00
|
|
|
});
|
|
|
|
|
|
|
|
// create content-type permissions for each role
|
2020-06-26 10:13:43 +02:00
|
|
|
const editorPermissions = strapi.admin.services['content-type'].getPermissionsWithNestedFields(
|
|
|
|
contentTypesActions,
|
|
|
|
{
|
2020-07-06 16:21:31 +02:00
|
|
|
restrictedSubjects: ['plugins::users-permissions.user'],
|
2020-06-26 10:13:43 +02:00
|
|
|
}
|
|
|
|
);
|
2020-06-24 14:09:43 +02:00
|
|
|
|
2020-08-14 16:31:36 +02:00
|
|
|
const authorPermissions = editorPermissions
|
|
|
|
.filter(({ action }) => action !== ACTIONS.publish)
|
2020-08-14 16:50:29 +02:00
|
|
|
.map(set('conditions', ['admin::is-creator']));
|
2020-06-24 14:09:43 +02:00
|
|
|
|
2020-07-07 20:02:27 +02:00
|
|
|
editorPermissions.push(...getDefaultPluginPermissions());
|
|
|
|
authorPermissions.push(...getDefaultPluginPermissions({ isAuthor: true }));
|
2020-06-24 14:09:43 +02:00
|
|
|
|
|
|
|
// assign permissions to roles
|
2020-10-19 14:48:03 +02:00
|
|
|
await strapi.admin.services.permission.createMany(editorRole.id, editorPermissions);
|
|
|
|
await strapi.admin.services.permission.createMany(authorRole.id, authorPermissions);
|
2020-06-24 14:09:43 +02:00
|
|
|
|
|
|
|
if (createPermissionsForAdmin) {
|
|
|
|
await strapi.admin.services.permission.resetSuperAdminPermissions();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2020-07-07 20:02:27 +02:00
|
|
|
const getDefaultPluginPermissions = ({ isAuthor = false } = {}) => {
|
|
|
|
const conditions = isAuthor ? ['admin::is-creator'] : null;
|
|
|
|
|
|
|
|
// add plugin permissions for each role
|
|
|
|
return [
|
|
|
|
{ action: 'plugins::upload.read', conditions },
|
|
|
|
{ action: 'plugins::upload.assets.create' },
|
|
|
|
{ action: 'plugins::upload.assets.update', conditions },
|
|
|
|
{ action: 'plugins::upload.assets.download' },
|
|
|
|
{ action: 'plugins::upload.assets.copy-link' },
|
|
|
|
].map(createPermission);
|
|
|
|
};
|
|
|
|
|
2020-06-24 14:09:43 +02:00
|
|
|
/** Display a warning if the role superAdmin doesn't exist
|
|
|
|
* or if the role is not assigned to at least one user
|
|
|
|
* @returns {Promise<>}
|
|
|
|
*/
|
|
|
|
const displayWarningIfNoSuperAdmin = async () => {
|
|
|
|
const superAdminRole = await getSuperAdminWithUsersCount();
|
|
|
|
const someUsersExists = await strapi.admin.services.user.exists();
|
|
|
|
if (!superAdminRole) {
|
|
|
|
strapi.log.warn("Your application doesn't have a super admin role.");
|
|
|
|
} else if (someUsersExists && superAdminRole.usersCount === 0) {
|
|
|
|
strapi.log.warn("Your application doesn't have a super admin user.");
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2020-05-19 14:51:08 +02:00
|
|
|
module.exports = {
|
2020-05-22 12:58:14 +02:00
|
|
|
sanitizeRole,
|
2020-05-19 14:51:08 +02:00
|
|
|
create,
|
|
|
|
findOne,
|
2020-06-01 09:56:53 +02:00
|
|
|
findOneWithUsersCount,
|
2020-05-18 16:29:32 +02:00
|
|
|
find,
|
2020-05-29 18:19:12 +02:00
|
|
|
findAllWithUsersCount,
|
2020-05-19 16:11:19 +02:00
|
|
|
update,
|
2020-05-25 11:22:35 +02:00
|
|
|
exists,
|
2020-08-03 11:20:42 +02:00
|
|
|
count,
|
2020-05-28 17:32:44 +02:00
|
|
|
deleteByIds,
|
2020-05-29 18:59:47 +02:00
|
|
|
getUsersCount,
|
2020-06-18 11:40:50 +02:00
|
|
|
getSuperAdmin,
|
|
|
|
getSuperAdminWithUsersCount,
|
2020-06-24 14:09:43 +02:00
|
|
|
createRolesIfNoneExist,
|
|
|
|
displayWarningIfNoSuperAdmin,
|
2020-05-18 16:21:02 +02:00
|
|
|
};
|