2021-12-29 00:38:25 +01:00
|
|
|
const { isEmpty } = require('lodash');
|
2022-01-15 19:17:19 +01:00
|
|
|
const { logMessage, sanitizeConfig, dynamicSort, noLimit, getCombinedUid, getCombinedUidWhereFilter, getUidParamsFromName } = require('../utils');
|
2022-01-24 20:48:59 +01:00
|
|
|
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 {
|
2023-09-04 13:04:08 +02:00
|
|
|
constructor({ queryString, configName, uid, jsonFields, relations, components }) {
|
2021-12-28 22:10:04 +01:00
|
|
|
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-12-28 22:10:04 +01:00
|
|
|
}
|
2021-10-14 16:37:32 +02:00
|
|
|
if (!queryString) {
|
2021-12-28 22:10:04 +01:00
|
|
|
strapi.log.error(logMessage(`No query string found for the '${configName}' config type.`));
|
2021-12-31 13:28:04 +01:00
|
|
|
process.exit(0);
|
2021-12-28 22:10:04 +01:00
|
|
|
}
|
2022-01-15 19:17:19 +01:00
|
|
|
// 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") {
|
2022-01-15 19:17:19 +01:00
|
|
|
this.uidKeys = [uid];
|
2022-01-17 21:02:50 +01:00
|
|
|
} else if (Array.isArray(uid)) {
|
2022-01-15 19:17:19 +01:00
|
|
|
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;
|
2021-12-28 22:10:04 +01:00
|
|
|
this.configPrefix = configName;
|
2021-10-15 14:54:58 +02:00
|
|
|
this.jsonFields = jsonFields || [];
|
2021-11-02 00:33:13 +01:00
|
|
|
this.relations = relations || [];
|
2023-09-04 13:04:08 +02:00
|
|
|
this.components = components || null;
|
2021-10-14 16:37:32 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2021-11-02 00:33:13 +01: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.
|
2024-05-08 20:48:33 +02:00
|
|
|
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;
|
|
|
|
|
2024-05-08 20:48:33 +02:00
|
|
|
const softImport = strapi.config.get('plugin::config-sync.soft');
|
2021-10-14 16:37:32 +02:00
|
|
|
const queryAPI = strapi.query(this.queryString);
|
2022-01-15 19:17:19 +01:00
|
|
|
const uidParams = getUidParamsFromName(this.uidKeys, configName);
|
|
|
|
const combinedUidWhereFilter = getCombinedUidWhereFilter(this.uidKeys, uidParams);
|
2021-11-02 00:33:13 +01:00
|
|
|
let existingConfig = await queryAPI
|
|
|
|
.findOne({
|
2022-01-15 19:17:19 +01:00
|
|
|
where: combinedUidWhereFilter,
|
2021-11-02 00:33:13 +01:00
|
|
|
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;
|
|
|
|
|
2022-12-05 18:55:49 +01:00
|
|
|
// Exit when trying to delete the super-admin role.
|
|
|
|
if (this.configPrefix === 'admin-role' && configName === 'strapi-super-admin') {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2021-11-02 00:33:13 +01:00
|
|
|
await Promise.all(this.relations.map(async ({ queryString, parentName }) => {
|
2021-12-08 13:35:47 +01:00
|
|
|
const relations = await noLimit(strapi.query(queryString), {
|
2021-11-02 00:33:13 +01:00
|
|
|
where: {
|
2022-01-17 17:46:02 +01:00
|
|
|
[parentName]: existingConfig.id,
|
2021-11-02 00:33:13 +01:00
|
|
|
},
|
|
|
|
});
|
|
|
|
|
|
|
|
await Promise.all(relations.map(async (relation) => {
|
2023-10-23 21:06:04 +02:00
|
|
|
await queryFallBack.delete(queryString, { where: {
|
|
|
|
id: relation.id,
|
|
|
|
}});
|
2021-11-02 00:33:13 +01:00
|
|
|
}));
|
|
|
|
}));
|
|
|
|
|
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) {
|
2021-11-02 00:33:13 +01:00
|
|
|
// 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]));
|
2021-11-02 00:33:13 +01:00
|
|
|
|
|
|
|
// Create entity.
|
|
|
|
this.relations.map(({ relationName }) => delete query[relationName]);
|
2023-10-19 08:51:29 +02:00
|
|
|
const newEntity = await queryFallBack.create(this.queryString, {
|
2023-05-03 11:19:53 +02:00
|
|
|
data: query,
|
|
|
|
});
|
2021-11-02 00:33:13 +01:00
|
|
|
|
|
|
|
// 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) => {
|
2021-11-02 00:33:13 +01:00
|
|
|
const relationQuery = { ...relationEntity, [parentName]: newEntity };
|
2023-10-19 08:51:29 +02:00
|
|
|
await queryFallBack.create(queryString, {
|
2023-05-03 11:19:53 +02:00
|
|
|
data: relationQuery,
|
|
|
|
});
|
2021-11-27 23:00:26 +01:00
|
|
|
}));
|
|
|
|
}));
|
2022-01-15 19:17:19 +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;
|
|
|
|
|
2021-11-02 00:33:13 +01:00
|
|
|
// Format JSON fields.
|
|
|
|
configContent = sanitizeConfig(configContent);
|
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]));
|
2021-11-02 00:33:13 +01:00
|
|
|
|
|
|
|
// 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 });
|
2021-11-02 00:33:13 +01:00
|
|
|
|
|
|
|
// Delete/create relations.
|
2022-01-21 16:21:00 +01:00
|
|
|
await Promise.all(this.relations.map(async ({ queryString, relationName, parentName, relationSortFields }) => {
|
2021-11-02 00:33:13 +01:00
|
|
|
const relationQueryApi = strapi.query(queryString);
|
2022-01-21 16:21:00 +01:00
|
|
|
existingConfig = sanitizeConfig(existingConfig, relationName, relationSortFields);
|
|
|
|
configContent = sanitizeConfig(configContent, relationName, relationSortFields);
|
2021-11-02 00:33:13 +01:00
|
|
|
|
2022-01-21 17:33:14 +01:00
|
|
|
const configToAdd = difference(configContent[relationName], existingConfig[relationName], relationSortFields);
|
|
|
|
const configToDelete = difference(existingConfig[relationName], configContent[relationName], relationSortFields);
|
2022-01-24 20:48:59 +01:00
|
|
|
const configToUpdate = same(configContent[relationName], existingConfig[relationName], relationSortFields);
|
2021-11-02 00:33:13 +01:00
|
|
|
|
2021-11-10 16:22:52 +01:00
|
|
|
await Promise.all(configToDelete.map(async (config) => {
|
2022-01-21 16:21:00 +01:00
|
|
|
const whereClause = {};
|
|
|
|
relationSortFields.map((sortField) => {
|
|
|
|
whereClause[sortField] = config[sortField];
|
|
|
|
});
|
2021-11-02 00:33:13 +01:00
|
|
|
await relationQueryApi.delete({
|
|
|
|
where: {
|
2022-01-21 16:21:00 +01:00
|
|
|
...whereClause,
|
2021-11-02 00:33:13 +01:00
|
|
|
[parentName]: entity.id,
|
|
|
|
},
|
|
|
|
});
|
2021-11-10 16:22:52 +01:00
|
|
|
}));
|
2021-11-02 00:33:13 +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, {
|
2021-11-02 00:33:13 +01:00
|
|
|
data: { ...config, [parentName]: entity.id },
|
|
|
|
});
|
2021-11-10 16:22:52 +01:00
|
|
|
}));
|
2022-01-24 20:48:59 +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.
|
2024-05-08 20:48:33 +02:00
|
|
|
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);
|
2022-01-15 19:17:19 +01:00
|
|
|
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
|
|
|
/**
|
2021-11-02 00:33:13 +01: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 () => {
|
2023-05-03 11:19:53 +02:00
|
|
|
const AllConfig = await noLimit(strapi.query(this.queryString), {
|
2023-09-04 13:04:08 +02:00
|
|
|
populate: this.components,
|
2023-05-03 11:19:53 +02:00
|
|
|
});
|
2021-10-14 16:37:32 +02:00
|
|
|
const configs = {};
|
|
|
|
|
2021-11-02 00:33:13 +01:00
|
|
|
await Promise.all(Object.values(AllConfig).map(async (config) => {
|
2022-01-15 19:17:19 +01:00
|
|
|
const combinedUid = getCombinedUid(this.uidKeys, config);
|
|
|
|
const combinedUidWhereFilter = getCombinedUidWhereFilter(this.uidKeys, config);
|
2022-04-23 14:49:13 +02:00
|
|
|
|
|
|
|
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.
|
2024-05-08 20:48:33 +02:00
|
|
|
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;
|
|
|
|
|
2021-11-02 00:33:13 +01:00
|
|
|
const formattedConfig = { ...sanitizeConfig(config) };
|
2022-01-21 16:21:00 +01:00
|
|
|
await Promise.all(this.relations.map(async ({ queryString, relationName, relationSortFields, parentName }) => {
|
2021-12-08 13:35:47 +01:00
|
|
|
const relations = await noLimit(strapi.query(queryString), {
|
2022-01-15 19:17:19 +01:00
|
|
|
where: { [parentName]: combinedUidWhereFilter },
|
2021-11-02 00:33:13 +01:00
|
|
|
});
|
2021-10-14 16:37:32 +02:00
|
|
|
|
2021-11-02 00:33:13 +01:00
|
|
|
relations.map((relation) => sanitizeConfig(relation));
|
2022-01-21 16:21:00 +01:00
|
|
|
relationSortFields.map((sortField) => {
|
|
|
|
relations.sort(dynamicSort(sortField));
|
|
|
|
});
|
2021-11-02 00:33:13 +01:00
|
|
|
formattedConfig[relationName] = relations;
|
|
|
|
}));
|
|
|
|
|
|
|
|
this.jsonFields.map((field) => formattedConfig[field] = JSON.parse(config[field]));
|
2022-01-15 19:17:19 +01:00
|
|
|
configs[`${this.configPrefix}.${combinedUid}`] = formattedConfig;
|
2021-11-02 00:33:13 +01:00
|
|
|
}));
|
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;
|