Skip to content

Commit 761024c

Browse files
committed
feat: added option to download zip
1 parent 6312517 commit 761024c

6 files changed

Lines changed: 93 additions & 13 deletions

File tree

admin/src/components/ActionButtons/index.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import { Map } from 'immutable';
77
import { useNotification } from '@strapi/helper-plugin';
88

99
import ConfirmModal from '../ConfirmModal';
10-
import { exportAllConfig, importAllConfig } from '../../state/actions/Config';
10+
import { downloadZip, exportAllConfig, importAllConfig } from '../../state/actions/Config';
1111

1212
const ActionButtons = () => {
1313
const dispatch = useDispatch();
@@ -30,6 +30,7 @@ const ActionButtons = () => {
3030
<ActionButtonsStyling>
3131
<Button disabled={isEmpty(partialDiff)} onClick={() => openModal('import')}>Import</Button>
3232
<Button disabled={isEmpty(partialDiff)} onClick={() => openModal('export')}>Export</Button>
33+
<Button onClick={() => dispatch(downloadZip(toggleNotification))}>Download Config</Button>
3334
{!isEmpty(partialDiff) && (
3435
<h4 style={{ display: 'inline' }}>{Object.keys(partialDiff).length} {Object.keys(partialDiff).length === 1 ? "config change" : "config changes"}</h4>
3536
)}

admin/src/state/actions/Config.js

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
import { request } from '@strapi/helper-plugin';
88

99
export function getAllConfigDiff(toggleNotification) {
10-
return async function(dispatch) {
10+
return async function (dispatch) {
1111
dispatch(setLoadingState(true));
1212
try {
1313
const configDiff = await request('/config-sync/diff', { method: 'GET' });
@@ -38,7 +38,7 @@ export function setConfigPartialDiffInState(config) {
3838
}
3939

4040
export function exportAllConfig(partialDiff, toggleNotification) {
41-
return async function(dispatch) {
41+
return async function (dispatch) {
4242
dispatch(setLoadingState(true));
4343
try {
4444
const { message } = await request('/config-sync/export', {
@@ -55,8 +55,27 @@ export function exportAllConfig(partialDiff, toggleNotification) {
5555
};
5656
}
5757

58+
export function downloadZip(toggleNotification) {
59+
return async function (dispatch) {
60+
dispatch(setLoadingState(true));
61+
try {
62+
const { message, url } = await request('/config-sync/zip', {
63+
method: 'GET'
64+
});
65+
toggleNotification({ type: 'success', message });
66+
if (url) {
67+
window.location = url;
68+
}
69+
dispatch(setLoadingState(false));
70+
} catch (err) {
71+
toggleNotification({ type: 'warning', message: { id: 'notification.error' } });
72+
dispatch(setLoadingState(false));
73+
}
74+
};
75+
}
76+
5877
export function importAllConfig(partialDiff, force, toggleNotification) {
59-
return async function(dispatch) {
78+
return async function (dispatch) {
6079
dispatch(setLoadingState(true));
6180
try {
6281
const { message } = await request('/config-sync/import', {
@@ -85,7 +104,7 @@ export function setLoadingState(value) {
85104
}
86105

87106
export function getAppEnv(toggleNotification) {
88-
return async function(dispatch) {
107+
return async function (dispatch) {
89108
try {
90109
const envVars = await request('/config-sync/app-env', {
91110
method: 'GET',

server/config/type.js

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,7 @@ const ConfigType = class ConfigType {
166166
* @param {string} configName - The name of the config file.
167167
* @returns {void}
168168
*/
169-
exportSingle = async (configName) => {
169+
exportSingle = async (configName) => {
170170
const formattedDiff = await strapi.plugin('config-sync').service('main').getFormattedDiff(this.configPrefix);
171171

172172
// Check if the config should be excluded.
@@ -186,12 +186,23 @@ const ConfigType = class ConfigType {
186186
}
187187
}
188188

189+
190+
/**
191+
* Zip config files
192+
*
193+
* @param {string} configName - The name of the zip archive.
194+
* @returns {void}
195+
*/
196+
zipConfig = async () => {
197+
return strapi.plugin('config-sync').service('main').zipConfigFiles();
198+
}
199+
189200
/**
190201
* Get all role-permissions config from the db.
191202
*
192203
* @returns {object} Object with key value pairs of configs.
193204
*/
194-
getAllFromDatabase = async () => {
205+
getAllFromDatabase = async () => {
195206
const AllConfig = await noLimit(strapi.query(this.queryString), {});
196207
const configs = {};
197208

@@ -234,7 +245,7 @@ const ConfigType = class ConfigType {
234245
*
235246
* @returns {void}
236247
*/
237-
importAll = async () => {
248+
importAll = async () => {
238249
// The main.importAllConfig service will loop the core-store.importSingle service.
239250
await strapi.plugin('config-sync').service('main').importAllConfig(this.configPrefix);
240251
}
@@ -244,7 +255,7 @@ const ConfigType = class ConfigType {
244255
*
245256
* @returns {void}
246257
*/
247-
exportAll = async () => {
258+
exportAll = async () => {
248259
// The main.importAllConfig service will loop the core-store.importSingle service.
249260
await strapi.plugin('config-sync').service('main').exportAllConfig(this.configPrefix);
250261
}

server/controllers/config.js

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,19 @@ module.exports = {
8484
return strapi.plugin('config-sync').service('main').getFormattedDiff();
8585
},
8686

87+
zipConfig: async (ctx) => {
88+
// Check for existance of the config file sync dir.
89+
if (!fs.existsSync(strapi.config.get('plugin.config-sync.syncDir'))) {
90+
ctx.send({
91+
message: 'No config files were found.',
92+
});
93+
94+
return;
95+
}
96+
97+
return strapi.plugin('config-sync').service('main').zipConfigFiles();
98+
},
99+
87100
/**
88101
* Get the current Strapi env.
89102
* @returns {string} The current Strapi environment.

server/routes/admin.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,14 @@ module.exports = {
2727
policies: [],
2828
},
2929
},
30+
{
31+
method: "GET",
32+
path: "/zip",
33+
handler: "config.zipConfig",
34+
config: {
35+
policies: [],
36+
},
37+
},
3038
{
3139
method: "GET",
3240
path: "/app-env",

server/services/main.js

Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ const fs = require('fs');
55
const util = require('util');
66
const difference = require('../utils/getObjectDiff');
77
const { logMessage } = require('../utils');
8+
const child_process = require("child_process");
89

910
/**
1011
* Main services for config import/export.
@@ -54,7 +55,7 @@ module.exports = () => ({
5455
* @param {string} configName - The name of the config file.
5556
* @returns {void}
5657
*/
57-
deleteConfigFile: async (configName) => {
58+
deleteConfigFile: async (configName) => {
5859
// Check if the config should be excluded.
5960
const shouldExclude = !isEmpty(strapi.config.get('plugin.config-sync.excludedConfig').filter((option) => configName.startsWith(option)));
6061
if (shouldExclude) return;
@@ -65,6 +66,33 @@ module.exports = () => ({
6566
fs.unlinkSync(`${strapi.config.get('plugin.config-sync.syncDir')}${configName}.json`);
6667
},
6768

69+
/**
70+
* Zip config files.
71+
*
72+
* @param {string} configName - The name of the config file.
73+
* @returns {void}
74+
*/
75+
zipConfigFiles: async () => {
76+
const fileName = `config-${new Date().toJSON()}.zip`
77+
child_process.execSync(`zip -r ${fileName} *`, {
78+
cwd: strapi.config.get('plugin.config-sync.syncDir')
79+
});
80+
const fullFilePath = `${strapi.config.get('plugin.config-sync.syncDir')}${fileName}`
81+
const stats = fs.statSync(fullFilePath);
82+
83+
const result = await strapi.plugins.upload.services.upload.upload({
84+
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.
85+
files: {
86+
path: fullFilePath,
87+
name: `configs/${fileName}`,
88+
type: 'application/zip', // mime type of the file
89+
size: stats.size,
90+
},
91+
});
92+
fs.unlinkSync(fullFilePath);
93+
return { url: result[0].url, message: 'Success' };
94+
},
95+
6896
/**
6997
* Read from a config file.
7098
*
@@ -191,7 +219,7 @@ module.exports = () => ({
191219
* @param {object} onSuccess - Success callback to run on each single successfull import.
192220
* @returns {void}
193221
*/
194-
exportAllConfig: async (configType = null, onSuccess) => {
222+
exportAllConfig: async (configType = null, onSuccess) => {
195223
const fileConfig = await strapi.plugin('config-sync').service('main').getAllConfigFromFiles();
196224
const databaseConfig = await strapi.plugin('config-sync').service('main').getAllConfigFromDatabase();
197225

@@ -242,8 +270,8 @@ module.exports = () => ({
242270
*
243271
* @returns {void}
244272
*/
245-
exportSingleConfig: async (configName, onSuccess) => {
246-
// Check if the config should be excluded.
273+
exportSingleConfig: async (configName, onSuccess) => {
274+
// Check if the config should be excluded.
247275
const shouldExclude = !isEmpty(strapi.config.get('plugin.config-sync.excludedConfig').filter((option) => configName.startsWith(option)));
248276
if (shouldExclude) return;
249277

0 commit comments

Comments
 (0)