From 879e8908a039b8d68d8b0d5bf8b1e88e3bfc64f8 Mon Sep 17 00:00:00 2001 From: ppaoli <103750528+PhilippPaoli@users.noreply.github.com> Date: Wed, 3 May 2023 11:19:53 +0200 Subject: [PATCH 01/15] Modified Strapi Api calls for components Change Strapi Query Engine Api to Strapi entityService Api. Add parameter "populate" to plugin config. Use import and export with components logic. --- server/config/type.js | 62 +++++++++++++++++++++++++++++++++---------- 1 file changed, 48 insertions(+), 14 deletions(-) diff --git a/server/config/type.js b/server/config/type.js index 74d15ca..9c2ff46 100644 --- a/server/config/type.js +++ b/server/config/type.js @@ -3,7 +3,7 @@ const { logMessage, sanitizeConfig, dynamicSort, noLimit, getCombinedUid, getCom const { difference, same } = require('../utils/getArrayDiff'); const ConfigType = class ConfigType { - constructor({ queryString, configName, uid, jsonFields, relations }) { + constructor({ queryString, configName, uid, jsonFields, relations, populate }) { if (!configName) { strapi.log.error(logMessage('A config type was registered without a config name.')); process.exit(0); @@ -25,6 +25,7 @@ const ConfigType = class ConfigType { this.configPrefix = configName; this.jsonFields = jsonFields || []; this.relations = relations || []; + this.populate = populate || []; } /** @@ -68,15 +69,11 @@ const ConfigType = class ConfigType { }); await Promise.all(relations.map(async (relation) => { - await strapi.query(queryString).delete({ - where: { id: relation.id }, - }); + await strapi.entityService.delete(this.queryString, relation.id); })); })); - await queryAPI.delete({ - where: { id: existingConfig.id }, - }); + await strapi.entityService.delete(this.queryString, existingConfig.id); return; } @@ -89,15 +86,17 @@ const ConfigType = class ConfigType { // Create entity. this.relations.map(({ relationName }) => delete query[relationName]); - const newEntity = await queryAPI.create({ data: query }); + const newEntity = await strapi.entityService.create(this.queryString, { + data: query, + }); // Create relation entities. await Promise.all(this.relations.map(async ({ queryString, relationName, parentName }) => { - const relationQueryApi = strapi.query(queryString); - await Promise.all(configContent[relationName].map(async (relationEntity) => { const relationQuery = { ...relationEntity, [parentName]: newEntity }; - await relationQueryApi.create({ data: relationQuery }); + await strapi.entityService.create(queryString, { + data: relationQuery, + }); })); })); } else { // Config does exist in DB --> update config in DB @@ -111,7 +110,21 @@ const ConfigType = class ConfigType { // Update entity. this.relations.map(({ relationName }) => delete query[relationName]); - const entity = await queryAPI.update({ where: combinedUidWhereFilter, data: query }); + + let entity; + switch (this.queryString) { + case "strapi::core-store": + entity = await queryAPI.update({ + where: combinedUidWhereFilter, + data: query, + }); + break; + default: + entity = await queryAPI.findOne({ where: combinedUidWhereFilter }); + await strapi.entityService.update(this.queryString, entity.id, { + data: query, + }); + } // Delete/create relations. await Promise.all(this.relations.map(async ({ queryString, relationName, parentName, relationSortFields }) => { @@ -137,7 +150,7 @@ const ConfigType = class ConfigType { })); await Promise.all(configToAdd.map(async (config) => { - await relationQueryApi.create({ + await strapi.entityService.create(queryString, { data: { ...config, [parentName]: entity.id }, }); })); @@ -192,7 +205,9 @@ const ConfigType = class ConfigType { * @returns {object} Object with key value pairs of configs. */ getAllFromDatabase = async () => { - const AllConfig = await noLimit(strapi.query(this.queryString), {}); + const AllConfig = await noLimit(strapi.query(this.queryString), { + populate: this.populate || null, + }); const configs = {}; await Promise.all(Object.values(AllConfig).map(async (config) => { @@ -221,6 +236,25 @@ const ConfigType = class ConfigType { formattedConfig[relationName] = relations; })); + this.populate + .filter((populatedFields) => !populatedFields.includes(".")) + .map((populatedFields) => { + formattedConfig[populatedFields] = formattedConfig[ + populatedFields + ].map((fields) => { + const sanitizeObjects = (fields) => { + sanitizeConfig(fields); + Object.keys(fields).map((key, index) => { + if (fields[key] && typeof fields[key] === "object") { + sanitizeObjects(fields[key]); + } + }); + }; + sanitizeObjects(fields); + return fields; + }); + }); + this.jsonFields.map((field) => formattedConfig[field] = JSON.parse(config[field])); configs[`${this.configPrefix}.${combinedUid}`] = formattedConfig; })); From 510312d3479a6d874219adb8b3d8c4a135f629e4 Mon Sep 17 00:00:00 2001 From: ppaoli Date: Thu, 10 Aug 2023 10:58:55 +0200 Subject: [PATCH 02/15] Fix small comments --- server/config/type.js | 46 +++++++++++++++++-------------------------- server/utils/index.js | 19 +++++++++++++----- 2 files changed, 32 insertions(+), 33 deletions(-) diff --git a/server/config/type.js b/server/config/type.js index 9c2ff46..7371a19 100644 --- a/server/config/type.js +++ b/server/config/type.js @@ -25,7 +25,7 @@ const ConfigType = class ConfigType { this.configPrefix = configName; this.jsonFields = jsonFields || []; this.relations = relations || []; - this.populate = populate || []; + this.populate = populate || null; } /** @@ -111,19 +111,15 @@ const ConfigType = class ConfigType { // Update entity. this.relations.map(({ relationName }) => delete query[relationName]); - let entity; - switch (this.queryString) { - case "strapi::core-store": - entity = await queryAPI.update({ - where: combinedUidWhereFilter, - data: query, - }); - break; - default: - entity = await queryAPI.findOne({ where: combinedUidWhereFilter }); - await strapi.entityService.update(this.queryString, entity.id, { - data: query, - }); + const entity = await queryAPI.findOne({ where: combinedUidWhereFilter }); + try { + await strapi.entityService.update(this.queryString, entity.id, { + data: query, + }); + } catch(error) { + console.warn(error); + console.log("Use Query Engine API instead of Entity Service API"); + await queryAPI.update({ where: combinedUidWhereFilter, data: query }); } // Delete/create relations. @@ -206,7 +202,7 @@ const ConfigType = class ConfigType { */ getAllFromDatabase = async () => { const AllConfig = await noLimit(strapi.query(this.queryString), { - populate: this.populate || null, + populate: this.populate, }); const configs = {}; @@ -236,24 +232,18 @@ const ConfigType = class ConfigType { formattedConfig[relationName] = relations; })); - this.populate - .filter((populatedFields) => !populatedFields.includes(".")) - .map((populatedFields) => { + if (Array.isArray(this.populate)) { + this.populate + .filter((populatedFields) => !populatedFields.includes(".")) + .map((populatedFields) => { formattedConfig[populatedFields] = formattedConfig[ populatedFields ].map((fields) => { - const sanitizeObjects = (fields) => { - sanitizeConfig(fields); - Object.keys(fields).map((key, index) => { - if (fields[key] && typeof fields[key] === "object") { - sanitizeObjects(fields[key]); - } - }); - }; - sanitizeObjects(fields); + sanitizeConfig(fields); return fields; }); - }); + }); + } this.jsonFields.map((field) => formattedConfig[field] = JSON.parse(config[field])); configs[`${this.configPrefix}.${combinedUid}`] = formattedConfig; diff --git a/server/utils/index.js b/server/utils/index.js index 4a6c6f9..ca61959 100644 --- a/server/utils/index.js +++ b/server/utils/index.js @@ -47,11 +47,6 @@ const dynamicSort = (property) => { }; const sanitizeConfig = (config, relation, relationSortFields) => { - delete config._id; - delete config.id; - delete config.updatedAt; - delete config.createdAt; - if (relation) { const formattedRelations = []; @@ -74,6 +69,20 @@ const sanitizeConfig = (config, relation, relationSortFields) => { config[relation] = formattedRelations; } + const sanitizeRecursive = (config) => { + delete config._id; + delete config.id; + delete config.updatedAt; + delete config.createdAt; + + Object.keys(config).map((key, index) => { + if (config[key] && typeof config[key] === "object") { + sanitizeRecursive(config[key]); + } + }); + }; + sanitizeRecursive(config); + return config; }; From 34426f5172eb7fea2c4b878f4572c4b02e7dc5ac Mon Sep 17 00:00:00 2001 From: ppaoli Date: Mon, 4 Sep 2023 13:04:08 +0200 Subject: [PATCH 03/15] Fixed ESLint warnings, change property naming Fixed ESLint Warnings Add Documentation for Components under "Custom types" Change property populate to components --- README.md | 15 +++++++++++++++ server/config/type.js | 18 +++++++++--------- server/utils/index.js | 20 ++++++++++---------- 3 files changed, 34 insertions(+), 19 deletions(-) diff --git a/README.md b/README.md index 53e9a82..fdf537e 100644 --- a/README.md +++ b/README.md @@ -330,6 +330,21 @@ This property can accept an array of field names from the type. It is meant to s > `required:` NO | `type:` array +#### Components + +This property can accept an array of component names from the type. Strapi Components can be included in the export/import process. With "." nested components can also be included in the process. +``` +customTypes: [{ + configName: 'webhook', + queryString: 'webhook', + uid: 'name', + components: ['ParentComponentA', 'ParentComponentA.ChildComponent', 'ParentComponentB'] +}], + +###### Key: `components` + +> `required:` NO | `type:` array + ## 🔍 Naming convention All the config files written in the sync directory have the same naming convention. It goes as follows: diff --git a/server/config/type.js b/server/config/type.js index 7371a19..7c53d53 100644 --- a/server/config/type.js +++ b/server/config/type.js @@ -3,7 +3,7 @@ const { logMessage, sanitizeConfig, dynamicSort, noLimit, getCombinedUid, getCom const { difference, same } = require('../utils/getArrayDiff'); const ConfigType = class ConfigType { - constructor({ queryString, configName, uid, jsonFields, relations, populate }) { + 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); @@ -25,7 +25,7 @@ const ConfigType = class ConfigType { this.configPrefix = configName; this.jsonFields = jsonFields || []; this.relations = relations || []; - this.populate = populate || null; + this.components = components || null; } /** @@ -202,7 +202,7 @@ const ConfigType = class ConfigType { */ getAllFromDatabase = async () => { const AllConfig = await noLimit(strapi.query(this.queryString), { - populate: this.populate, + populate: this.components, }); const configs = {}; @@ -232,12 +232,12 @@ const ConfigType = class ConfigType { formattedConfig[relationName] = relations; })); - if (Array.isArray(this.populate)) { - this.populate - .filter((populatedFields) => !populatedFields.includes(".")) - .map((populatedFields) => { - formattedConfig[populatedFields] = formattedConfig[ - populatedFields + if (Array.isArray(this.components)) { + this.components + .filter((componentFields) => !componentFields.includes(".")) + .map((componentFields) => { + formattedConfig[componentFields] = formattedConfig[ + componentFields ].map((fields) => { sanitizeConfig(fields); return fields; diff --git a/server/utils/index.js b/server/utils/index.js index ca61959..19291d1 100644 --- a/server/utils/index.js +++ b/server/utils/index.js @@ -69,19 +69,19 @@ const sanitizeConfig = (config, relation, relationSortFields) => { config[relation] = formattedRelations; } - const sanitizeRecursive = (config) => { - delete config._id; - delete config.id; - delete config.updatedAt; - delete config.createdAt; - - Object.keys(config).map((key, index) => { - if (config[key] && typeof config[key] === "object") { - sanitizeRecursive(config[key]); + const recursiveSanitizeConfig = (recursivedSanitizedConfig) => { + delete recursivedSanitizedConfig._id; + delete recursivedSanitizedConfig.id; + delete recursivedSanitizedConfig.updatedAt; + delete recursivedSanitizedConfig.createdAt; + + Object.keys(recursivedSanitizedConfig).map((key, index) => { + if (recursivedSanitizedConfig[key] && typeof recursivedSanitizedConfig[key] === "object") { + recursiveSanitizeConfig(recursivedSanitizedConfig[key]); } }); }; - sanitizeRecursive(config); + recursiveSanitizeConfig(config); return config; }; From b9527532b689976f49d0388ff2f7e073cd756a93 Mon Sep 17 00:00:00 2001 From: Boaz Poolman Date: Wed, 6 Sep 2023 16:09:23 +0200 Subject: [PATCH 04/15] fix: No need to additionally sanitize the components. They've allready been sanitized because their parent was santized. --- server/config/type.js | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/server/config/type.js b/server/config/type.js index 7c53d53..488cbad 100644 --- a/server/config/type.js +++ b/server/config/type.js @@ -232,19 +232,6 @@ const ConfigType = class ConfigType { formattedConfig[relationName] = relations; })); - if (Array.isArray(this.components)) { - this.components - .filter((componentFields) => !componentFields.includes(".")) - .map((componentFields) => { - formattedConfig[componentFields] = formattedConfig[ - componentFields - ].map((fields) => { - sanitizeConfig(fields); - return fields; - }); - }); - } - this.jsonFields.map((field) => formattedConfig[field] = JSON.parse(config[field])); configs[`${this.configPrefix}.${combinedUid}`] = formattedConfig; })); From 5199e7adc84d1408c86baca6042f89dfe205f010 Mon Sep 17 00:00:00 2001 From: Boaz Poolman Date: Wed, 6 Sep 2023 16:16:48 +0200 Subject: [PATCH 05/15] fix: Use strapi.log.warn instead of logging warnings with console.log --- server/config/type.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/server/config/type.js b/server/config/type.js index 488cbad..768744e 100644 --- a/server/config/type.js +++ b/server/config/type.js @@ -116,9 +116,8 @@ const ConfigType = class ConfigType { await strapi.entityService.update(this.queryString, entity.id, { data: query, }); - } catch(error) { - console.warn(error); - console.log("Use Query Engine API instead of Entity Service API"); + } catch (error) { + strapi.log.warn(logMessage(`Use Query Engine API instead of Entity Service API for type ${this.configPrefix}`)); await queryAPI.update({ where: combinedUidWhereFilter, data: query }); } From 8e9cbdd6aa19a6dd677915780bc676da4d5e336a Mon Sep 17 00:00:00 2001 From: Boaz Poolman Date: Wed, 6 Sep 2023 16:22:56 +0200 Subject: [PATCH 06/15] fix: Add missing env vars to playground --- playground/.env | 1 + playground/config/admin.js | 8 ++++++++ 2 files changed, 9 insertions(+) diff --git a/playground/.env b/playground/.env index c53b44b..57cb1e7 100644 --- a/playground/.env +++ b/playground/.env @@ -3,4 +3,5 @@ PORT=1337 APP_KEYS=SIwLyqu+IpSHIuUBDQfPZg==,Nzqbq2C3ATsR19u5XEAJQA==,/Agk5Sn8M4EzfoSiIHcDlQ==,gSxT2T0k2zbQatKXUV0zCA== API_TOKEN_SALT=reQcUBbGXD2KWG2QpRn7DA== ADMIN_JWT_SECRET= 69mzgwRGfEBUhPEaas8EBA== +TRANSFER_TOKEN_SALT=/LTsSGpC5afHICjZu0oEuQ== JWT_SECRET=E0TTVdsr+M/FXAjfrNIgXA== diff --git a/playground/config/admin.js b/playground/config/admin.js index 54eaf4a..15a268c 100644 --- a/playground/config/admin.js +++ b/playground/config/admin.js @@ -5,4 +5,12 @@ module.exports = ({ env }) => ({ watchIgnoreFiles: [ '**/config/sync/**', ], + apiToken: { + salt: env('API_TOKEN_SALT'), + }, + transfer: { + token: { + salt: env('TRANSFER_TOKEN_SALT'), + }, + }, }); From f6677886c32e46c52f905611918c31082b9c4da3 Mon Sep 17 00:00:00 2001 From: Boaz Poolman Date: Wed, 6 Sep 2023 16:58:04 +0200 Subject: [PATCH 07/15] docs: Write docs about the relations feature --- README.md | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/README.md b/README.md index 53e9a82..be43f24 100644 --- a/README.md +++ b/README.md @@ -322,6 +322,30 @@ If you do not have a single unique value, you can also pass in a array of keys f > `required:` YES | `type:` string | string[] +#### Relations + +The relations array specifies the relations you want to include in the sync process. +This feature is used to sync the relations between `roles` and `permissions`. See https://github.com/boazpoolman/strapi-plugin-config-sync/blob/master/server/config/types.js#L16. + +Example: +``` +{ + configName: 'admin-role', + queryString: 'admin::role', + uid: 'code', + relations: [{ + queryString: 'admin::permission', + relationName: 'permissions', + parentName: 'role', + relationSortFields: ['action', 'subject'], + }], +}, +``` + +###### Key: `relations` + +> `required:` NO | `type:` array + #### JSON fields This property can accept an array of field names from the type. It is meant to specify the JSON fields on the type so the plugin can better format the field values when calculating the config difference. From 69597c7464829e1caecd585216739d219fc8adae Mon Sep 17 00:00:00 2001 From: ppaoli <103750528+PhilippPaoli@users.noreply.github.com> Date: Wed, 3 May 2023 11:19:53 +0200 Subject: [PATCH 08/15] Modified Strapi Api calls for components Change Strapi Query Engine Api to Strapi entityService Api. Add parameter "populate" to plugin config. Use import and export with components logic. --- server/config/type.js | 62 +++++++++++++++++++++++++++++++++---------- 1 file changed, 48 insertions(+), 14 deletions(-) diff --git a/server/config/type.js b/server/config/type.js index 74d15ca..9c2ff46 100644 --- a/server/config/type.js +++ b/server/config/type.js @@ -3,7 +3,7 @@ const { logMessage, sanitizeConfig, dynamicSort, noLimit, getCombinedUid, getCom const { difference, same } = require('../utils/getArrayDiff'); const ConfigType = class ConfigType { - constructor({ queryString, configName, uid, jsonFields, relations }) { + constructor({ queryString, configName, uid, jsonFields, relations, populate }) { if (!configName) { strapi.log.error(logMessage('A config type was registered without a config name.')); process.exit(0); @@ -25,6 +25,7 @@ const ConfigType = class ConfigType { this.configPrefix = configName; this.jsonFields = jsonFields || []; this.relations = relations || []; + this.populate = populate || []; } /** @@ -68,15 +69,11 @@ const ConfigType = class ConfigType { }); await Promise.all(relations.map(async (relation) => { - await strapi.query(queryString).delete({ - where: { id: relation.id }, - }); + await strapi.entityService.delete(this.queryString, relation.id); })); })); - await queryAPI.delete({ - where: { id: existingConfig.id }, - }); + await strapi.entityService.delete(this.queryString, existingConfig.id); return; } @@ -89,15 +86,17 @@ const ConfigType = class ConfigType { // Create entity. this.relations.map(({ relationName }) => delete query[relationName]); - const newEntity = await queryAPI.create({ data: query }); + const newEntity = await strapi.entityService.create(this.queryString, { + data: query, + }); // Create relation entities. await Promise.all(this.relations.map(async ({ queryString, relationName, parentName }) => { - const relationQueryApi = strapi.query(queryString); - await Promise.all(configContent[relationName].map(async (relationEntity) => { const relationQuery = { ...relationEntity, [parentName]: newEntity }; - await relationQueryApi.create({ data: relationQuery }); + await strapi.entityService.create(queryString, { + data: relationQuery, + }); })); })); } else { // Config does exist in DB --> update config in DB @@ -111,7 +110,21 @@ const ConfigType = class ConfigType { // Update entity. this.relations.map(({ relationName }) => delete query[relationName]); - const entity = await queryAPI.update({ where: combinedUidWhereFilter, data: query }); + + let entity; + switch (this.queryString) { + case "strapi::core-store": + entity = await queryAPI.update({ + where: combinedUidWhereFilter, + data: query, + }); + break; + default: + entity = await queryAPI.findOne({ where: combinedUidWhereFilter }); + await strapi.entityService.update(this.queryString, entity.id, { + data: query, + }); + } // Delete/create relations. await Promise.all(this.relations.map(async ({ queryString, relationName, parentName, relationSortFields }) => { @@ -137,7 +150,7 @@ const ConfigType = class ConfigType { })); await Promise.all(configToAdd.map(async (config) => { - await relationQueryApi.create({ + await strapi.entityService.create(queryString, { data: { ...config, [parentName]: entity.id }, }); })); @@ -192,7 +205,9 @@ const ConfigType = class ConfigType { * @returns {object} Object with key value pairs of configs. */ getAllFromDatabase = async () => { - const AllConfig = await noLimit(strapi.query(this.queryString), {}); + const AllConfig = await noLimit(strapi.query(this.queryString), { + populate: this.populate || null, + }); const configs = {}; await Promise.all(Object.values(AllConfig).map(async (config) => { @@ -221,6 +236,25 @@ const ConfigType = class ConfigType { formattedConfig[relationName] = relations; })); + this.populate + .filter((populatedFields) => !populatedFields.includes(".")) + .map((populatedFields) => { + formattedConfig[populatedFields] = formattedConfig[ + populatedFields + ].map((fields) => { + const sanitizeObjects = (fields) => { + sanitizeConfig(fields); + Object.keys(fields).map((key, index) => { + if (fields[key] && typeof fields[key] === "object") { + sanitizeObjects(fields[key]); + } + }); + }; + sanitizeObjects(fields); + return fields; + }); + }); + this.jsonFields.map((field) => formattedConfig[field] = JSON.parse(config[field])); configs[`${this.configPrefix}.${combinedUid}`] = formattedConfig; })); From 378cd7bb58d7bbdc0e721fcff502a1af007b5a6a Mon Sep 17 00:00:00 2001 From: ppaoli Date: Thu, 10 Aug 2023 10:58:55 +0200 Subject: [PATCH 09/15] Fix small comments --- server/config/type.js | 46 +++++++++++++++++-------------------------- server/utils/index.js | 19 +++++++++++++----- 2 files changed, 32 insertions(+), 33 deletions(-) diff --git a/server/config/type.js b/server/config/type.js index 9c2ff46..7371a19 100644 --- a/server/config/type.js +++ b/server/config/type.js @@ -25,7 +25,7 @@ const ConfigType = class ConfigType { this.configPrefix = configName; this.jsonFields = jsonFields || []; this.relations = relations || []; - this.populate = populate || []; + this.populate = populate || null; } /** @@ -111,19 +111,15 @@ const ConfigType = class ConfigType { // Update entity. this.relations.map(({ relationName }) => delete query[relationName]); - let entity; - switch (this.queryString) { - case "strapi::core-store": - entity = await queryAPI.update({ - where: combinedUidWhereFilter, - data: query, - }); - break; - default: - entity = await queryAPI.findOne({ where: combinedUidWhereFilter }); - await strapi.entityService.update(this.queryString, entity.id, { - data: query, - }); + const entity = await queryAPI.findOne({ where: combinedUidWhereFilter }); + try { + await strapi.entityService.update(this.queryString, entity.id, { + data: query, + }); + } catch(error) { + console.warn(error); + console.log("Use Query Engine API instead of Entity Service API"); + await queryAPI.update({ where: combinedUidWhereFilter, data: query }); } // Delete/create relations. @@ -206,7 +202,7 @@ const ConfigType = class ConfigType { */ getAllFromDatabase = async () => { const AllConfig = await noLimit(strapi.query(this.queryString), { - populate: this.populate || null, + populate: this.populate, }); const configs = {}; @@ -236,24 +232,18 @@ const ConfigType = class ConfigType { formattedConfig[relationName] = relations; })); - this.populate - .filter((populatedFields) => !populatedFields.includes(".")) - .map((populatedFields) => { + if (Array.isArray(this.populate)) { + this.populate + .filter((populatedFields) => !populatedFields.includes(".")) + .map((populatedFields) => { formattedConfig[populatedFields] = formattedConfig[ populatedFields ].map((fields) => { - const sanitizeObjects = (fields) => { - sanitizeConfig(fields); - Object.keys(fields).map((key, index) => { - if (fields[key] && typeof fields[key] === "object") { - sanitizeObjects(fields[key]); - } - }); - }; - sanitizeObjects(fields); + sanitizeConfig(fields); return fields; }); - }); + }); + } this.jsonFields.map((field) => formattedConfig[field] = JSON.parse(config[field])); configs[`${this.configPrefix}.${combinedUid}`] = formattedConfig; diff --git a/server/utils/index.js b/server/utils/index.js index 4a6c6f9..ca61959 100644 --- a/server/utils/index.js +++ b/server/utils/index.js @@ -47,11 +47,6 @@ const dynamicSort = (property) => { }; const sanitizeConfig = (config, relation, relationSortFields) => { - delete config._id; - delete config.id; - delete config.updatedAt; - delete config.createdAt; - if (relation) { const formattedRelations = []; @@ -74,6 +69,20 @@ const sanitizeConfig = (config, relation, relationSortFields) => { config[relation] = formattedRelations; } + const sanitizeRecursive = (config) => { + delete config._id; + delete config.id; + delete config.updatedAt; + delete config.createdAt; + + Object.keys(config).map((key, index) => { + if (config[key] && typeof config[key] === "object") { + sanitizeRecursive(config[key]); + } + }); + }; + sanitizeRecursive(config); + return config; }; From c269b4847e8d0804940156d6bb2275d584d2720b Mon Sep 17 00:00:00 2001 From: ppaoli Date: Mon, 4 Sep 2023 13:04:08 +0200 Subject: [PATCH 10/15] Fixed ESLint warnings, change property naming Fixed ESLint Warnings Add Documentation for Components under "Custom types" Change property populate to components --- README.md | 15 +++++++++++++++ server/config/type.js | 18 +++++++++--------- server/utils/index.js | 20 ++++++++++---------- 3 files changed, 34 insertions(+), 19 deletions(-) diff --git a/README.md b/README.md index be43f24..fc5346f 100644 --- a/README.md +++ b/README.md @@ -354,6 +354,21 @@ This property can accept an array of field names from the type. It is meant to s > `required:` NO | `type:` array +#### Components + +This property can accept an array of component names from the type. Strapi Components can be included in the export/import process. With "." nested components can also be included in the process. +``` +customTypes: [{ + configName: 'webhook', + queryString: 'webhook', + uid: 'name', + components: ['ParentComponentA', 'ParentComponentA.ChildComponent', 'ParentComponentB'] +}], + +###### Key: `components` + +> `required:` NO | `type:` array + ## 🔍 Naming convention All the config files written in the sync directory have the same naming convention. It goes as follows: diff --git a/server/config/type.js b/server/config/type.js index 7371a19..7c53d53 100644 --- a/server/config/type.js +++ b/server/config/type.js @@ -3,7 +3,7 @@ const { logMessage, sanitizeConfig, dynamicSort, noLimit, getCombinedUid, getCom const { difference, same } = require('../utils/getArrayDiff'); const ConfigType = class ConfigType { - constructor({ queryString, configName, uid, jsonFields, relations, populate }) { + 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); @@ -25,7 +25,7 @@ const ConfigType = class ConfigType { this.configPrefix = configName; this.jsonFields = jsonFields || []; this.relations = relations || []; - this.populate = populate || null; + this.components = components || null; } /** @@ -202,7 +202,7 @@ const ConfigType = class ConfigType { */ getAllFromDatabase = async () => { const AllConfig = await noLimit(strapi.query(this.queryString), { - populate: this.populate, + populate: this.components, }); const configs = {}; @@ -232,12 +232,12 @@ const ConfigType = class ConfigType { formattedConfig[relationName] = relations; })); - if (Array.isArray(this.populate)) { - this.populate - .filter((populatedFields) => !populatedFields.includes(".")) - .map((populatedFields) => { - formattedConfig[populatedFields] = formattedConfig[ - populatedFields + if (Array.isArray(this.components)) { + this.components + .filter((componentFields) => !componentFields.includes(".")) + .map((componentFields) => { + formattedConfig[componentFields] = formattedConfig[ + componentFields ].map((fields) => { sanitizeConfig(fields); return fields; diff --git a/server/utils/index.js b/server/utils/index.js index ca61959..19291d1 100644 --- a/server/utils/index.js +++ b/server/utils/index.js @@ -69,19 +69,19 @@ const sanitizeConfig = (config, relation, relationSortFields) => { config[relation] = formattedRelations; } - const sanitizeRecursive = (config) => { - delete config._id; - delete config.id; - delete config.updatedAt; - delete config.createdAt; - - Object.keys(config).map((key, index) => { - if (config[key] && typeof config[key] === "object") { - sanitizeRecursive(config[key]); + const recursiveSanitizeConfig = (recursivedSanitizedConfig) => { + delete recursivedSanitizedConfig._id; + delete recursivedSanitizedConfig.id; + delete recursivedSanitizedConfig.updatedAt; + delete recursivedSanitizedConfig.createdAt; + + Object.keys(recursivedSanitizedConfig).map((key, index) => { + if (recursivedSanitizedConfig[key] && typeof recursivedSanitizedConfig[key] === "object") { + recursiveSanitizeConfig(recursivedSanitizedConfig[key]); } }); }; - sanitizeRecursive(config); + recursiveSanitizeConfig(config); return config; }; From 0c2086e33ac4c0520f6b5fbe975e1d3b7c1a0605 Mon Sep 17 00:00:00 2001 From: Boaz Poolman Date: Wed, 6 Sep 2023 16:09:23 +0200 Subject: [PATCH 11/15] fix: No need to additionally sanitize the components. They've allready been sanitized because their parent was santized. --- server/config/type.js | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/server/config/type.js b/server/config/type.js index 7c53d53..488cbad 100644 --- a/server/config/type.js +++ b/server/config/type.js @@ -232,19 +232,6 @@ const ConfigType = class ConfigType { formattedConfig[relationName] = relations; })); - if (Array.isArray(this.components)) { - this.components - .filter((componentFields) => !componentFields.includes(".")) - .map((componentFields) => { - formattedConfig[componentFields] = formattedConfig[ - componentFields - ].map((fields) => { - sanitizeConfig(fields); - return fields; - }); - }); - } - this.jsonFields.map((field) => formattedConfig[field] = JSON.parse(config[field])); configs[`${this.configPrefix}.${combinedUid}`] = formattedConfig; })); From c0582bd756b55fb6b73efcf42a466376d0ad79b2 Mon Sep 17 00:00:00 2001 From: Boaz Poolman Date: Wed, 6 Sep 2023 16:16:48 +0200 Subject: [PATCH 12/15] fix: Use strapi.log.warn instead of logging warnings with console.log --- server/config/type.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/server/config/type.js b/server/config/type.js index 488cbad..768744e 100644 --- a/server/config/type.js +++ b/server/config/type.js @@ -116,9 +116,8 @@ const ConfigType = class ConfigType { await strapi.entityService.update(this.queryString, entity.id, { data: query, }); - } catch(error) { - console.warn(error); - console.log("Use Query Engine API instead of Entity Service API"); + } catch (error) { + strapi.log.warn(logMessage(`Use Query Engine API instead of Entity Service API for type ${this.configPrefix}`)); await queryAPI.update({ where: combinedUidWhereFilter, data: query }); } From b35817e074db954a068094ede6eb494279eda2d6 Mon Sep 17 00:00:00 2001 From: Boaz Poolman Date: Wed, 6 Sep 2023 16:22:56 +0200 Subject: [PATCH 13/15] fix: Add missing env vars to playground --- playground/.env | 1 + playground/config/admin.js | 8 ++++++++ 2 files changed, 9 insertions(+) diff --git a/playground/.env b/playground/.env index c53b44b..57cb1e7 100644 --- a/playground/.env +++ b/playground/.env @@ -3,4 +3,5 @@ PORT=1337 APP_KEYS=SIwLyqu+IpSHIuUBDQfPZg==,Nzqbq2C3ATsR19u5XEAJQA==,/Agk5Sn8M4EzfoSiIHcDlQ==,gSxT2T0k2zbQatKXUV0zCA== API_TOKEN_SALT=reQcUBbGXD2KWG2QpRn7DA== ADMIN_JWT_SECRET= 69mzgwRGfEBUhPEaas8EBA== +TRANSFER_TOKEN_SALT=/LTsSGpC5afHICjZu0oEuQ== JWT_SECRET=E0TTVdsr+M/FXAjfrNIgXA== diff --git a/playground/config/admin.js b/playground/config/admin.js index 54eaf4a..15a268c 100644 --- a/playground/config/admin.js +++ b/playground/config/admin.js @@ -5,4 +5,12 @@ module.exports = ({ env }) => ({ watchIgnoreFiles: [ '**/config/sync/**', ], + apiToken: { + salt: env('API_TOKEN_SALT'), + }, + transfer: { + token: { + salt: env('TRANSFER_TOKEN_SALT'), + }, + }, }); From 10ea389822f0d4024a4847b7e2e30192bd45aa37 Mon Sep 17 00:00:00 2001 From: ppaoli Date: Wed, 11 Oct 2023 18:17:53 +0200 Subject: [PATCH 14/15] Update type.js Resolved Integration Test Error --- server/config/type.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/server/config/type.js b/server/config/type.js index 768744e..2034cd5 100644 --- a/server/config/type.js +++ b/server/config/type.js @@ -69,7 +69,9 @@ const ConfigType = class ConfigType { }); await Promise.all(relations.map(async (relation) => { - await strapi.entityService.delete(this.queryString, relation.id); + await strapi.query(queryString).delete({ + where: { id: relation.id }, + }); })); })); @@ -117,7 +119,7 @@ const ConfigType = class ConfigType { data: query, }); } catch (error) { - strapi.log.warn(logMessage(`Use Query Engine API instead of Entity Service API for type ${this.configPrefix}`)); + console.warn(logMessage(`Use Query Engine API instead of Entity Service API for type ${this.configPrefix}`)); await queryAPI.update({ where: combinedUidWhereFilter, data: query }); } From d3bcb1cd7c082c9d1fd5588052f585e580a07cd0 Mon Sep 17 00:00:00 2001 From: ppaoli Date: Sat, 14 Oct 2023 11:01:39 +0200 Subject: [PATCH 15/15] Update type.js Update Query String --- server/config/type.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/server/config/type.js b/server/config/type.js index 2034cd5..0724322 100644 --- a/server/config/type.js +++ b/server/config/type.js @@ -69,9 +69,7 @@ const ConfigType = class ConfigType { }); await Promise.all(relations.map(async (relation) => { - await strapi.query(queryString).delete({ - where: { id: relation.id }, - }); + await strapi.entityService.delete(queryString, relation.id); })); }));