2021-03-24 16:22:03 +01:00
'use strict' ;
2021-12-29 00:38:25 +01:00
const { isEmpty } = require ( 'lodash' ) ;
2021-03-24 16:22:03 +01:00
const fs = require ( 'fs' ) ;
const util = require ( 'util' ) ;
2021-03-27 17:14:56 +01:00
const difference = require ( '../utils/getObjectDiff' ) ;
2022-04-24 09:07:18 +02:00
const { logMessage } = require ( '../utils' ) ;
2023-06-16 01:33:56 +02:00
const child _process = require ( "child_process" ) ;
2021-03-24 16:22:03 +01:00
/ * *
* Main services for config import / export .
* /
2021-10-14 16:37:32 +02:00
module . exports = ( ) => ( {
2021-03-24 16:22:03 +01:00
/ * *
* Write a single config file .
*
* @ param { string } configType - The type of the config .
* @ param { string } configName - The name of the config file .
* @ param { string } fileContents - The JSON content of the config file .
* @ returns { void }
* /
writeConfigFile : async ( configType , configName , fileContents ) => {
// Check if the config should be excluded.
2021-12-29 00:38:25 +01:00
const shouldExclude = ! isEmpty ( strapi . config . get ( 'plugin.config-sync.excludedConfig' ) . filter ( ( option ) => ` ${ configType } . ${ configName } ` . startsWith ( option ) ) ) ;
2021-03-24 16:22:03 +01:00
if ( shouldExclude ) return ;
2022-05-13 10:22:31 +02:00
// Replace reserved characters in filenames.
2022-06-14 18:47:28 +02:00
configName = configName . replace ( /:/g , "#" ) . replace ( /\//g , "$" ) ;
2021-11-21 21:16:42 +01:00
2021-05-12 17:24:42 +02:00
// Check if the JSON content should be minified.
2021-10-14 16:37:32 +02:00
const json = ! strapi . config . get ( 'plugin.config-sync' ) . minify
2021-10-14 14:37:00 +02:00
? JSON . stringify ( fileContents , null , 2 )
: JSON . stringify ( fileContents ) ;
2021-03-24 16:22:03 +01:00
2021-12-28 22:10:04 +01:00
if ( ! fs . existsSync ( strapi . config . get ( 'plugin.config-sync.syncDir' ) ) ) {
fs . mkdirSync ( strapi . config . get ( 'plugin.config-sync.syncDir' ) , { recursive : true } ) ;
2021-03-24 16:22:03 +01:00
}
const writeFile = util . promisify ( fs . writeFile ) ;
2021-12-28 22:10:04 +01:00
await writeFile ( ` ${ strapi . config . get ( 'plugin.config-sync.syncDir' ) } ${ configType } . ${ configName } .json ` , json )
2021-03-24 16:22:03 +01:00
. then ( ( ) => {
// @TODO:
// Add logging for successfull config export.
} )
. catch ( ( ) => {
// @TODO:
// Add logging for failed config export.
} ) ;
} ,
2021-03-27 18:20:51 +01:00
/ * *
* Delete config file .
*
* @ param { string } configName - The name of the config file .
* @ returns { void }
* /
2023-06-16 01:33:56 +02:00
deleteConfigFile : async ( configName ) => {
2021-03-27 18:20:51 +01:00
// Check if the config should be excluded.
2021-12-29 00:38:25 +01:00
const shouldExclude = ! isEmpty ( strapi . config . get ( 'plugin.config-sync.excludedConfig' ) . filter ( ( option ) => configName . startsWith ( option ) ) ) ;
2021-03-27 18:20:51 +01:00
if ( shouldExclude ) return ;
2022-05-13 10:22:31 +02:00
// Replace reserved characters in filenames.
2022-06-14 18:47:28 +02:00
configName = configName . replace ( /:/g , "#" ) . replace ( /\//g , "$" ) ;
2021-11-21 21:16:42 +01:00
2021-12-28 22:10:04 +01:00
fs . unlinkSync ( ` ${ strapi . config . get ( 'plugin.config-sync.syncDir' ) } ${ configName } .json ` ) ;
2021-03-27 18:20:51 +01:00
} ,
2023-06-16 01:33:56 +02:00
/ * *
* 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' } ;
} ,
2021-03-24 16:22:03 +01:00
/ * *
* Read from a config file .
*
* @ param { string } configType - The type of config .
* @ param { string } configName - The name of the config file .
* @ returns { object } The JSON content of the config file .
* /
readConfigFile : async ( configType , configName ) => {
2022-05-13 10:22:31 +02:00
// Replace reserved characters in filenames.
2022-06-14 18:47:28 +02:00
configName = configName . replace ( /:/g , "#" ) . replace ( /\//g , "$" ) ;
2021-11-21 21:16:42 +01:00
2021-03-24 16:22:03 +01:00
const readFile = util . promisify ( fs . readFile ) ;
2021-12-28 22:10:04 +01:00
return readFile ( ` ${ strapi . config . get ( 'plugin.config-sync.syncDir' ) } ${ configType } . ${ configName } .json ` )
2021-03-24 16:22:03 +01:00
. then ( ( data ) => {
return JSON . parse ( data ) ;
} )
. catch ( ( ) => {
return null ;
} ) ;
} ,
2021-03-24 18:37:14 +01:00
/ * *
* Get all the config JSON from the filesystem .
*
2021-10-14 14:37:00 +02:00
* @ param { string } configType - Type of config to gather . Leave empty to get all config .
2021-03-24 18:37:14 +01:00
* @ returns { object } Object with key value pairs of configs .
* /
2021-03-27 18:20:51 +01:00
getAllConfigFromFiles : async ( configType = null ) => {
2021-12-28 22:10:04 +01:00
if ( ! fs . existsSync ( strapi . config . get ( 'plugin.config-sync.syncDir' ) ) ) {
2021-03-27 20:21:30 +01:00
return { } ;
}
2021-12-28 22:10:04 +01:00
const configFiles = fs . readdirSync ( strapi . config . get ( 'plugin.config-sync.syncDir' ) ) ;
2021-03-24 18:37:14 +01:00
const getConfigs = async ( ) => {
2021-10-14 14:37:00 +02:00
const fileConfigs = { } ;
2021-03-24 18:37:14 +01:00
await Promise . all ( configFiles . map ( async ( file ) => {
2021-10-15 14:54:58 +02:00
const type = file . split ( '.' ) [ 0 ] ; // Grab the first part of the filename.
const name = file . split ( /\.(.+)/ ) [ 1 ] . split ( '.' ) . slice ( 0 , - 1 ) . join ( '.' ) ; // Grab the rest of the filename minus the file extension.
2021-03-27 18:20:51 +01:00
2022-05-13 10:22:31 +02:00
// Put back reserved characters from filenames.
2022-06-14 18:47:28 +02:00
const formattedName = name . replace ( /#/g , ":" ) . replace ( /\$/g , "/" ) ;
2021-11-21 21:16:42 +01:00
2021-03-27 18:37:55 +01:00
if (
2021-10-14 14:37:00 +02:00
configType && configType !== type
2021-12-28 22:10:04 +01:00
|| ! strapi . plugin ( 'config-sync' ) . types [ type ]
2021-12-29 00:38:25 +01:00
|| ! isEmpty ( strapi . config . get ( 'plugin.config-sync.excludedConfig' ) . filter ( ( option ) => ` ${ type } . ${ name } ` . startsWith ( option ) ) )
2021-03-27 18:37:55 +01:00
) {
2021-03-27 18:20:51 +01:00
return ;
}
2021-10-14 16:37:32 +02:00
const fileContents = await strapi . plugin ( 'config-sync' ) . service ( 'main' ) . readConfigFile ( type , name ) ;
2022-04-24 09:07:18 +02:00
if ( ! fileContents ) {
strapi . log . warn ( logMessage ( ` An empty config file ' ${ file } ' was found in the sync directory ` ) ) ;
return ;
}
2021-11-21 21:16:42 +01:00
fileConfigs [ ` ${ type } . ${ formattedName } ` ] = fileContents ;
2021-03-24 18:37:14 +01:00
} ) ) ;
return fileConfigs ;
} ;
2021-10-14 14:37:00 +02:00
return getConfigs ( ) ;
2021-03-24 18:37:14 +01:00
} ,
/ * *
* Get all the config JSON from the database .
*
2021-10-14 14:37:00 +02:00
* @ param { string } configType - Type of config to gather . Leave empty to get all config .
2021-03-24 18:37:14 +01:00
* @ returns { object } Object with key value pairs of configs .
* /
getAllConfigFromDatabase : async ( configType = null ) => {
const getConfigs = async ( ) => {
let databaseConfigs = { } ;
2021-10-14 14:37:00 +02:00
2021-12-28 22:10:04 +01:00
await Promise . all ( Object . entries ( strapi . plugin ( 'config-sync' ) . types ) . map ( async ( [ name , type ] ) => {
if ( configType && configType !== name ) {
2021-03-24 18:37:14 +01:00
return ;
}
2021-12-28 22:10:04 +01:00
const config = await type . getAllFromDatabase ( ) ;
2021-03-24 18:37:14 +01:00
databaseConfigs = Object . assign ( config , databaseConfigs ) ;
} ) ) ;
return databaseConfigs ;
2021-10-14 14:37:00 +02:00
} ;
2021-03-24 18:37:14 +01:00
2021-10-14 14:37:00 +02:00
return getConfigs ( ) ;
2021-03-24 18:37:14 +01:00
} ,
2021-03-24 16:22:03 +01:00
/ * *
* Import all config files into the db .
*
2021-10-14 14:37:00 +02:00
* @ param { string } configType - Type of config to impor . Leave empty to import all config .
2021-11-10 16:22:52 +01:00
* @ param { object } onSuccess - Success callback to run on each single successfull import .
2021-03-24 16:22:03 +01:00
* @ returns { void }
* /
2021-11-10 16:22:52 +01:00
importAllConfig : async ( configType = null , onSuccess ) => {
2021-10-14 16:37:32 +02:00
const fileConfig = await strapi . plugin ( 'config-sync' ) . service ( 'main' ) . getAllConfigFromFiles ( ) ;
const databaseConfig = await strapi . plugin ( 'config-sync' ) . service ( 'main' ) . getAllConfigFromDatabase ( ) ;
2021-03-27 17:14:56 +01:00
const diff = difference ( databaseConfig , fileConfig ) ;
2021-03-24 16:22:03 +01:00
2021-10-22 13:56:58 +02:00
await Promise . all ( Object . keys ( diff ) . map ( async ( file ) => {
2021-03-24 16:22:03 +01:00
const type = file . split ( '.' ) [ 0 ] ; // Grab the first part of the filename.
2021-12-13 17:07:06 +01:00
const name = file . split ( /\.(.+)/ ) [ 1 ] ; // Grab the rest of the filename.
2021-03-24 16:22:03 +01:00
if ( configType && configType !== type ) {
return ;
}
2021-11-18 22:45:20 +01:00
await strapi . plugin ( 'config-sync' ) . service ( 'main' ) . importSingleConfig ( ` ${ type } . ${ name } ` , onSuccess ) ;
2021-10-22 13:56:58 +02:00
} ) ) ;
2021-03-24 16:22:03 +01:00
} ,
/ * *
* Export all config files .
*
2021-10-14 14:37:00 +02:00
* @ param { string } configType - Type of config to export . Leave empty to export all config .
2021-11-20 14:28:17 +01:00
* @ param { object } onSuccess - Success callback to run on each single successfull import .
2021-03-24 16:22:03 +01:00
* @ returns { void }
* /
2023-06-16 01:33:56 +02:00
exportAllConfig : async ( configType = null , onSuccess ) => {
2021-11-20 14:28:17 +01:00
const fileConfig = await strapi . plugin ( 'config-sync' ) . service ( 'main' ) . getAllConfigFromFiles ( ) ;
const databaseConfig = await strapi . plugin ( 'config-sync' ) . service ( 'main' ) . getAllConfigFromDatabase ( ) ;
const diff = difference ( databaseConfig , fileConfig ) ;
await Promise . all ( Object . keys ( diff ) . map ( async ( file ) => {
const type = file . split ( '.' ) [ 0 ] ; // Grab the first part of the filename.
2021-12-13 17:07:06 +01:00
const name = file . split ( /\.(.+)/ ) [ 1 ] ; // Grab the rest of the filename.
2021-11-20 14:28:17 +01:00
2021-03-24 16:22:03 +01:00
if ( configType && configType !== type ) {
return ;
}
2021-11-20 14:28:17 +01:00
await strapi . plugin ( 'config-sync' ) . service ( 'main' ) . exportSingleConfig ( ` ${ type } . ${ name } ` , onSuccess ) ;
2021-03-24 16:22:03 +01:00
} ) ) ;
} ,
/ * *
* Import a single config file into the db .
*
* @ param { string } configName - The name of the config file .
2021-11-18 22:45:20 +01:00
* @ param { object } onSuccess - Success callback to run on each single successfull import .
2022-11-28 17:00:35 +01:00
* @ param { boolean } force - Ignore the soft setting .
2021-03-24 16:22:03 +01:00
* @ returns { void }
* /
2022-11-28 17:00:35 +01:00
importSingleConfig : async ( configName , onSuccess , force ) => {
2021-03-24 16:22:03 +01:00
// Check if the config should be excluded.
2021-12-29 00:38:25 +01:00
const shouldExclude = ! isEmpty ( strapi . config . get ( 'plugin.config-sync.excludedConfig' ) . filter ( ( option ) => configName . startsWith ( option ) ) ) ;
2021-03-24 16:22:03 +01:00
if ( shouldExclude ) return ;
2021-12-13 17:07:06 +01:00
const type = configName . split ( '.' ) [ 0 ] ; // Grab the first part of the filename.
const name = configName . split ( /\.(.+)/ ) [ 1 ] ; // Grab the rest of the filename.
2021-11-18 22:45:20 +01:00
const fileContents = await strapi . plugin ( 'config-sync' ) . service ( 'main' ) . readConfigFile ( type , name ) ;
2021-03-24 16:22:03 +01:00
2021-11-18 22:45:20 +01:00
try {
2022-11-28 17:00:35 +01:00
const importState = await strapi . plugin ( 'config-sync' ) . types [ type ] . importSingle ( name , fileContents , force ) ;
if ( onSuccess && importState !== false ) onSuccess ( ` ${ type } . ${ name } ` ) ;
2021-11-18 22:45:20 +01:00
} catch ( e ) {
2022-08-15 13:22:31 +02:00
throw new Error ( ` Error when trying to import ${ type } . ${ name } . ${ e } ` ) ;
2021-11-18 22:45:20 +01:00
}
2021-03-24 16:22:03 +01:00
} ,
/ * *
* Export a single config file .
*
* @ param { string } configName - The name of the config file .
2021-11-20 14:28:17 +01:00
* @ param { object } onSuccess - Success callback to run on each single successfull import .
2022-08-15 13:22:31 +02:00
*
2021-03-24 16:22:03 +01:00
* @ returns { void }
* /
2023-06-16 01:33:56 +02:00
exportSingleConfig : async ( configName , onSuccess ) => {
// Check if the config should be excluded.
2021-12-29 00:38:25 +01: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 ;
2021-12-13 17:07:06 +01:00
const type = configName . split ( '.' ) [ 0 ] ; // Grab the first part of the filename.
const name = configName . split ( /\.(.+)/ ) [ 1 ] ; // Grab the rest of the filename.
2021-10-14 14:37:00 +02:00
2021-11-20 14:28:17 +01:00
try {
2021-12-28 22:10:04 +01:00
await strapi . plugin ( 'config-sync' ) . types [ type ] . exportSingle ( configName ) ;
2022-08-15 13:22:31 +02:00
if ( onSuccess ) onSuccess ( ` ${ type } . ${ name } ` ) ;
2021-11-20 14:28:17 +01:00
} catch ( e ) {
2022-08-15 13:22:31 +02:00
throw new Error ( ` Error when trying to export ${ type } . ${ name } . ${ e } ` ) ;
2021-11-20 14:28:17 +01:00
}
2021-03-24 16:22:03 +01:00
} ,
2021-11-10 16:22:52 +01:00
/ * *
* Get the formatted diff .
*
* @ param { string } configType - Type of config to get the diff of . Leave empty to get the diff of all config .
*
* @ returns { object } - the formatted diff .
* /
getFormattedDiff : async ( configType = null ) => {
const formattedDiff = {
fileConfig : { } ,
databaseConfig : { } ,
diff : { } ,
} ;
const fileConfig = await strapi . plugin ( 'config-sync' ) . service ( 'main' ) . getAllConfigFromFiles ( configType ) ;
const databaseConfig = await strapi . plugin ( 'config-sync' ) . service ( 'main' ) . getAllConfigFromDatabase ( configType ) ;
const diff = difference ( databaseConfig , fileConfig ) ;
formattedDiff . diff = diff ;
Object . keys ( diff ) . map ( ( changedConfigName ) => {
formattedDiff . fileConfig [ changedConfigName ] = fileConfig [ changedConfigName ] ;
formattedDiff . databaseConfig [ changedConfigName ] = databaseConfig [ changedConfigName ] ;
} ) ;
return formattedDiff ;
} ,
2021-10-14 16:37:32 +02:00
} ) ;