274 lines
10 KiB
JavaScript
274 lines
10 KiB
JavaScript
import isEmpty from 'lodash/isEmpty';
|
|
import { logMessage, sanitizeConfig, dynamicSort, noLimit, getCombinedUid, getCombinedUidWhereFilter, getUidParamsFromName } from '../utils';
|
|
import { difference, same } from '../utils/getArrayDiff';
|
|
import queryFallBack from '../utils/queryFallBack';
|
|
|
|
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.'));
|
|
process.exit(0);
|
|
}
|
|
if (!queryString) {
|
|
strapi.log.error(logMessage(`No query string found for the '${configName}' config type.`));
|
|
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[]
|
|
if (typeof uid === "string") {
|
|
this.uidKeys = [uid];
|
|
} else if (Array.isArray(uid)) {
|
|
this.uidKeys = uid.sort();
|
|
} else {
|
|
strapi.log.error(logMessage(`Wrong uid config for the '${configName}' config type.`));
|
|
process.exit(0);
|
|
}
|
|
this.queryString = queryString;
|
|
this.configPrefix = configName;
|
|
this.jsonFields = jsonFields || [];
|
|
this.relations = relations || [];
|
|
this.components = components || null;
|
|
}
|
|
|
|
/**
|
|
* 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.
|
|
* @param {boolean} force - Ignore the soft setting.
|
|
* @returns {void}
|
|
*/
|
|
importSingle = async (configName, configContent, force) => {
|
|
// Check if the config should be excluded.
|
|
const shouldExclude = !isEmpty(strapi.config.get('plugin::config-sync.excludedConfig').filter((option) => `${this.configPrefix}.${configName}`.startsWith(option)));
|
|
if (shouldExclude) return;
|
|
|
|
const softImport = strapi.config.get('plugin::config-sync.soft');
|
|
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),
|
|
});
|
|
|
|
// 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: {
|
|
[parentName]: existingConfig.id,
|
|
},
|
|
});
|
|
|
|
await Promise.all(relations.map(async (relation) => {
|
|
await queryFallBack.delete(queryString, { where: {
|
|
id: relation.id,
|
|
}});
|
|
}));
|
|
}));
|
|
|
|
await queryFallBack.delete(this.queryString, { where: {
|
|
id: existingConfig.id,
|
|
}});
|
|
|
|
return;
|
|
}
|
|
|
|
// Config does not exist in DB --> create config in DB
|
|
if (!existingConfig) {
|
|
// Format JSON fields.
|
|
const query = { ...configContent };
|
|
this.jsonFields.map((field) => query[field] = JSON.stringify(configContent[field]));
|
|
|
|
// Create entity.
|
|
this.relations.map(({ relationName }) => delete query[relationName]);
|
|
const newEntity = await queryFallBack.create(this.queryString, {
|
|
data: query,
|
|
});
|
|
|
|
// Create relation entities.
|
|
await Promise.all(this.relations.map(async ({ queryString, relationName, parentName }) => {
|
|
await Promise.all(configContent[relationName].map(async (relationEntity) => {
|
|
const relationQuery = { ...relationEntity, [parentName]: newEntity };
|
|
await queryFallBack.create(queryString, {
|
|
data: relationQuery,
|
|
});
|
|
}));
|
|
}));
|
|
} else { // Config does exist in DB --> update config in DB
|
|
// Don't preform action when soft setting is true.
|
|
if (softImport && !force) return false;
|
|
|
|
// Format JSON fields.
|
|
configContent = sanitizeConfig({
|
|
config: configContent,
|
|
configName,
|
|
});
|
|
const query = { ...configContent };
|
|
this.jsonFields.map((field) => query[field] = JSON.stringify(configContent[field]));
|
|
|
|
// Update entity.
|
|
this.relations.map(({ relationName }) => delete query[relationName]);
|
|
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);
|
|
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);
|
|
|
|
await Promise.all(configToDelete.map(async (config) => {
|
|
const whereClause = {};
|
|
relationSortFields.map((sortField) => {
|
|
whereClause[sortField] = config[sortField];
|
|
});
|
|
await relationQueryApi.delete({
|
|
where: {
|
|
...whereClause,
|
|
[parentName]: entity.id,
|
|
},
|
|
});
|
|
}));
|
|
|
|
await Promise.all(configToAdd.map(async (config) => {
|
|
await queryFallBack.create(queryString, {
|
|
data: { ...config, [parentName]: entity.id },
|
|
});
|
|
}));
|
|
|
|
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 },
|
|
});
|
|
}));
|
|
}));
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 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)));
|
|
if (shouldExclude) return;
|
|
|
|
const currentConfig = formattedDiff.databaseConfig[configName];
|
|
|
|
if (
|
|
!currentConfig
|
|
&& formattedDiff.fileConfig[configName]
|
|
) {
|
|
await strapi.plugin('config-sync').service('main').deleteConfigFile(configName);
|
|
} else {
|
|
const combinedUid = getCombinedUid(this.uidKeys, currentConfig);
|
|
await strapi.plugin('config-sync').service('main').writeConfigFile(this.configPrefix, combinedUid, currentConfig);
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* Zip config files
|
|
*
|
|
* @param {string} configName - The name of the zip archive.
|
|
* @returns {void}
|
|
*/
|
|
zipConfig = async () => {
|
|
return strapi.plugin('config-sync').service('main').zipConfigFiles();
|
|
}
|
|
|
|
/**
|
|
* Get all role-permissions config from the db.
|
|
*
|
|
* @returns {object} Object with key value pairs of configs.
|
|
*/
|
|
getAllFromDatabase = async () => {
|
|
const AllConfig = await noLimit(strapi.query(this.queryString), {
|
|
populate: this.components,
|
|
});
|
|
const configs = {};
|
|
|
|
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;
|
|
}
|
|
|
|
// Check if the config should be excluded.
|
|
const shouldExclude = !isEmpty(strapi.config.get('plugin::config-sync.excludedConfig').filter((option) => `${this.configPrefix}.${combinedUid}`.startsWith(option)));
|
|
if (shouldExclude) return;
|
|
|
|
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 },
|
|
});
|
|
|
|
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;
|
|
}));
|
|
|
|
|
|
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);
|
|
}
|
|
|
|
/**
|
|
* Export all core-store config to files.
|
|
*
|
|
* @returns {void}
|
|
*/
|
|
exportAll = async () => {
|
|
// The main.importAllConfig service will loop the core-store.importSingle service.
|
|
await strapi.plugin('config-sync').service('main').exportAllConfig(this.configPrefix);
|
|
}
|
|
};
|
|
|
|
export default ConfigType;
|