feat: integrate relation syncing in default config type (permission relations)
parent
db9745ef81
commit
eff6cb50eb
|
@ -1,5 +1,7 @@
|
||||||
const { logMessage, sanitizeConfig } = require('../utils');
|
const { logMessage, sanitizeConfig, dynamicSort } = require('../utils');
|
||||||
const difference = require('../utils/getObjectDiff');
|
const difference = require('../utils/getObjectDiff');
|
||||||
|
const arrayDifference = require('../utils/getArrayDiff');
|
||||||
|
|
||||||
|
|
||||||
const ConfigType = class ConfigType {
|
const ConfigType = class ConfigType {
|
||||||
constructor(queryString, configPrefix, uid, jsonFields, relations) {
|
constructor(queryString, configPrefix, uid, jsonFields, relations) {
|
||||||
|
@ -10,7 +12,7 @@ const ConfigType = class ConfigType {
|
||||||
this.configPrefix = configPrefix;
|
this.configPrefix = configPrefix;
|
||||||
this.uid = uid;
|
this.uid = uid;
|
||||||
this.jsonFields = jsonFields || [];
|
this.jsonFields = jsonFields || [];
|
||||||
this.relations = relations || {};
|
this.relations = relations || [];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -55,7 +57,7 @@ const ConfigType = class ConfigType {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Import a single core-store config file into the db.
|
* Import a single role-permissions config file into the db.
|
||||||
*
|
*
|
||||||
* @param {string} configName - The name of the config file.
|
* @param {string} configName - The name of the config file.
|
||||||
* @param {string} configContent - The JSON content of the config file.
|
* @param {string} configContent - The JSON content of the config file.
|
||||||
|
@ -68,48 +70,124 @@ const ConfigType = class ConfigType {
|
||||||
|
|
||||||
const queryAPI = strapi.query(this.queryString);
|
const queryAPI = strapi.query(this.queryString);
|
||||||
|
|
||||||
const configExists = await queryAPI
|
let existingConfig = await queryAPI
|
||||||
.findOne({ where: { [this.uid]: configName } });
|
.findOne({
|
||||||
|
where: { [this.uid]: configName },
|
||||||
|
populate: this.relations.map(({ relationName }) => relationName),
|
||||||
|
});
|
||||||
|
|
||||||
if (configExists && configContent === null) {
|
if (existingConfig && configContent === null) {
|
||||||
await queryAPI.delete({ where: { [this.uid]: configName } });
|
const entity = await queryAPI.findOne({
|
||||||
|
where: { [this.uid]: configName },
|
||||||
|
populate: this.relations.map(({ relationName }) => relationName),
|
||||||
|
});
|
||||||
|
|
||||||
|
await Promise.all(this.relations.map(async ({ queryString, parentName }) => {
|
||||||
|
const relations = await strapi.query(queryString).findMany({
|
||||||
|
where: {
|
||||||
|
[parentName]: entity.id,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
await Promise.all(relations.map(async (relation) => {
|
||||||
|
await strapi.query(queryString).delete({
|
||||||
|
where: { id: relation.id },
|
||||||
|
});
|
||||||
|
}));
|
||||||
|
}));
|
||||||
|
|
||||||
|
await queryAPI.delete({
|
||||||
|
where: { id: entity.id },
|
||||||
|
});
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!configExists) {
|
if (!existingConfig) {
|
||||||
|
// Format JSON fields.
|
||||||
const query = { ...configContent };
|
const query = { ...configContent };
|
||||||
this.jsonFields.map((field) => query[field] = JSON.stringify(configContent[field]));
|
this.jsonFields.map((field) => query[field] = JSON.stringify(configContent[field]));
|
||||||
await queryAPI.create({ data: query });
|
|
||||||
|
// Create entity.
|
||||||
|
this.relations.map(({ relationName }) => delete query[relationName]);
|
||||||
|
const newEntity = await queryAPI.create({ data: query });
|
||||||
|
|
||||||
|
// Create relation entities.
|
||||||
|
this.relations.map(async ({ queryString, relationName, parentName }) => {
|
||||||
|
const relationQueryApi = strapi.query(queryString);
|
||||||
|
|
||||||
|
configContent[relationName].map(async (relationEntity) => {
|
||||||
|
const relationQuery = { ...relationEntity, [parentName]: newEntity };
|
||||||
|
await relationQueryApi.create({ data: relationQuery });
|
||||||
|
});
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
|
// Format JSON fields.
|
||||||
|
configContent = sanitizeConfig(configContent);
|
||||||
const query = { ...configContent };
|
const query = { ...configContent };
|
||||||
this.jsonFields.map((field) => query[field] = JSON.stringify(configContent[field]));
|
this.jsonFields.map((field) => query[field] = JSON.stringify(configContent[field]));
|
||||||
await queryAPI.update({ where: { [this.uid]: configName }, data: { ...query } });
|
|
||||||
|
// Update entity.
|
||||||
|
this.relations.map(({ relationName }) => delete query[relationName]);
|
||||||
|
const entity = await queryAPI.update({ where: { [this.uid]: configName }, data: query });
|
||||||
|
|
||||||
|
// Delete/create relations.
|
||||||
|
this.relations.map(async ({ queryString, relationName, parentName, relationSortField }) => {
|
||||||
|
const relationQueryApi = strapi.query(queryString);
|
||||||
|
existingConfig = sanitizeConfig(existingConfig, relationName, relationSortField);
|
||||||
|
configContent = sanitizeConfig(configContent, relationName, relationSortField);
|
||||||
|
|
||||||
|
const configToAdd = arrayDifference(configContent[relationName], existingConfig[relationName], relationSortField);
|
||||||
|
const configToDelete = arrayDifference(existingConfig[relationName], configContent[relationName], relationSortField);
|
||||||
|
|
||||||
|
configToDelete.map(async (config) => {
|
||||||
|
await relationQueryApi.delete({
|
||||||
|
where: {
|
||||||
|
[relationSortField]: config[relationSortField],
|
||||||
|
[parentName]: entity.id,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
configToAdd.map(async (config) => {
|
||||||
|
await relationQueryApi.create({
|
||||||
|
data: { ...config, [parentName]: entity.id },
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get all core-store config from the db.
|
* Get all role-permissions config from the db.
|
||||||
*
|
*
|
||||||
* @returns {object} Object with key value pairs of configs.
|
* @returns {object} Object with key value pairs of configs.
|
||||||
*/
|
*/
|
||||||
getAllFromDatabase = async () => {
|
getAllFromDatabase = async () => {
|
||||||
const AllConfig = await strapi.query(this.queryString).findMany({ _limit: -1 });
|
const AllConfig = await strapi.query(this.queryString).findMany({ limit: 0 });
|
||||||
const configs = {};
|
const configs = {};
|
||||||
|
|
||||||
Object.values(AllConfig).map((config) => {
|
await Promise.all(Object.values(AllConfig).map(async (config) => {
|
||||||
// Check if the config should be excluded.
|
// Check if the config should be excluded.
|
||||||
const shouldExclude = strapi.config.get('plugin.config-sync.exclude').includes(`${this.configPrefix}.${config[this.uid]}`);
|
const shouldExclude = strapi.config.get('plugin.config-sync.exclude').includes(`${this.configPrefix}.${config[this.uid]}`);
|
||||||
if (shouldExclude) return;
|
if (shouldExclude) return;
|
||||||
|
|
||||||
config = sanitizeConfig(config);
|
const formattedConfig = { ...sanitizeConfig(config) };
|
||||||
|
await Promise.all(this.relations.map(async ({ queryString, relationName, relationSortField, parentName }) => {
|
||||||
const formattedObject = { ...config };
|
const relations = await strapi.query(queryString).findMany({
|
||||||
this.jsonFields.map((field) => formattedObject[field] = JSON.parse(config[field]));
|
where: { [parentName]: { [this.uid]: config[this.uid] } },
|
||||||
|
|
||||||
configs[`${this.configPrefix}.${config[this.uid]}`] = formattedObject;
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
relations.map((relation) => sanitizeConfig(relation));
|
||||||
|
relations.sort(dynamicSort(relationSortField));
|
||||||
|
formattedConfig[relationName] = relations;
|
||||||
|
}));
|
||||||
|
|
||||||
|
this.jsonFields.map((field) => formattedConfig[field] = JSON.parse(config[field]));
|
||||||
|
configs[`${this.configPrefix}.${config[this.uid]}`] = formattedConfig;
|
||||||
|
}));
|
||||||
|
|
||||||
|
|
||||||
return configs;
|
return configs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,83 +0,0 @@
|
||||||
const { sanitizeConfig } = require('../utils');
|
|
||||||
const ConfigType = require("../services/type");
|
|
||||||
|
|
||||||
const AdminRolePermissionsConfigType = class AdminRolePermissionsConfigType extends ConfigType {
|
|
||||||
/**
|
|
||||||
* Import a single role-permissions config file into the db.
|
|
||||||
*
|
|
||||||
* @param {string} configName - The name of the config file.
|
|
||||||
* @param {string} configContent - The JSON content of the config file.
|
|
||||||
* @returns {void}
|
|
||||||
*/
|
|
||||||
importSingle = async (configName, configContent) => {
|
|
||||||
// Check if the config should be excluded.
|
|
||||||
const shouldExclude = strapi.config.get('plugin.config-sync.exclude').includes(`${this.configPrefix}.${configName}`);
|
|
||||||
if (shouldExclude) return;
|
|
||||||
|
|
||||||
const queryAPI = strapi.query(this.queryString);
|
|
||||||
|
|
||||||
const existingConfig = await queryAPI
|
|
||||||
.findOne({ where: { [this.uid]: configName } });
|
|
||||||
|
|
||||||
if (existingConfig && configContent === null) {
|
|
||||||
await queryAPI.delete({
|
|
||||||
where: { [this.uid]: configName },
|
|
||||||
populate: this.relations.map(({ relationName }) => relationName),
|
|
||||||
});
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!existingConfig) {
|
|
||||||
// Format JSON fields.
|
|
||||||
const query = { ...configContent };
|
|
||||||
this.jsonFields.map((field) => query[field] = JSON.stringify(configContent[field]));
|
|
||||||
|
|
||||||
this.relations.map(({ queryString }) => {
|
|
||||||
const queryAPI = strapi.query(queryString);
|
|
||||||
|
|
||||||
// Compare relations
|
|
||||||
// Make changes to the db
|
|
||||||
});
|
|
||||||
|
|
||||||
await queryAPI.create({ data: query });
|
|
||||||
} else {
|
|
||||||
const query = { ...configContent };
|
|
||||||
this.jsonFields.map((field) => query[field] = JSON.stringify(configContent[field]));
|
|
||||||
await queryAPI.update({ where: { [this.uid]: configName }, data: { ...query } });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get all role-permissions config from the db.
|
|
||||||
*
|
|
||||||
* @returns {object} Object with key value pairs of configs.
|
|
||||||
*/
|
|
||||||
getAllFromDatabase = async () => {
|
|
||||||
const AllConfig = await strapi.query(this.queryString).findMany({ limit: 0 });
|
|
||||||
const configs = {};
|
|
||||||
|
|
||||||
await Promise.all(Object.values(AllConfig).map(async (config) => {
|
|
||||||
// Check if the config should be excluded.
|
|
||||||
const shouldExclude = strapi.config.get('plugin.config-sync.exclude').includes(`${this.configPrefix}.${config[this.uid]}`);
|
|
||||||
if (shouldExclude) return;
|
|
||||||
|
|
||||||
config = sanitizeConfig(config);
|
|
||||||
|
|
||||||
const existingPermissions = await strapi.admin.services.permission.findMany({
|
|
||||||
where: { role: { code: config.code } },
|
|
||||||
});
|
|
||||||
|
|
||||||
existingPermissions.map((permission) => sanitizeConfig(permission));
|
|
||||||
|
|
||||||
const formattedObject = { ...config, permissions: existingPermissions };
|
|
||||||
this.jsonFields.map((field) => formattedObject[field] = JSON.parse(config[field]));
|
|
||||||
|
|
||||||
configs[`${this.configPrefix}.${config[this.uid]}`] = formattedObject;
|
|
||||||
}));
|
|
||||||
|
|
||||||
return configs;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
module.exports = AdminRolePermissionsConfigType;
|
|
|
@ -1,14 +1,23 @@
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
const ConfigType = require("../services/type");
|
const ConfigType = require("../services/type");
|
||||||
const UserRoleConfigType = require("./user-role");
|
|
||||||
const AdminRoleConfigType = require("./admin-role");
|
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
'i18n-locale': new ConfigType('plugin::i18n.locale', 'i18n-locale', 'code'),
|
'i18n-locale': new ConfigType('plugin::i18n.locale', 'i18n-locale', 'code'),
|
||||||
'core-store': new ConfigType('strapi::core-store', 'core-store', 'key', ['value']),
|
'core-store': new ConfigType('strapi::core-store', 'core-store', 'key', ['value']),
|
||||||
'user-role': new UserRoleConfigType('plugin::users-permissions.role', 'user-role', 'type'),
|
'user-role': new ConfigType(
|
||||||
'admin-role': new AdminRoleConfigType(
|
'plugin::users-permissions.role',
|
||||||
|
'user-role',
|
||||||
|
'type',
|
||||||
|
[],
|
||||||
|
[{
|
||||||
|
queryString: 'plugin::users-permissions.permission',
|
||||||
|
relationName: 'permissions',
|
||||||
|
parentName: 'role',
|
||||||
|
relationSortField: 'action',
|
||||||
|
}]
|
||||||
|
),
|
||||||
|
'admin-role': new ConfigType(
|
||||||
'admin::role',
|
'admin::role',
|
||||||
'admin-role',
|
'admin-role',
|
||||||
'code',
|
'code',
|
||||||
|
@ -16,6 +25,8 @@ module.exports = {
|
||||||
[{
|
[{
|
||||||
queryString: 'admin::permission',
|
queryString: 'admin::permission',
|
||||||
relationName: 'permissions',
|
relationName: 'permissions',
|
||||||
|
parentName: 'role',
|
||||||
|
relationSortField: 'action',
|
||||||
}]
|
}]
|
||||||
),
|
),
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,76 +0,0 @@
|
||||||
const { sanitizeConfig } = require('../utils');
|
|
||||||
const ConfigType = require("../services/type");
|
|
||||||
|
|
||||||
const UserRolePermissionsConfigType = class UserRolePermissionsConfigType extends ConfigType {
|
|
||||||
/**
|
|
||||||
* Import a single role-permissions config file into the db.
|
|
||||||
*
|
|
||||||
* @param {string} configName - The name of the config file.
|
|
||||||
* @param {string} configContent - The JSON content of the config file.
|
|
||||||
* @returns {void}
|
|
||||||
*/
|
|
||||||
importSingle = async (configName, configContent) => {
|
|
||||||
// Check if the config should be excluded.
|
|
||||||
const shouldExclude = strapi.config.get('plugin.config-sync.exclude').includes(`${this.configPrefix}.${configName}`);
|
|
||||||
if (shouldExclude) return;
|
|
||||||
|
|
||||||
const roleService = strapi.plugin('users-permissions').service('role');
|
|
||||||
|
|
||||||
const role = await strapi
|
|
||||||
.query(this.queryString)
|
|
||||||
.findOne({ where: { type: configName } });
|
|
||||||
|
|
||||||
if (role && configContent === null) {
|
|
||||||
const publicRole = await strapi.query(this.queryString).findOne({ where: { type: 'public' } });
|
|
||||||
const publicRoleID = publicRole.id;
|
|
||||||
|
|
||||||
await roleService.deleteRole(role.id, publicRoleID);
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const users = role ? role.users : [];
|
|
||||||
configContent.users = users;
|
|
||||||
|
|
||||||
if (!role) {
|
|
||||||
await roleService.createRole(configContent);
|
|
||||||
} else {
|
|
||||||
await roleService.updateRole(role.id, configContent);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get all role-permissions config from the db.
|
|
||||||
*
|
|
||||||
* @returns {object} Object with key value pairs of configs.
|
|
||||||
*/
|
|
||||||
getAllFromDatabase = async () => {
|
|
||||||
const UPService = strapi.plugin('users-permissions').service('users-permissions');
|
|
||||||
const roleService = strapi.plugin('users-permissions').service('role');
|
|
||||||
|
|
||||||
const [roles, plugins] = await Promise.all([
|
|
||||||
roleService.getRoles(),
|
|
||||||
UPService.getPlugins(),
|
|
||||||
]);
|
|
||||||
|
|
||||||
const rolesWithPermissions = await Promise.all(
|
|
||||||
roles.map(async (role) => roleService.getRole(role.id, plugins))
|
|
||||||
);
|
|
||||||
|
|
||||||
const configs = {};
|
|
||||||
|
|
||||||
rolesWithPermissions.map(({ id, ...config }) => {
|
|
||||||
// Check if the config should be excluded.
|
|
||||||
const shouldExclude = strapi.config.get('plugin.config-sync.exclude').includes(`${this.configPrefix}.${config.type}`);
|
|
||||||
if (shouldExclude) return;
|
|
||||||
|
|
||||||
config = sanitizeConfig(config);
|
|
||||||
|
|
||||||
configs[`${this.configPrefix}.${config.type}`] = config;
|
|
||||||
});
|
|
||||||
|
|
||||||
return configs;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
module.exports = UserRolePermissionsConfigType;
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
const difference = (arrayOne, arrayTwo, compareKey) => {
|
||||||
|
return arrayOne.filter(({ [compareKey]: id1 }) => {
|
||||||
|
return !arrayTwo.some(({ [compareKey]: id2 }) => id2 === id1);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = difference;
|
|
@ -10,12 +10,58 @@ const getService = (name) => {
|
||||||
|
|
||||||
const logMessage = (msg = '') => `[strapi-plugin-config-sync]: ${msg}`;
|
const logMessage = (msg = '') => `[strapi-plugin-config-sync]: ${msg}`;
|
||||||
|
|
||||||
const sanitizeConfig = (config) => {
|
const sortByKeys = (unordered) => {
|
||||||
|
return Object.keys(unordered).sort().reduce((obj, key) => {
|
||||||
|
obj[key] = unordered[key];
|
||||||
|
return obj;
|
||||||
|
},
|
||||||
|
{}
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const dynamicSort = (property) => {
|
||||||
|
let sortOrder = 1;
|
||||||
|
|
||||||
|
if (property[0] === "-") {
|
||||||
|
sortOrder = -1;
|
||||||
|
property = property.substr(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (a, b) => {
|
||||||
|
if (sortOrder === -1) {
|
||||||
|
return b[property].localeCompare(a[property]);
|
||||||
|
} else {
|
||||||
|
return a[property].localeCompare(b[property]);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
const sanitizeConfig = (config, relation, relationSortField) => {
|
||||||
delete config._id;
|
delete config._id;
|
||||||
delete config.id;
|
delete config.id;
|
||||||
delete config.updatedAt;
|
delete config.updatedAt;
|
||||||
delete config.createdAt;
|
delete config.createdAt;
|
||||||
|
|
||||||
|
if (relation) {
|
||||||
|
const formattedRelations = [];
|
||||||
|
|
||||||
|
config[relation].map((relationEntity) => {
|
||||||
|
delete relationEntity._id;
|
||||||
|
delete relationEntity.id;
|
||||||
|
delete relationEntity.updatedAt;
|
||||||
|
delete relationEntity.createdAt;
|
||||||
|
relationEntity = sortByKeys(relationEntity);
|
||||||
|
|
||||||
|
formattedRelations.push(relationEntity);
|
||||||
|
});
|
||||||
|
|
||||||
|
if (relationSortField) {
|
||||||
|
formattedRelations.sort(dynamicSort(relationSortField));
|
||||||
|
}
|
||||||
|
|
||||||
|
config[relation] = formattedRelations;
|
||||||
|
}
|
||||||
|
|
||||||
return config;
|
return config;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -24,4 +70,6 @@ module.exports = {
|
||||||
getCoreStore,
|
getCoreStore,
|
||||||
logMessage,
|
logMessage,
|
||||||
sanitizeConfig,
|
sanitizeConfig,
|
||||||
|
sortByKeys,
|
||||||
|
dynamicSort,
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue