feat: added option to download zip

pull/94/head
Alexander Engel 2023-06-15 16:33:56 -07:00
parent 6312517dba
commit 761024cc74
6 changed files with 93 additions and 13 deletions

View File

@ -7,7 +7,7 @@ import { Map } from 'immutable';
import { useNotification } from '@strapi/helper-plugin'; import { useNotification } from '@strapi/helper-plugin';
import ConfirmModal from '../ConfirmModal'; import ConfirmModal from '../ConfirmModal';
import { exportAllConfig, importAllConfig } from '../../state/actions/Config'; import { downloadZip, exportAllConfig, importAllConfig } from '../../state/actions/Config';
const ActionButtons = () => { const ActionButtons = () => {
const dispatch = useDispatch(); const dispatch = useDispatch();
@ -30,6 +30,7 @@ const ActionButtons = () => {
<ActionButtonsStyling> <ActionButtonsStyling>
<Button disabled={isEmpty(partialDiff)} onClick={() => openModal('import')}>Import</Button> <Button disabled={isEmpty(partialDiff)} onClick={() => openModal('import')}>Import</Button>
<Button disabled={isEmpty(partialDiff)} onClick={() => openModal('export')}>Export</Button> <Button disabled={isEmpty(partialDiff)} onClick={() => openModal('export')}>Export</Button>
<Button onClick={() => dispatch(downloadZip(toggleNotification))}>Download Config</Button>
{!isEmpty(partialDiff) && ( {!isEmpty(partialDiff) && (
<h4 style={{ display: 'inline' }}>{Object.keys(partialDiff).length} {Object.keys(partialDiff).length === 1 ? "config change" : "config changes"}</h4> <h4 style={{ display: 'inline' }}>{Object.keys(partialDiff).length} {Object.keys(partialDiff).length === 1 ? "config change" : "config changes"}</h4>
)} )}

View File

@ -7,7 +7,7 @@
import { request } from '@strapi/helper-plugin'; import { request } from '@strapi/helper-plugin';
export function getAllConfigDiff(toggleNotification) { export function getAllConfigDiff(toggleNotification) {
return async function(dispatch) { return async function (dispatch) {
dispatch(setLoadingState(true)); dispatch(setLoadingState(true));
try { try {
const configDiff = await request('/config-sync/diff', { method: 'GET' }); const configDiff = await request('/config-sync/diff', { method: 'GET' });
@ -38,7 +38,7 @@ export function setConfigPartialDiffInState(config) {
} }
export function exportAllConfig(partialDiff, toggleNotification) { export function exportAllConfig(partialDiff, toggleNotification) {
return async function(dispatch) { return async function (dispatch) {
dispatch(setLoadingState(true)); dispatch(setLoadingState(true));
try { try {
const { message } = await request('/config-sync/export', { const { message } = await request('/config-sync/export', {
@ -55,8 +55,27 @@ export function exportAllConfig(partialDiff, toggleNotification) {
}; };
} }
export function downloadZip(toggleNotification) {
return async function (dispatch) {
dispatch(setLoadingState(true));
try {
const { message, url } = await request('/config-sync/zip', {
method: 'GET'
});
toggleNotification({ type: 'success', message });
if (url) {
window.location = url;
}
dispatch(setLoadingState(false));
} catch (err) {
toggleNotification({ type: 'warning', message: { id: 'notification.error' } });
dispatch(setLoadingState(false));
}
};
}
export function importAllConfig(partialDiff, force, toggleNotification) { export function importAllConfig(partialDiff, force, toggleNotification) {
return async function(dispatch) { return async function (dispatch) {
dispatch(setLoadingState(true)); dispatch(setLoadingState(true));
try { try {
const { message } = await request('/config-sync/import', { const { message } = await request('/config-sync/import', {
@ -85,7 +104,7 @@ export function setLoadingState(value) {
} }
export function getAppEnv(toggleNotification) { export function getAppEnv(toggleNotification) {
return async function(dispatch) { return async function (dispatch) {
try { try {
const envVars = await request('/config-sync/app-env', { const envVars = await request('/config-sync/app-env', {
method: 'GET', method: 'GET',

View File

@ -166,7 +166,7 @@ const ConfigType = class ConfigType {
* @param {string} configName - The name of the config file. * @param {string} configName - The name of the config file.
* @returns {void} * @returns {void}
*/ */
exportSingle = async (configName) => { exportSingle = async (configName) => {
const formattedDiff = await strapi.plugin('config-sync').service('main').getFormattedDiff(this.configPrefix); const formattedDiff = await strapi.plugin('config-sync').service('main').getFormattedDiff(this.configPrefix);
// Check if the config should be excluded. // Check if the config should be excluded.
@ -186,12 +186,23 @@ const ConfigType = class ConfigType {
} }
} }
/**
* 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. * 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 noLimit(strapi.query(this.queryString), {}); const AllConfig = await noLimit(strapi.query(this.queryString), {});
const configs = {}; const configs = {};
@ -234,7 +245,7 @@ const ConfigType = class ConfigType {
* *
* @returns {void} * @returns {void}
*/ */
importAll = async () => { importAll = async () => {
// The main.importAllConfig service will loop the core-store.importSingle service. // The main.importAllConfig service will loop the core-store.importSingle service.
await strapi.plugin('config-sync').service('main').importAllConfig(this.configPrefix); await strapi.plugin('config-sync').service('main').importAllConfig(this.configPrefix);
} }
@ -244,7 +255,7 @@ const ConfigType = class ConfigType {
* *
* @returns {void} * @returns {void}
*/ */
exportAll = async () => { exportAll = async () => {
// The main.importAllConfig service will loop the core-store.importSingle service. // The main.importAllConfig service will loop the core-store.importSingle service.
await strapi.plugin('config-sync').service('main').exportAllConfig(this.configPrefix); await strapi.plugin('config-sync').service('main').exportAllConfig(this.configPrefix);
} }

View File

@ -84,6 +84,19 @@ module.exports = {
return strapi.plugin('config-sync').service('main').getFormattedDiff(); return strapi.plugin('config-sync').service('main').getFormattedDiff();
}, },
zipConfig: async (ctx) => {
// Check for existance of the config file sync dir.
if (!fs.existsSync(strapi.config.get('plugin.config-sync.syncDir'))) {
ctx.send({
message: 'No config files were found.',
});
return;
}
return strapi.plugin('config-sync').service('main').zipConfigFiles();
},
/** /**
* Get the current Strapi env. * Get the current Strapi env.
* @returns {string} The current Strapi environment. * @returns {string} The current Strapi environment.

View File

@ -27,6 +27,14 @@ module.exports = {
policies: [], policies: [],
}, },
}, },
{
method: "GET",
path: "/zip",
handler: "config.zipConfig",
config: {
policies: [],
},
},
{ {
method: "GET", method: "GET",
path: "/app-env", path: "/app-env",

View File

@ -5,6 +5,7 @@ const fs = require('fs');
const util = require('util'); const util = require('util');
const difference = require('../utils/getObjectDiff'); const difference = require('../utils/getObjectDiff');
const { logMessage } = require('../utils'); const { logMessage } = require('../utils');
const child_process = require("child_process");
/** /**
* Main services for config import/export. * Main services for config import/export.
@ -54,7 +55,7 @@ module.exports = () => ({
* @param {string} configName - The name of the config file. * @param {string} configName - The name of the config file.
* @returns {void} * @returns {void}
*/ */
deleteConfigFile: async (configName) => { deleteConfigFile: async (configName) => {
// Check if the config should be excluded. // Check if the config should be excluded.
const shouldExclude = !isEmpty(strapi.config.get('plugin.config-sync.excludedConfig').filter((option) => configName.startsWith(option))); const shouldExclude = !isEmpty(strapi.config.get('plugin.config-sync.excludedConfig').filter((option) => configName.startsWith(option)));
if (shouldExclude) return; if (shouldExclude) return;
@ -65,6 +66,33 @@ module.exports = () => ({
fs.unlinkSync(`${strapi.config.get('plugin.config-sync.syncDir')}${configName}.json`); fs.unlinkSync(`${strapi.config.get('plugin.config-sync.syncDir')}${configName}.json`);
}, },
/**
* Zip config files.
*
* @param {string} configName - The name of the config file.
* @returns {void}
*/
zipConfigFiles: async () => {
const fileName = `config-${new Date().toJSON()}.zip`
child_process.execSync(`zip -r ${fileName} *`, {
cwd: strapi.config.get('plugin.config-sync.syncDir')
});
const fullFilePath = `${strapi.config.get('plugin.config-sync.syncDir')}${fileName}`
const stats = fs.statSync(fullFilePath);
const result = await strapi.plugins.upload.services.upload.upload({
data: {}, //mandatory declare the data(can be empty), otherwise it will give you an undefined error. This parameters will be used to relate the file with a collection.
files: {
path: fullFilePath,
name: `configs/${fileName}`,
type: 'application/zip', // mime type of the file
size: stats.size,
},
});
fs.unlinkSync(fullFilePath);
return { url: result[0].url, message: 'Success' };
},
/** /**
* Read from a config file. * Read from a config file.
* *
@ -191,7 +219,7 @@ module.exports = () => ({
* @param {object} onSuccess - Success callback to run on each single successfull import. * @param {object} onSuccess - Success callback to run on each single successfull import.
* @returns {void} * @returns {void}
*/ */
exportAllConfig: async (configType = null, onSuccess) => { exportAllConfig: async (configType = null, onSuccess) => {
const fileConfig = await strapi.plugin('config-sync').service('main').getAllConfigFromFiles(); const fileConfig = await strapi.plugin('config-sync').service('main').getAllConfigFromFiles();
const databaseConfig = await strapi.plugin('config-sync').service('main').getAllConfigFromDatabase(); const databaseConfig = await strapi.plugin('config-sync').service('main').getAllConfigFromDatabase();
@ -242,8 +270,8 @@ module.exports = () => ({
* *
* @returns {void} * @returns {void}
*/ */
exportSingleConfig: async (configName, onSuccess) => { exportSingleConfig: async (configName, onSuccess) => {
// Check if the config should be excluded. // Check if the config should be excluded.
const shouldExclude = !isEmpty(strapi.config.get('plugin.config-sync.excludedConfig').filter((option) => configName.startsWith(option))); const shouldExclude = !isEmpty(strapi.config.get('plugin.config-sync.excludedConfig').filter((option) => configName.startsWith(option)));
if (shouldExclude) return; if (shouldExclude) return;