strapi-plugin-config-sync/server/config/type.js

263 lines
9.9 KiB
JavaScript
Raw Normal View History

const { isEmpty } = require('lodash');
const { logMessage, sanitizeConfig, dynamicSort, noLimit, getCombinedUid, getCombinedUidWhereFilter, getUidParamsFromName } = require('../utils');
const { difference, same } = require('../utils/getArrayDiff');
2023-10-19 08:51:29 +02:00
const queryFallBack = require('../utils/queryFallBack');
2021-10-14 16:37:32 +02:00
const ConfigType = class ConfigType {
constructor({ queryString, configName, uid, jsonFields, relations, components }) {
if (!configName) {
strapi.log.error(logMessage('A config type was registered without a config name.'));
2021-12-31 13:28:04 +01:00
process.exit(0);
}
2021-10-14 16:37:32 +02:00
if (!queryString) {
strapi.log.error(logMessage(`No query string found for the '${configName}' config type.`));
2021-12-31 13:28:04 +01:00
process.exit(0);
}
// uid could be a single key or an array for a combined uid. So the type of uid is either string or string[]
2022-01-17 21:02:50 +01:00
if (typeof uid === "string") {
this.uidKeys = [uid];
2022-01-17 21:02:50 +01:00
} else if (Array.isArray(uid)) {
this.uidKeys = uid.sort();
} else {
strapi.log.error(logMessage(`Wrong uid config for the '${configName}' config type.`));
2021-12-31 13:28:04 +01:00
process.exit(0);
2021-10-14 16:37:32 +02:00
}
this.queryString = queryString;
this.configPrefix = configName;
2021-10-15 14:54:58 +02:00
this.jsonFields = jsonFields || [];
this.relations = relations || [];
this.components = components || null;
2021-10-14 16:37:32 +02:00
}
/**
* Import a single role-permissions config file into the db.
2021-10-14 16:37:32 +02:00
*
* @param {string} configName - The name of the config file.
* @param {string} configContent - The JSON content of the config file.
2022-11-28 17:00:35 +01:00
* @param {boolean} force - Ignore the soft setting.
2021-10-14 16:37:32 +02:00
* @returns {void}
*/
2022-11-28 17:00:35 +01:00
importSingle = async (configName, configContent, force) => {
2021-10-14 16:37:32 +02:00
// Check if the config should be excluded.
const shouldExclude = !isEmpty(strapi.config.get('plugin::config-sync.excludedConfig').filter((option) => `${this.configPrefix}.${configName}`.startsWith(option)));
2021-10-14 16:37:32 +02:00
if (shouldExclude) return;
const softImport = strapi.config.get('plugin::config-sync.soft');
2021-10-14 16:37:32 +02:00
const queryAPI = strapi.query(this.queryString);
const uidParams = getUidParamsFromName(this.uidKeys, configName);
const combinedUidWhereFilter = getCombinedUidWhereFilter(this.uidKeys, uidParams);
let existingConfig = await queryAPI
.findOne({
where: combinedUidWhereFilter,
populate: this.relations.map(({ relationName }) => relationName),
});
2022-11-28 17:00:35 +01:00
// Config exists in DB but no configfile content --> delete config from DB
if (existingConfig && configContent === null) {
// Don't preform action when soft setting is true.
if (softImport && !force) return false;
// Exit when trying to delete the super-admin role.
if (this.configPrefix === 'admin-role' && configName === 'strapi-super-admin') {
return false;
}
await Promise.all(this.relations.map(async ({ queryString, parentName }) => {
const relations = await noLimit(strapi.query(queryString), {
where: {
2022-01-17 17:46:02 +01:00
[parentName]: existingConfig.id,
},
});
await Promise.all(relations.map(async (relation) => {
2023-10-23 21:06:04 +02:00
await queryFallBack.delete(queryString, { where: {
id: relation.id,
}});
}));
}));
2023-10-23 21:06:04 +02:00
await queryFallBack.delete(this.queryString, { where: {
id: existingConfig.id,
}});
2021-10-14 16:37:32 +02:00
return;
}
2022-11-28 17:00:35 +01:00
// Config does not exist in DB --> create config in DB
if (!existingConfig) {
// Format JSON fields.
2021-10-14 16:37:32 +02:00
const query = { ...configContent };
2021-10-15 14:54:58 +02:00
this.jsonFields.map((field) => query[field] = JSON.stringify(configContent[field]));
// Create entity.
this.relations.map(({ relationName }) => delete query[relationName]);
2023-10-19 08:51:29 +02:00
const newEntity = await queryFallBack.create(this.queryString, {
data: query,
});
// Create relation entities.
2021-11-27 23:00:26 +01:00
await Promise.all(this.relations.map(async ({ queryString, relationName, parentName }) => {
await Promise.all(configContent[relationName].map(async (relationEntity) => {
const relationQuery = { ...relationEntity, [parentName]: newEntity };
2023-10-19 08:51:29 +02:00
await queryFallBack.create(queryString, {
data: relationQuery,
});
2021-11-27 23:00:26 +01:00
}));
}));
} else { // Config does exist in DB --> update config in DB
2022-11-28 17:00:35 +01:00
// Don't preform action when soft setting is true.
if (softImport && !force) return false;
// Format JSON fields.
2024-08-13 20:29:46 +02:00
configContent = sanitizeConfig({
config: configContent,
configName,
});
2021-10-14 16:37:32 +02:00
const query = { ...configContent };
2021-10-15 14:54:58 +02:00
this.jsonFields.map((field) => query[field] = JSON.stringify(configContent[field]));
// Update entity.
this.relations.map(({ relationName }) => delete query[relationName]);
2023-10-23 21:06:04 +02:00
const entity = await queryFallBack.update(this.queryString, { where: combinedUidWhereFilter, data: query });
// Delete/create relations.
await Promise.all(this.relations.map(async ({ queryString, relationName, parentName, relationSortFields }) => {
const relationQueryApi = strapi.query(queryString);
2024-08-13 20:29:46 +02:00
existingConfig = sanitizeConfig({ config: existingConfig, configName, relation: relationName, relationSortFields });
configContent = sanitizeConfig({ config: configContent, configName, relation: relationName, relationSortFields });
const configToAdd = difference(configContent[relationName], existingConfig[relationName], relationSortFields);
const configToDelete = difference(existingConfig[relationName], configContent[relationName], relationSortFields);
const configToUpdate = same(configContent[relationName], existingConfig[relationName], relationSortFields);
2021-11-10 16:22:52 +01:00
await Promise.all(configToDelete.map(async (config) => {
const whereClause = {};
relationSortFields.map((sortField) => {
whereClause[sortField] = config[sortField];
});
await relationQueryApi.delete({
where: {
...whereClause,
[parentName]: entity.id,
},
});
2021-11-10 16:22:52 +01:00
}));
2021-11-10 16:22:52 +01:00
await Promise.all(configToAdd.map(async (config) => {
2023-10-19 08:51:29 +02:00
await queryFallBack.create(queryString, {
data: { ...config, [parentName]: entity.id },
});
2021-11-10 16:22:52 +01:00
}));
await Promise.all(configToUpdate.map(async (config, index) => {
const whereClause = {};
relationSortFields.map((sortField) => {
whereClause[sortField] = config[sortField];
});
await relationQueryApi.update({
where: {
...whereClause,
[parentName]: entity.id,
},
data: { ...config, [parentName]: entity.id },
});
}));
2021-11-10 16:22:52 +01:00
}));
2021-10-14 16:37:32 +02:00
}
}
2021-11-20 14:28:17 +01:00
/**
* Export a single core-store config to a file.
*
* @param {string} configName - The name of the config file.
* @returns {void}
*/
exportSingle = async (configName) => {
const formattedDiff = await strapi.plugin('config-sync').service('main').getFormattedDiff(this.configPrefix);
// Check if the config should be excluded.
const shouldExclude = !isEmpty(strapi.config.get('plugin::config-sync.excludedConfig').filter((option) => configName.startsWith(option)));
2021-11-20 14:28:17 +01:00
if (shouldExclude) return;
const currentConfig = formattedDiff.databaseConfig[configName];
if (
!currentConfig
&& formattedDiff.fileConfig[configName]
) {
await strapi.plugin('config-sync').service('main').deleteConfigFile(configName);
} else {
2022-01-17 21:02:50 +01:00
const combinedUid = getCombinedUid(this.uidKeys, currentConfig);
await strapi.plugin('config-sync').service('main').writeConfigFile(this.configPrefix, combinedUid, currentConfig);
2021-11-20 14:28:17 +01:00
}
}
2021-10-14 16:37:32 +02:00
/**
* Get all role-permissions config from the db.
2021-10-14 16:37:32 +02:00
*
* @returns {object} Object with key value pairs of configs.
*/
getAllFromDatabase = async () => {
const AllConfig = await noLimit(strapi.query(this.queryString), {
populate: this.components,
});
2021-10-14 16:37:32 +02:00
const configs = {};
2024-08-13 20:29:46 +02:00
await Promise.all(Object.entries(AllConfig).map(async ([configName, config]) => {
const combinedUid = getCombinedUid(this.uidKeys, config);
const combinedUidWhereFilter = getCombinedUidWhereFilter(this.uidKeys, config);
if (!combinedUid) {
strapi.log.warn(logMessage(`Missing data for entity with id ${config.id} of type ${this.configPrefix}`));
return;
}
2021-10-14 16:37:32 +02:00
// Check if the config should be excluded.
const shouldExclude = !isEmpty(strapi.config.get('plugin::config-sync.excludedConfig').filter((option) => `${this.configPrefix}.${combinedUid}`.startsWith(option)));
2021-10-14 16:37:32 +02:00
if (shouldExclude) return;
2024-08-13 20:29:46 +02:00
const formattedConfig = { ...sanitizeConfig({ config, configName }) };
await Promise.all(this.relations.map(async ({ queryString, relationName, relationSortFields, parentName }) => {
const relations = await noLimit(strapi.query(queryString), {
where: { [parentName]: combinedUidWhereFilter },
});
2021-10-14 16:37:32 +02:00
2024-08-13 20:29:46 +02:00
relations.map((relation) => sanitizeConfig({ config: relation, configName: relationName }));
relationSortFields.map((sortField) => {
relations.sort(dynamicSort(sortField));
});
formattedConfig[relationName] = relations;
}));
this.jsonFields.map((field) => formattedConfig[field] = JSON.parse(config[field]));
configs[`${this.configPrefix}.${combinedUid}`] = formattedConfig;
}));
2021-10-14 16:37:32 +02:00
return configs;
}
/**
* Import all core-store config files into the db.
*
* @returns {void}
*/
importAll = async () => {
// The main.importAllConfig service will loop the core-store.importSingle service.
await strapi.plugin('config-sync').service('main').importAllConfig(this.configPrefix);
}
/**
2021-11-20 14:28:17 +01:00
* Export all core-store config to files.
2021-10-14 16:37:32 +02:00
*
* @returns {void}
*/
2021-11-20 14:28:17 +01:00
exportAll = async () => {
// The main.importAllConfig service will loop the core-store.importSingle service.
await strapi.plugin('config-sync').service('main').exportAllConfig(this.configPrefix);
2021-10-14 16:37:32 +02:00
}
};
module.exports = ConfigType;