From ceff2a8cbb59b70ee3dd62a87f2856cce10a4e71 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gustavo=20Bascop=C3=A9?= Date: Fri, 10 Jan 2025 10:22:58 -0400 Subject: [PATCH 1/8] added ellipsis options to add settings to bundles --- .../Controllers/Api/DevLinkController.php | 13 +++- ProcessMaker/Models/Bundle.php | 59 ++++++++++++-- ProcessMaker/Models/Setting.php | 11 ++- .../components/AuthClientsListing.vue | 11 ++- .../components/BundleConfigurations.vue | 9 ++- .../admin/devlink/components/BundleDetail.vue | 2 + .../components/platformConfigurations.js | 12 ++- .../js/admin/devlink/components/settings.js | 8 +- .../admin/groups/components/GroupsListing.vue | 8 +- .../script-executors/ScriptExecutors.vue | 18 +++++ .../components/SettingsMenuCollapse.vue | 34 +++++++- .../admin/users/components/UsersListing.vue | 8 +- .../js/components/shared/AddToBundle.vue | 77 +++++++++++++------ .../views/admin/auth-clients/index.blade.php | 2 +- routes/api.php | 1 + 15 files changed, 222 insertions(+), 51 deletions(-) diff --git a/ProcessMaker/Http/Controllers/Api/DevLinkController.php b/ProcessMaker/Http/Controllers/Api/DevLinkController.php index e77f926d3e..a0d06ac138 100644 --- a/ProcessMaker/Http/Controllers/Api/DevLinkController.php +++ b/ProcessMaker/Http/Controllers/Api/DevLinkController.php @@ -223,7 +223,7 @@ public function addAsset(Request $request, Bundle $bundle) public function addSettings(Request $request, Bundle $bundle) { - $bundle->addSettings($request->input('setting'), $request->input('config')); + $bundle->addSettings($request->input('setting'), $request->input('config'), $request->input('type')); } public function addAssetToBundles(Request $request) @@ -238,6 +238,17 @@ public function addAssetToBundles(Request $request) } } + public function addSettingToBundles(Request $request) + { + $bundles = $request->input('bundles'); + foreach ($bundles as $id) { + $bundle = Bundle::find($id); + if ($bundle) { + $bundle->addSettingToBundles($request->input('setting'), $request->input('config')); + } + } + } + public function sharedAssets(Request $request) { return Setting::Where('group', 'Devlink')->get(); diff --git a/ProcessMaker/Models/Bundle.php b/ProcessMaker/Models/Bundle.php index 31112a4a8b..47e77ca390 100644 --- a/ProcessMaker/Models/Bundle.php +++ b/ProcessMaker/Models/Bundle.php @@ -9,6 +9,7 @@ use ProcessMaker\ImportExport\Logger; use ProcessMaker\ImportExport\Options; use ProcessMaker\Models\ProcessMakerModel; +use ProcessMaker\Models\SettingsMenus; use Spatie\MediaLibrary\HasMedia; use Spatie\MediaLibrary\InteractsWithMedia; @@ -138,18 +139,52 @@ public function addAsset(ProcessMakerModel $asset) ]); } - public function addSettings($setting, $config) + public function addSettings($setting, $newId, $type = null) { - $exists = $this->settings()->where('setting', $setting)->exists(); - if ($exists) { - $this->settings()->where('setting', $setting)->update([ - 'config' => $config, + $existingSetting = $this->settings()->where('setting', $setting)->first(); + + if ($existingSetting) { + // If the config is null, do not add the new ID + if (is_null($existingSetting->config)) { + return; + } + + // Decode the existing JSON + $config = json_decode($existingSetting->config, true); + + // Ensure 'id' is an array + if (!isset($config['id']) || !is_array($config['id'])) { + $config['id'] = []; + } + + // Add the new ID + $config['id'][] = $newId; + + // Remove duplicates + $config['id'] = array_unique($config['id']); + + // Update the config + $existingSetting->update([ + 'config' => json_encode($config), ]); } else { + // Create a new BundleSetting with the initial ID + $config = ['id' => []]; + if ($newId) { + $config['id'][] = $newId; + } + + if ($type) { + $settingsMenu = SettingsMenus::where('menu_group', $setting)->first(); + if ($settingsMenu) { + $config['id'] = $settingsMenu->id; + } + } + BundleSetting::create([ 'bundle_id' => $this->id, 'setting' => $setting, - 'config' => $config, + 'config' => json_encode($config), ]); } } @@ -166,6 +201,18 @@ public function addAssetToBundles(ProcessMakerModel $asset) return $message; } + public function addSettingToBundles($setting, $newId) + { + $message = null; + try { + $this->addSettings($setting, $newId); + } catch (ValidationException $ve) { + $message = $ve->getMessage(); + } + + return $message; + } + public function validateEditable() { if (!$this->editable()) { diff --git a/ProcessMaker/Models/Setting.php b/ProcessMaker/Models/Setting.php index e6167a2517..9119959002 100644 --- a/ProcessMaker/Models/Setting.php +++ b/ProcessMaker/Models/Setting.php @@ -143,7 +143,7 @@ public static function messages() * * @param string $key * - * @return \ProcessMaker\Models\Setting|null + * @return Setting|null * @throws \Exception */ public static function byKey(string $key) @@ -382,7 +382,7 @@ public static function getFavicon() */ public static function groupsByMenu($menuId) { - $query = Setting::query() + $query = self::query() ->select('group') ->groupBy('group') ->where('group_id', $menuId) @@ -409,7 +409,7 @@ public static function groupsByMenu($menuId) */ public static function updateSettingsGroup($settingsGroup, $id) { - Setting::where('group', $settingsGroup)->whereNull('group_id')->chunk( + self::where('group', $settingsGroup)->whereNull('group_id')->chunk( 50, function ($settings) use ($id) { foreach ($settings as $setting) { @@ -429,7 +429,7 @@ function ($settings) use ($id) { */ public static function updateAllSettingsGroupId() { - Setting::whereNull('group_id')->chunk(100, function ($settings) { + self::whereNull('group_id')->chunk(100, function ($settings) { $defaultId = SettingsMenus::EMAIL_MENU_GROUP; foreach ($settings as $setting) { // Define the value of 'menu_group' based on 'group' @@ -466,6 +466,9 @@ public static function updateAllSettingsGroupId() case 'System': // System not related with settings menu $id = null; break; + case 'Devlink': + $id = null; + break; default: // The default value if (preg_match('/^Email Server/', $setting->group)) { $id = SettingsMenus::getId(SettingsMenus::EMAIL_MENU_GROUP); diff --git a/resources/js/admin/auth-clients/components/AuthClientsListing.vue b/resources/js/admin/auth-clients/components/AuthClientsListing.vue index 34702a07ee..f69e7a6db4 100644 --- a/resources/js/admin/auth-clients/components/AuthClientsListing.vue +++ b/resources/js/admin/auth-clients/components/AuthClientsListing.vue @@ -29,6 +29,7 @@ @navigate="onNavigate" :actions="actions" :data="props.rowData" + :permission="permission" :divider="true" /> @@ -46,6 +47,10 @@ {{ props.rowData.secret.substr(0, 10) }}... + @@ -46,6 +47,10 @@ const props = defineProps({ title: { type: String, required: true + }, + type: { + type: String, + required: false } }); diff --git a/resources/js/admin/devlink/components/BundleDetail.vue b/resources/js/admin/devlink/components/BundleDetail.vue index 8a34d94d81..2909f60486 100644 --- a/resources/js/admin/devlink/components/BundleDetail.vue +++ b/resources/js/admin/devlink/components/BundleDetail.vue @@ -91,6 +91,7 @@ :values="bundle.settings" @config-change="handleConfigChange" title="Settings" + type="settings" /> { ProcessMaker.apiClient.post(`devlink/local-bundles/${bundle.value.id}/add-settings`, { setting: event.key, config: null, + type: event.type, }) .then(() => { loadAssets(); diff --git a/resources/js/admin/devlink/components/platformConfigurations.js b/resources/js/admin/devlink/components/platformConfigurations.js index 1f78d359c4..61d477b21c 100644 --- a/resources/js/admin/devlink/components/platformConfigurations.js +++ b/resources/js/admin/devlink/components/platformConfigurations.js @@ -16,12 +16,16 @@ export default [ name: "UI Settings", }, { - type: "script_executors", - name: "Script Executors", + type: "ui_dashboards", + name: "Dashboards", + }, + { + type: "ui_menus", + name: "Menus", }, { - type: "analytics_settings", - name: "Analytics Settings", + type: "script_executors", + name: "Script Executors", }, { type: "public_files", diff --git a/resources/js/admin/devlink/components/settings.js b/resources/js/admin/devlink/components/settings.js index 3d7593c7da..c961cbefc8 100644 --- a/resources/js/admin/devlink/components/settings.js +++ b/resources/js/admin/devlink/components/settings.js @@ -1,18 +1,18 @@ export default [ { - type: "email_settings", + type: "Email", name: "Email Settings", }, { - type: "log-in_auth", + type: "Log-In & Auth", name: "Log-in & Auth", }, { - type: "user_settings", + type: "User Settings", name: "User Settings", }, { - type: "integrations", + type: "Integrations", name: "Integrations", }, ]; diff --git a/resources/js/admin/groups/components/GroupsListing.vue b/resources/js/admin/groups/components/GroupsListing.vue index 34ab46d279..695ae82fbe 100644 --- a/resources/js/admin/groups/components/GroupsListing.vue +++ b/resources/js/admin/groups/components/GroupsListing.vue @@ -33,6 +33,10 @@ /> + + + + + import datatableMixin from "../../components/common/mixins/datatable"; import dataLoadingMixin from "../../components/common/mixins/apiDataLoading"; +import AddToBundle from "../../components/shared/AddToBundle.vue"; import { createUniqIdsMixin } from "vue-uniq-ids"; const uniqIdsMixin = createUniqIdsMixin(); export default { mixins: [datatableMixin, dataLoadingMixin, uniqIdsMixin], + components: { AddToBundle }, props: ["filter", "permission"], data() { return { @@ -508,6 +523,9 @@ export default { this.loading = false; }); }, + onAddToBundle(data) { + this.$root.$emit('add-to-bundle', data); + }, }, }; diff --git a/resources/js/admin/settings/components/SettingsMenuCollapse.vue b/resources/js/admin/settings/components/SettingsMenuCollapse.vue index 13cec06982..6f5d978ef2 100644 --- a/resources/js/admin/settings/components/SettingsMenuCollapse.vue +++ b/resources/js/admin/settings/components/SettingsMenuCollapse.vue @@ -20,11 +20,18 @@ aria-expanded="false" :aria-controls="`collapseOne${menu.id}`" > + {{ menu.menu_group }} - + @@ -50,11 +57,20 @@ + @@ -223,3 +248,10 @@ export default { font-weight: 700; } + diff --git a/resources/js/admin/users/components/UsersListing.vue b/resources/js/admin/users/components/UsersListing.vue index 313966ada7..c5daaf0af4 100644 --- a/resources/js/admin/users/components/UsersListing.vue +++ b/resources/js/admin/users/components/UsersListing.vue @@ -36,6 +36,10 @@ /> + { selected.value = null; error.value = null; assetId.value = data.id; + assetName.value = data.name || data.title; modal.value.show(); }); const save = (event) => { event.preventDefault(); if (selected.value?.id) { - const asset = { - 'type': props.assetType, - 'id': assetId.value - }; - window.ProcessMaker.apiClient.post(`devlink/local-bundles/${selected.value.id}/add-assets`, asset).then(() => { - modal.value.hide(); - window.ProcessMaker.alert(vue.$t('Asset added to bundle'), 'success'); - }).catch(e => { - error.value = e.response?.data?.error?.message || e.message; - }) + if (props.setting) { + window.ProcessMaker.apiClient.post(`devlink/local-bundles/${selected.value.id}/add-settings`, { + setting: props.assetType, + config: null, + }) + .then(() => { + window.ProcessMaker.alert(vue.$t('Setting added to bundle'), 'success'); + }); + } else { + const asset = { + 'type': props.assetType, + 'id': assetId.value + }; + window.ProcessMaker.apiClient.post(`devlink/local-bundles/${selected.value.id}/add-assets`, asset).then(() => { + modal.value.hide(); + window.ProcessMaker.alert(vue.$t('Asset added to bundle'), 'success'); + }).catch(e => { + error.value = e.response?.data?.error?.message || e.message; + }) + } } if (Array.isArray(selected.value)) { let bundles = []; selected.value.forEach((item) => { bundles.push(item.id); }); - const asset = { - 'type': props.assetType, - 'id': assetId.value, - 'bundles': bundles - }; - window.ProcessMaker.apiClient.post(`devlink/local-bundles/add-asset-to-bundles`, asset).then(() => { - modal.value.hide(); - window.ProcessMaker.alert(vue.$t('Asset added to bundle'), 'success'); - }).catch(e => { - error.value = e.response?.data?.error?.message || e.message; - }); + if (props.setting) { + const setting = { + 'setting': props.assetType, + 'config': assetId.value, + 'bundles': bundles + }; + window.ProcessMaker.apiClient.post(`devlink/local-bundles/add-setting-to-bundles`, setting).then(() => { + modal.value.hide(); + window.ProcessMaker.alert(vue.$t('Setting added to bundle'), 'success'); + }).catch(e => { + error.value = e.response?.data?.error?.message || e.message; + }); + } else { + const asset = { + 'type': props.assetType, + 'id': assetId.value, + 'bundles': bundles + }; + window.ProcessMaker.apiClient.post(`devlink/local-bundles/add-asset-to-bundles`, asset).then(() => { + modal.value.hide(); + window.ProcessMaker.alert(vue.$t('Asset added to bundle'), 'success'); + }).catch(e => { + error.value = e.response?.data?.error?.message || e.message; + }); + } } }; @@ -71,7 +100,7 @@ const save = (event) => { >

{{ vue.$t('The asset') }} - {{ vue.$t('Marketing screens') }} + {{ assetName }} {{ vue.$t('can be added to one or various bundles.') }}

{{ vue.$t('Bundles') }} @@ -96,4 +125,4 @@ const save = (event) => { .add-to-bundle-modal .modal-footer { border-top: none; } - \ No newline at end of file + diff --git a/resources/views/admin/auth-clients/index.blade.php b/resources/views/admin/auth-clients/index.blade.php index 39651acf3c..926a39e92b 100644 --- a/resources/views/admin/auth-clients/index.blade.php +++ b/resources/views/admin/auth-clients/index.blade.php @@ -68,7 +68,7 @@
- +
diff --git a/routes/api.php b/routes/api.php index 9c465e653c..cef69151f8 100644 --- a/routes/api.php +++ b/routes/api.php @@ -399,6 +399,7 @@ Route::post('devlink/local-bundles/{bundle}/add-assets', [DevLinkController::class, 'addAsset'])->name('devlink.add-asset'); Route::post('devlink/local-bundles/{bundle}/add-settings', [DevLinkController::class, 'addSettings'])->name('devlink.add-settings'); Route::post('devlink/local-bundles/add-asset-to-bundles', [DevLinkController::class, 'addAssetToBundles'])->name('devlink.add-asset-to-bundles'); + Route::post('devlink/local-bundles/add-setting-to-bundles', [DevLinkController::class, 'addSettingToBundles'])->name('devlink.add-setting-to-bundles'); Route::delete('devlink/local-bundles/{bundle}', [DevLinkController::class, 'deleteBundle'])->name('devlink.delete-bundle'); Route::delete('devlink/local-bundles/assets/{bundle_asset}', [DevLinkController::class, 'deleteBundleAsset'])->name('devlink.delete-bundle-asset'); Route::delete('devlink/local-bundles/settings/{bundle_setting}', [DevLinkController::class, 'deleteBundleSetting'])->name('devlink.delete-bundle-setting'); From 3bd28bcebe7a4f3fef2736ca7a9dad7ffd4528b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gustavo=20Bascop=C3=A9?= Date: Fri, 10 Jan 2025 19:26:43 -0400 Subject: [PATCH 2/8] Identify the settings from an asset for install --- .../Http/Controllers/Api/DevLinkController.php | 2 +- ProcessMaker/Models/Bundle.php | 9 +++++---- ProcessMaker/Models/DevLink.php | 1 + .../components/SettingsMenuCollapse.vue | 17 ++++++++++++----- resources/js/components/shared/AddToBundle.vue | 8 +++++++- 5 files changed, 26 insertions(+), 11 deletions(-) diff --git a/ProcessMaker/Http/Controllers/Api/DevLinkController.php b/ProcessMaker/Http/Controllers/Api/DevLinkController.php index a0d06ac138..5c590319cb 100644 --- a/ProcessMaker/Http/Controllers/Api/DevLinkController.php +++ b/ProcessMaker/Http/Controllers/Api/DevLinkController.php @@ -244,7 +244,7 @@ public function addSettingToBundles(Request $request) foreach ($bundles as $id) { $bundle = Bundle::find($id); if ($bundle) { - $bundle->addSettingToBundles($request->input('setting'), $request->input('config')); + $bundle->addSettingToBundles($request->input('setting'), $request->input('config'), $request->input('type')); } } } diff --git a/ProcessMaker/Models/Bundle.php b/ProcessMaker/Models/Bundle.php index 47e77ca390..b0d56d833c 100644 --- a/ProcessMaker/Models/Bundle.php +++ b/ProcessMaker/Models/Bundle.php @@ -170,14 +170,15 @@ public function addSettings($setting, $newId, $type = null) } else { // Create a new BundleSetting with the initial ID $config = ['id' => []]; - if ($newId) { + if ($newId && $type !== 'settings') { $config['id'][] = $newId; } if ($type) { $settingsMenu = SettingsMenus::where('menu_group', $setting)->first(); if ($settingsMenu) { - $config['id'] = $settingsMenu->id; + $config['id'][] = $settingsMenu->id; + $config['type'] = $type; } } @@ -201,11 +202,11 @@ public function addAssetToBundles(ProcessMakerModel $asset) return $message; } - public function addSettingToBundles($setting, $newId) + public function addSettingToBundles($setting, $newId, $type = null) { $message = null; try { - $this->addSettings($setting, $newId); + $this->addSettings($setting, $newId, $type); } catch (ValidationException $ve) { $message = $ve->getMessage(); } diff --git a/ProcessMaker/Models/DevLink.php b/ProcessMaker/Models/DevLink.php index cf831d0210..2ac82248ca 100644 --- a/ProcessMaker/Models/DevLink.php +++ b/ProcessMaker/Models/DevLink.php @@ -142,6 +142,7 @@ public function installRemoteBundle($remoteBundleId, $updateType) $bundleExport = $this->client()->get( route('api.devlink.export-local-bundle', ['bundle' => $remoteBundleId], false) )->json(); + dd($bundleExport); $bundleSettingsExport = $this->client()->get( route('api.devlink.export-local-bundle-settings', ['bundle' => $remoteBundleId], false) diff --git a/resources/js/admin/settings/components/SettingsMenuCollapse.vue b/resources/js/admin/settings/components/SettingsMenuCollapse.vue index 6f5d978ef2..f2eec464fd 100644 --- a/resources/js/admin/settings/components/SettingsMenuCollapse.vue +++ b/resources/js/admin/settings/components/SettingsMenuCollapse.vue @@ -58,9 +58,9 @@ @@ -84,7 +84,9 @@ export default { collapsedMenus: {}, oldMenuGroups: [], changeEmailServers: false, - selectedMenu: null, + selectedMenu: { + menu_group: "User Settings", + }, actions: [ { value: "add-to-bundle", content: "Add to Bundle", icon: "fas fa-folder-plus" }, ], @@ -179,9 +181,14 @@ export default { this.selectItem(this.menuGroups[0].groups[0]); }, onNavigate(action, data, index) { - this.selectedMenu = data; - console.log(this.selectedMenu); - this.$root.$emit('add-to-bundle', data); + switch (action.value) { + case "add-to-bundle": + this.selectedMenu = data; + this.$root.$emit('add-to-bundle', data); + break; + default: + break; + } }, }, }; diff --git a/resources/js/components/shared/AddToBundle.vue b/resources/js/components/shared/AddToBundle.vue index 82b9117424..c0fb4986fe 100644 --- a/resources/js/components/shared/AddToBundle.vue +++ b/resources/js/components/shared/AddToBundle.vue @@ -10,6 +10,10 @@ const props = defineProps({ setting: { type: Boolean, default: false + }, + settingType: { + type: String, + default: null } }); @@ -34,6 +38,7 @@ const save = (event) => { window.ProcessMaker.apiClient.post(`devlink/local-bundles/${selected.value.id}/add-settings`, { setting: props.assetType, config: null, + type: props.settingType || null }) .then(() => { window.ProcessMaker.alert(vue.$t('Setting added to bundle'), 'success'); @@ -60,7 +65,8 @@ const save = (event) => { const setting = { 'setting': props.assetType, 'config': assetId.value, - 'bundles': bundles + 'bundles': bundles, + 'type': props.settingType || null }; window.ProcessMaker.apiClient.post(`devlink/local-bundles/add-setting-to-bundles`, setting).then(() => { modal.value.hide(); From 0107849fbb2360ca69b60b02230023ad09438d41 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gustavo=20Bascop=C3=A9?= Date: Wed, 15 Jan 2025 18:24:44 -0400 Subject: [PATCH 3/8] Added the import and export methods for the bundle settings --- .../Controllers/Api/DevLinkController.php | 5 + ProcessMaker/ImportExport/Importer.php | 3 +- ProcessMaker/ImportExport/Manifest.php | 9 +- ProcessMaker/Models/Bundle.php | 110 ++++++++++++-- ProcessMaker/Models/BundleSetting.php | 143 +++++++++++++++++- ProcessMaker/Models/DevLink.php | 7 +- .../components/BundleConfigurations.vue | 6 + .../admin/devlink/components/BundleDetail.vue | 2 + .../js/components/shared/AddToBundle.vue | 2 +- routes/api.php | 1 + 10 files changed, 262 insertions(+), 26 deletions(-) diff --git a/ProcessMaker/Http/Controllers/Api/DevLinkController.php b/ProcessMaker/Http/Controllers/Api/DevLinkController.php index 5c590319cb..408d387ce5 100644 --- a/ProcessMaker/Http/Controllers/Api/DevLinkController.php +++ b/ProcessMaker/Http/Controllers/Api/DevLinkController.php @@ -208,6 +208,11 @@ public function exportLocalBundleSettings(Bundle $bundle) return ['settings' => $bundle->exportSettings()]; } + public function exportLocalBundleSettingPayloads(Bundle $bundle) + { + return ['payloads' => $bundle->exportSettingPayloads()]; + } + public function exportLocalAsset(Request $request) { $asset = $request->input('class')::findOrFail($request->input('id')); diff --git a/ProcessMaker/ImportExport/Importer.php b/ProcessMaker/ImportExport/Importer.php index dd08295bb1..9b0af8d471 100644 --- a/ProcessMaker/ImportExport/Importer.php +++ b/ProcessMaker/ImportExport/Importer.php @@ -36,7 +36,7 @@ public function previewImport() public function loadManifest() { - return Manifest::fromArray($this->payload['export'], $this->options, $this->logger); + return Manifest::fromArray($this->payload['export'], $this->options, $this->logger, $this->payload['root']); } public function doImport($existingAssetInDatabase = null, $importingFromTemplate = false) @@ -50,6 +50,7 @@ public function doImport($existingAssetInDatabase = null, $importingFromTemplate $this->logger->log("Importing {$count} assets"); foreach ($this->manifest->all() as $uuid => $exporter) { $this->logger->setStatus('saving', $uuid); + \Log::info('Importing ' . get_class($exporter->model), ['mode' => $exporter->mode]); if ($exporter->mode !== 'discard') { $this->logger->log('Importing ' . get_class($exporter->model)); if ($exporter->disableEventsWhenImporting) { diff --git a/ProcessMaker/ImportExport/Manifest.php b/ProcessMaker/ImportExport/Manifest.php index 1b553cd592..494d3197b5 100644 --- a/ProcessMaker/ImportExport/Manifest.php +++ b/ProcessMaker/ImportExport/Manifest.php @@ -81,7 +81,7 @@ public function toArray($skipHidden = false) return $manifest; } - public static function fromArray(array $array, Options $options, $logger) + public static function fromArray(array $array, Options $options, $logger, $root) { self::$logger = $logger; @@ -95,7 +95,8 @@ public static function fromArray(array $array, Options $options, $logger) $exporterClass = $assetInfo['exporter']; $modeOption = $options->get('mode', $uuid); $saveAssetsModeOption = $options->get('saveAssetsMode', $uuid); - list($mode, $model, $matchedBy) = self::getModel($uuid, $assetInfo, $modeOption, $exporterClass); + $isRoot = $uuid === $root; + list($mode, $model, $matchedBy) = self::getModel($uuid, $assetInfo, $modeOption, $exporterClass, $isRoot); $model = self::updateBPMNDefinitions($model, $saveAssetsModeOption); $exporter = new $exporterClass($model, $manifest, $options, false); $exporter->logger = $logger; @@ -134,7 +135,7 @@ public function push(string $uuid, ExporterInterface $exporter) $this->manifest[$uuid] = $exporter; } - public static function getModel($uuid, $assetInfo, $mode, $exporterClass) + public static function getModel($uuid, $assetInfo, $mode, $exporterClass, $isRoot) { $model = null; $class = $assetInfo['model']; @@ -153,7 +154,7 @@ public static function getModel($uuid, $assetInfo, $mode, $exporterClass) } } - if ($exporterClass::doNotImport($uuid, $assetInfo)) { + if (!$isRoot && $exporterClass::doNotImport($uuid, $assetInfo)) { $mode = 'discard'; } diff --git a/ProcessMaker/Models/Bundle.php b/ProcessMaker/Models/Bundle.php index b0d56d833c..b5d29ea2f7 100644 --- a/ProcessMaker/Models/Bundle.php +++ b/ProcessMaker/Models/Bundle.php @@ -9,6 +9,7 @@ use ProcessMaker\ImportExport\Logger; use ProcessMaker\ImportExport\Options; use ProcessMaker\Models\ProcessMakerModel; +use ProcessMaker\Models\Setting; use ProcessMaker\Models\SettingsMenus; use Spatie\MediaLibrary\HasMedia; use Spatie\MediaLibrary\InteractsWithMedia; @@ -79,6 +80,17 @@ public function export() } public function exportSettings() + { + $exports = []; + + foreach ($this->settings as $setting) { + $exports[] = $setting; + } + + return $exports; + } + + public function exportSettingPayloads() { return $this->settings()->get()->map(function ($setting) { return $setting->export(); @@ -142,6 +154,11 @@ public function addAsset(ProcessMakerModel $asset) public function addSettings($setting, $newId, $type = null) { $existingSetting = $this->settings()->where('setting', $setting)->first(); + // verify if newId is a json with id key + $decodedNewId = json_decode($newId, true); + if (json_last_error() === JSON_ERROR_NONE && isset($decodedNewId['id'])) { + $newId = $decodedNewId['id']; + } if ($existingSetting) { // If the config is null, do not add the new ID @@ -169,24 +186,36 @@ public function addSettings($setting, $newId, $type = null) ]); } else { // Create a new BundleSetting with the initial ID - $config = ['id' => []]; - if ($newId && $type !== 'settings') { - $config['id'][] = $newId; - } + if ($newId === null && $type === null) { + BundleSetting::create([ + 'bundle_id' => $this->id, + 'setting' => $setting, + 'config' => null, + ]); + } else { + $config = ['id' => []]; + if ($newId && $type !== 'settings') { + $config['id'][] = $newId; + } - if ($type) { - $settingsMenu = SettingsMenus::where('menu_group', $setting)->first(); - if ($settingsMenu) { - $config['id'][] = $settingsMenu->id; - $config['type'] = $type; + if ($type === 'settings') { + $settingsMenu = SettingsMenus::where('menu_group', $setting)->first(); + $settingsKeys = Setting::where([ + ['group_id', '=', $settingsMenu->id], + ['hidden', '=', false], + ])->pluck('key')->toArray(); + if ($settingsMenu) { + $config['id'] = $settingsKeys; + $config['type'] = $type; + } } - } - BundleSetting::create([ - 'bundle_id' => $this->id, - 'setting' => $setting, - 'config' => json_encode($config), - ]); + BundleSetting::create([ + 'bundle_id' => $this->id, + 'setting' => $setting, + 'config' => json_encode($config), + ]); + } } } @@ -274,6 +303,57 @@ public function installSettings($settings) } } + public function installSettingsPayloads(array $payloads, $mode, $logger = null) + { + $options = new Options([ + 'mode' => $mode, + ]); + $clientRepository = app('Laravel\Passport\ClientRepository'); + + $assets = []; + foreach ($payloads as $payload) { + if (isset($payload['export'])) { + $logger->status('Installing bundle settings on the this instance'); + $logger->setSteps($payloads); + $assets[] = DevLink::import($payload, $options, $logger); + } else { + switch ($payload['setting_type']) { + case 'auth_clients': + $clientRepository->create( + null, + $payload['name'], + $payload['redirect'], + $payload['provider'], + $payload['personal_access_client'], + $payload['password_client'] + ); + break; + case 'User Settings': + case 'Email': + case 'Integrations': + case 'Log-In & Auth': + $settingsMenu = SettingsMenus::where('menu_group', $payload['setting_type'])->first(); + foreach ($payload['id'] as $key) { + Setting::updateOrCreate([ + 'key' => $key, + ], [ + 'config' => $payload['config'], + 'name' => $payload['name'], + 'helper' => $payload['helper'], + 'format' => $payload['format'], + 'hidden' => $payload['hidden'], + 'read_only' => $payload['read_only'], + 'ui' => $payload['ui'], + 'group' => $payload['group'], + 'group_id' => $settingsMenu->id, + ]); + } + break; + } + } + } + } + public function install(array $payloads, $mode, $logger = null) { if ($logger === null) { diff --git a/ProcessMaker/Models/BundleSetting.php b/ProcessMaker/Models/BundleSetting.php index 35de7bf8dc..9da8ed7981 100644 --- a/ProcessMaker/Models/BundleSetting.php +++ b/ProcessMaker/Models/BundleSetting.php @@ -3,7 +3,18 @@ namespace ProcessMaker\Models; use Illuminate\Database\Eloquent\Factories\HasFactory; +use ProcessMaker\Enums\ExporterMap; +use ProcessMaker\ImportExport\Exporter; +use ProcessMaker\ImportExport\Exporters\GroupExporter; +use ProcessMaker\ImportExport\Exporters\ScriptExecutorExporter; +use ProcessMaker\ImportExport\Exporters\UserExporter; use ProcessMaker\Models\ProcessMakerModel; +use ProcessMaker\Package\PackageDynamicUI\ImportExport\DashboardExporter; +use ProcessMaker\Package\PackageDynamicUI\ImportExport\MenuExporter; +use ProcessMaker\Package\PackageDynamicUI\Models\Dashboard; +use ProcessMaker\Package\PackageDynamicUI\Models\Menu; +use ProcessMaker\Package\Translations\ImportExport\TranslatableExporter; +use ProcessMaker\Package\Translations\Models\Translatable; class BundleSetting extends ProcessMakerModel { @@ -26,9 +37,133 @@ public function bundle() public function export() { - return [ - 'setting' => $this->setting, - 'config' => $this->config, - ]; + $configData = json_decode($this->config, true); + $ids = $configData['id'] ?? []; + + switch ($this->setting) { + case 'users': + if (empty($this->config)) { + $users = User::all(); + + return $users->map(function ($user) { + return $this->exportHelper($user, UserExporter::class); + }); + } else { + $users = User::whereIn('id', $ids)->get(); + + return $users->map(function ($user) { + return $this->exportHelper($user, UserExporter::class); + }); + } + case 'groups': + if (empty($this->config)) { + $groups = Group::all(); + + return $groups->map(function ($group) { + return $this->exportHelper($group, GroupExporter::class); + }); + } else { + $groups = Group::whereIn('id', $ids)->get(); + + return $groups->map(function ($group) { + return $this->exportHelper($group, GroupExporter::class); + }); + } + case 'script_executors': + if (empty($this->config)) { + $scriptExecutors = ScriptExecutor::all(); + + return $scriptExecutors->map(function ($scriptExecutor) { + return $this->exportHelper($scriptExecutor, ScriptExecutorExporter::class); + }); + } else { + $scriptExecutors = ScriptExecutor::whereIn('id', $ids)->get(); + + return $scriptExecutors->map(function ($scriptExecutor) { + return $this->exportHelper($scriptExecutor, ScriptExecutorExporter::class); + }); + } + case 'ui_dashboards': + if (empty($this->config)) { + $uiDashboards = Dashboard::all(); + + return $uiDashboards->map(function ($uiDashboard) { + return $this->exportHelper($uiDashboard, DashboardExporter::class); + }); + } else { + $uiDashboards = Dashboard::whereIn('id', $ids)->get(); + + return $uiDashboards->map(function ($uiDashboard) { + return $this->exportHelper($uiDashboard, DashboardExporter::class); + }); + } + case 'ui_menus': + if (empty($this->config)) { + $uiMenus = Menu::all(); + + return $uiMenus->map(function ($uiMenu) { + return $this->exportHelper($uiMenu, MenuExporter::class); + }); + } else { + $uiMenus = Menu::whereIn('id', $ids)->get(); + + return $uiMenus->map(function ($uiMenu) { + return $this->exportHelper($uiMenu, MenuExporter::class); + }); + } + case 'translations': + if (empty($this->config)) { + $translations = Translatable::all(); + + return $translations->map(function ($translation) { + return $this->exportHelper($translation, TranslatableExporter::class); + }); + } else { + $translations = Translatable::whereIn('key', $ids)->get(); + + return $translations->map(function ($translation) { + return $this->exportHelper($translation, TranslatableExporter::class); + }); + } + case 'auth_clients': + if (empty($this->config)) { + $authClients = \Laravel\Passport\Client::where('revoked', false)->get(); + + return $authClients->map(function ($authClient) { + $authClient->setting_type = $this->setting; + + return $authClient; + }); + } else { + $authClients = \Laravel\Passport\Client::where('revoked', false)->whereIn('id', $ids)->get(); + + return $authClients->map(function ($authClient) { + $authClient->setting_type = $this->setting; + + return $authClient; + }); + } + case 'Log-In & Auth': + case 'User Settings': + case 'Email': + case 'Integrations': + $bundleSettings = Setting::whereIn('key', $ids)->get(); + + return $bundleSettings->map(function ($bundleSetting) { + $bundleSetting->setting_type = $this->setting; + + return $bundleSetting; + }); + } + + return []; + } + + public function exportHelper($model, $exporterClass, $options = null, $ignoreExplicitExport = true) + { + $exporter = new Exporter(false, $ignoreExplicitExport); + $exporter->export($model, $exporterClass, $options); + + return $exporter->payload(); } } diff --git a/ProcessMaker/Models/DevLink.php b/ProcessMaker/Models/DevLink.php index 2ac82248ca..a00a1cd420 100644 --- a/ProcessMaker/Models/DevLink.php +++ b/ProcessMaker/Models/DevLink.php @@ -142,12 +142,15 @@ public function installRemoteBundle($remoteBundleId, $updateType) $bundleExport = $this->client()->get( route('api.devlink.export-local-bundle', ['bundle' => $remoteBundleId], false) )->json(); - dd($bundleExport); $bundleSettingsExport = $this->client()->get( route('api.devlink.export-local-bundle-settings', ['bundle' => $remoteBundleId], false) )->json(); + $bundleSettingsPayloads = $this->client()->get( + route('api.devlink.export-local-bundle-setting-payloads', ['bundle' => $remoteBundleId], false) + )->json(); + $bundle = Bundle::updateOrCreate( [ 'remote_id' => $remoteBundleId, @@ -161,7 +164,9 @@ public function installRemoteBundle($remoteBundleId, $updateType) ); $bundle->install($bundleExport['payloads'], $updateType, $this->logger); + $bundle->installSettingsPayloads($bundleSettingsPayloads['payloads'][0], $updateType, $this->logger); $bundle->installSettings($bundleSettingsExport['settings']); + $this->logger->setStatus('done'); } diff --git a/resources/js/admin/devlink/components/BundleConfigurations.vue b/resources/js/admin/devlink/components/BundleConfigurations.vue index f057c72650..1e488b23c2 100644 --- a/resources/js/admin/devlink/components/BundleConfigurations.vue +++ b/resources/js/admin/devlink/components/BundleConfigurations.vue @@ -16,6 +16,7 @@ @@ -89,6 +90,7 @@ { if (props.setting) { const setting = { 'setting': props.assetType, - 'config': assetId.value, + 'config': null, 'bundles': bundles, 'type': props.settingType || null }; diff --git a/routes/api.php b/routes/api.php index cef69151f8..0d4b1ec38f 100644 --- a/routes/api.php +++ b/routes/api.php @@ -405,6 +405,7 @@ Route::delete('devlink/local-bundles/settings/{bundle_setting}', [DevLinkController::class, 'deleteBundleSetting'])->name('devlink.delete-bundle-setting'); Route::get('devlink/export-local-bundle/{bundle}', [DevLinkController::class, 'exportLocalBundle'])->name('devlink.export-local-bundle'); Route::get('devlink/export-local-bundle/{bundle}/settings', [DevLinkController::class, 'exportLocalBundleSettings'])->name('devlink.export-local-bundle-settings'); + Route::get('devlink/export-local-bundle/{bundle}/settings-payloads', [DevLinkController::class, 'exportLocalBundleSettingPayloads'])->name('devlink.export-local-bundle-setting-payloads'); Route::get('devlink/export-local-asset', [DevLinkController::class, 'exportLocalAsset'])->name('devlink.export-local-asset'); Route::post('devlink/{devLink}/remote-bundles/{remoteBundleId}/install', [DevLinkController::class, 'installRemoteBundle'])->name('devlink.install-remote-bundle'); From 0d4d98f852a7e2c7655097f48bb042dbc14d92bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gustavo=20Bascop=C3=A9?= Date: Thu, 16 Jan 2025 12:24:14 -0400 Subject: [PATCH 4/8] fix export settings payloads --- .../Controllers/Api/DevLinkController.php | 21 ++++++++++++------- ProcessMaker/ImportExport/Dependent.php | 2 +- 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/ProcessMaker/Http/Controllers/Api/DevLinkController.php b/ProcessMaker/Http/Controllers/Api/DevLinkController.php index 408d387ce5..10aaf758a6 100644 --- a/ProcessMaker/Http/Controllers/Api/DevLinkController.php +++ b/ProcessMaker/Http/Controllers/Api/DevLinkController.php @@ -168,14 +168,15 @@ public function deleteBundle(Bundle $bundle) public function installRemoteBundle(Request $request, DevLink $devLink, $remoteBundleId) { $updateType = $request->input('updateType', DevLinkInstall::MODE_UPDATE); - DevLinkInstall::dispatch( - $request->user()->id, - $devLink->id, - Bundle::class, - $remoteBundleId, - $updateType, - DevLinkInstall::TYPE_INSTALL_BUNDLE, - ); + // DevLinkInstall::dispatch( + // $request->user()->id, + // $devLink->id, + // Bundle::class, + // $remoteBundleId, + // $updateType, + // DevLinkInstall::TYPE_INSTALL_BUNDLE, + // ); + $devLink->installRemoteBundle($remoteBundleId, $updateType); return [ 'status' => 'queued', @@ -210,6 +211,10 @@ public function exportLocalBundleSettings(Bundle $bundle) public function exportLocalBundleSettingPayloads(Bundle $bundle) { + if ($bundle->settings->isEmpty()) { + return ['payloads' => [0 => []]]; + } + return ['payloads' => $bundle->exportSettingPayloads()]; } diff --git a/ProcessMaker/ImportExport/Dependent.php b/ProcessMaker/ImportExport/Dependent.php index 9d25b3e412..a115882bb7 100644 --- a/ProcessMaker/ImportExport/Dependent.php +++ b/ProcessMaker/ImportExport/Dependent.php @@ -56,7 +56,7 @@ public function __get($property) 'attributes' => $this->fallbackMatches, ]; - list($_, $model) = Manifest::getModel($this->uuid, $assetInfo, 'discard', $this->exporterClass); + list($_, $model) = Manifest::getModel($this->uuid, $assetInfo, 'discard', $this->exporterClass, false); // Only return the model if it is persisted in the database if ($model && $model->exists) { From 9777abf081732fe80e3ed56ba55add8c241ee36d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gustavo=20Bascop=C3=A9?= Date: Fri, 17 Jan 2025 14:59:21 -0400 Subject: [PATCH 5/8] fixed code review observations --- .../Controllers/Api/DevLinkController.php | 17 ++-- ProcessMaker/Models/BundleSetting.php | 88 ++++++------------- 2 files changed, 37 insertions(+), 68 deletions(-) diff --git a/ProcessMaker/Http/Controllers/Api/DevLinkController.php b/ProcessMaker/Http/Controllers/Api/DevLinkController.php index 10aaf758a6..3eb474fee0 100644 --- a/ProcessMaker/Http/Controllers/Api/DevLinkController.php +++ b/ProcessMaker/Http/Controllers/Api/DevLinkController.php @@ -168,15 +168,14 @@ public function deleteBundle(Bundle $bundle) public function installRemoteBundle(Request $request, DevLink $devLink, $remoteBundleId) { $updateType = $request->input('updateType', DevLinkInstall::MODE_UPDATE); - // DevLinkInstall::dispatch( - // $request->user()->id, - // $devLink->id, - // Bundle::class, - // $remoteBundleId, - // $updateType, - // DevLinkInstall::TYPE_INSTALL_BUNDLE, - // ); - $devLink->installRemoteBundle($remoteBundleId, $updateType); + DevLinkInstall::dispatch( + $request->user()->id, + $devLink->id, + Bundle::class, + $remoteBundleId, + $updateType, + DevLinkInstall::TYPE_INSTALL_BUNDLE, + ); return [ 'status' => 'queued', diff --git a/ProcessMaker/Models/BundleSetting.php b/ProcessMaker/Models/BundleSetting.php index 9da8ed7981..9a8afb14a4 100644 --- a/ProcessMaker/Models/BundleSetting.php +++ b/ProcessMaker/Models/BundleSetting.php @@ -44,105 +44,75 @@ public function export() case 'users': if (empty($this->config)) { $users = User::all(); - - return $users->map(function ($user) { - return $this->exportHelper($user, UserExporter::class); - }); } else { $users = User::whereIn('id', $ids)->get(); - - return $users->map(function ($user) { - return $this->exportHelper($user, UserExporter::class); - }); } + + return $users->map(function ($user) { + return $this->exportHelper($user, UserExporter::class); + }); case 'groups': if (empty($this->config)) { $groups = Group::all(); - - return $groups->map(function ($group) { - return $this->exportHelper($group, GroupExporter::class); - }); } else { $groups = Group::whereIn('id', $ids)->get(); - - return $groups->map(function ($group) { - return $this->exportHelper($group, GroupExporter::class); - }); } + + return $groups->map(function ($group) { + return $this->exportHelper($group, GroupExporter::class); + }); case 'script_executors': if (empty($this->config)) { $scriptExecutors = ScriptExecutor::all(); - - return $scriptExecutors->map(function ($scriptExecutor) { - return $this->exportHelper($scriptExecutor, ScriptExecutorExporter::class); - }); } else { $scriptExecutors = ScriptExecutor::whereIn('id', $ids)->get(); - - return $scriptExecutors->map(function ($scriptExecutor) { - return $this->exportHelper($scriptExecutor, ScriptExecutorExporter::class); - }); } + + return $scriptExecutors->map(function ($scriptExecutor) { + return $this->exportHelper($scriptExecutor, ScriptExecutorExporter::class); + }); case 'ui_dashboards': if (empty($this->config)) { $uiDashboards = Dashboard::all(); - - return $uiDashboards->map(function ($uiDashboard) { - return $this->exportHelper($uiDashboard, DashboardExporter::class); - }); } else { $uiDashboards = Dashboard::whereIn('id', $ids)->get(); - - return $uiDashboards->map(function ($uiDashboard) { - return $this->exportHelper($uiDashboard, DashboardExporter::class); - }); } + + return $uiDashboards->map(function ($uiDashboard) { + return $this->exportHelper($uiDashboard, DashboardExporter::class); + }); case 'ui_menus': if (empty($this->config)) { $uiMenus = Menu::all(); - - return $uiMenus->map(function ($uiMenu) { - return $this->exportHelper($uiMenu, MenuExporter::class); - }); } else { $uiMenus = Menu::whereIn('id', $ids)->get(); - - return $uiMenus->map(function ($uiMenu) { - return $this->exportHelper($uiMenu, MenuExporter::class); - }); } + + return $uiMenus->map(function ($uiMenu) { + return $this->exportHelper($uiMenu, MenuExporter::class); + }); case 'translations': if (empty($this->config)) { $translations = Translatable::all(); - - return $translations->map(function ($translation) { - return $this->exportHelper($translation, TranslatableExporter::class); - }); } else { $translations = Translatable::whereIn('key', $ids)->get(); - - return $translations->map(function ($translation) { - return $this->exportHelper($translation, TranslatableExporter::class); - }); } + + return $translations->map(function ($translation) { + return $this->exportHelper($translation, TranslatableExporter::class); + }); case 'auth_clients': if (empty($this->config)) { $authClients = \Laravel\Passport\Client::where('revoked', false)->get(); - - return $authClients->map(function ($authClient) { - $authClient->setting_type = $this->setting; - - return $authClient; - }); } else { $authClients = \Laravel\Passport\Client::where('revoked', false)->whereIn('id', $ids)->get(); + } - return $authClients->map(function ($authClient) { - $authClient->setting_type = $this->setting; + return $authClients->map(function ($authClient) { + $authClient->setting_type = $this->setting; - return $authClient; - }); - } + return $authClient; + }); case 'Log-In & Auth': case 'User Settings': case 'Email': From 6ceafad371452bcd6fd6fe121e9af92bbed1bde7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gustavo=20Bascop=C3=A9?= Date: Mon, 20 Jan 2025 12:05:09 -0400 Subject: [PATCH 6/8] Fixed php unit tests --- tests/Model/DevLinkTest.php | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/tests/Model/DevLinkTest.php b/tests/Model/DevLinkTest.php index 5a35e8356b..dcec8f0c75 100644 --- a/tests/Model/DevLinkTest.php +++ b/tests/Model/DevLinkTest.php @@ -7,6 +7,7 @@ use ProcessMaker\Models\Bundle; use ProcessMaker\Models\DevLink; use ProcessMaker\Models\Screen; +use ProcessMaker\Models\User; use Tests\TestCase; class DevLinkTest extends TestCase @@ -60,10 +61,14 @@ public function testInstallRemoteBundle() $screen1 = Screen::factory()->create(['title' => 'Screen 1']); $screen2 = Screen::factory()->create(['title' => 'Screen 2']); + + $user1 = User::factory()->create(); + $bundle = Bundle::factory()->create([]); $bundle->syncAssets([$screen1, $screen2]); - + $bundle->addSettings('users', $user1->id); $exports = $bundle->export(); + $exportsSettingsPayloads = $bundle->exportSettingPayloads(); $screen1->delete(); $screen2->delete(); @@ -85,6 +90,9 @@ public function testInstallRemoteBundle() 'config' => null, ]], ]), + 'http://remote-instance.test/api/1.0/devlink/export-local-bundle/123/settings-payloads' => Http::response([ + 'payloads' => $exportsSettingsPayloads, + ]), ]); $devLink = DevLink::factory()->create([ @@ -147,8 +155,12 @@ public function testUpdateBundle() // Remote Instance $screen = Screen::factory()->create(['title' => 'Screen Name']); $bundle = Bundle::factory()->create([]); + $user1 = User::factory()->create(); + $bundle->addSettings('users', $user1->id); $bundle->syncAssets([$screen]); $exports = $bundle->export(); + $exportsSettingsPayloads = $bundle->exportSettingPayloads(); + $screenUuid = $screen->uuid; $screen->delete(); @@ -222,6 +234,9 @@ public function testUpdateBundle() 'config' => null, ]], ]), + 'http://remote-instance.test/api/1.0/devlink/export-local-bundle/123/settings-payloads' => Http::response([ + 'payloads' => $exportsSettingsPayloads, + ]), ]); $devLink->installRemoteBundle(123, 'update'); From 030e6e4d5e70a5d727fca7b84e17560b8e42aa70 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gustavo=20Bascop=C3=A9?= Date: Mon, 20 Jan 2025 13:34:51 -0400 Subject: [PATCH 7/8] Fixed manifest php unit test --- tests/Feature/ImportExport/ManifestTest.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/Feature/ImportExport/ManifestTest.php b/tests/Feature/ImportExport/ManifestTest.php index 023a062a9d..0ac76f2eed 100644 --- a/tests/Feature/ImportExport/ManifestTest.php +++ b/tests/Feature/ImportExport/ManifestTest.php @@ -147,7 +147,7 @@ public function testWarningIfExporterClassMissing() ], ]; - Manifest::fromArray($payload, new Options([]), new Logger($user->id)); + Manifest::fromArray($payload, new Options([]), new Logger($user->id), $user->uuid); Event::assertDispatched(ImportLog::class, function ($event) { return $event->message === 'Class My\Test\Package does not exist.'; @@ -168,7 +168,7 @@ public function testWarningIfModelClassMissing() ], ]; - Manifest::fromArray($payload, new Options([]), new Logger($user->id)); + Manifest::fromArray($payload, new Options([]), new Logger($user->id), $user->uuid); Event::assertDispatched(ImportLog::class, function ($event) { return $event->message === 'Class Some\Other\Class does not exist.'; @@ -192,7 +192,7 @@ public function testWarningIfUnknownColumn() ], ]; - Manifest::fromArray($payload, new Options([]), new Logger($user->id)); + Manifest::fromArray($payload, new Options([]), new Logger($user->id), $user->uuid); Event::assertDispatched(ImportLog::class, function ($event) { return $event->message === "Attribute 'a_missing_column' does not exist in the table 'screens'"; From ac261650a18df0a5419f3b4d0458c074a99ccbac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gustavo=20Bascop=C3=A9?= Date: Thu, 23 Jan 2025 01:57:02 -0400 Subject: [PATCH 8/8] fixed adding settings to bundle and installing bundle --- ProcessMaker/Models/Bundle.php | 135 ++++++++++-------- ProcessMaker/Models/DevLink.php | 2 +- .../js/components/shared/AddToBundle.vue | 4 +- 3 files changed, 75 insertions(+), 66 deletions(-) diff --git a/ProcessMaker/Models/Bundle.php b/ProcessMaker/Models/Bundle.php index b5d29ea2f7..2a6134f9b6 100644 --- a/ProcessMaker/Models/Bundle.php +++ b/ProcessMaker/Models/Bundle.php @@ -154,68 +154,79 @@ public function addAsset(ProcessMakerModel $asset) public function addSettings($setting, $newId, $type = null) { $existingSetting = $this->settings()->where('setting', $setting)->first(); + //If $newId is null, set config to null + if (is_null($newId) && is_null($type)) { + if ($existingSetting) { + $existingSetting->update(['config' => null]); + } else { + BundleSetting::create([ + 'bundle_id' => $this->id, + 'setting' => $setting, + 'config' => null, + ]); + } + + return; + } // verify if newId is a json with id key $decodedNewId = json_decode($newId, true); - if (json_last_error() === JSON_ERROR_NONE && isset($decodedNewId['id'])) { - $newId = $decodedNewId['id']; + if (json_last_error() === JSON_ERROR_NONE) { + if (is_array($decodedNewId)) { + $newId = $decodedNewId; + } elseif (isset($decodedNewId['id'])) { + $newId = [$decodedNewId['id']]; + } else { + $newId = ['id' => [$decodedNewId]]; + } + } else { + $newId = ['id' => [$newId]]; } if ($existingSetting) { - // If the config is null, do not add the new ID - if (is_null($existingSetting->config)) { - return; - } - // Decode the existing JSON $config = json_decode($existingSetting->config, true); - // Ensure 'id' is an array if (!isset($config['id']) || !is_array($config['id'])) { $config['id'] = []; } - // Add the new ID - $config['id'][] = $newId; - + foreach ($newId['id'] as $id) { + $config['id'][] = $id; + } // Remove duplicates $config['id'] = array_unique($config['id']); - + //reindex the array + $config['id'] = array_values($config['id']); // Update the config $existingSetting->update([ 'config' => json_encode($config), ]); } else { // Create a new BundleSetting with the initial ID - if ($newId === null && $type === null) { - BundleSetting::create([ - 'bundle_id' => $this->id, - 'setting' => $setting, - 'config' => null, - ]); - } else { - $config = ['id' => []]; - if ($newId && $type !== 'settings') { - $config['id'][] = $newId; + $config = ['id' => []]; + if ($newId && $type !== 'settings') { + foreach ($newId['id'] as $id) { + $config['id'][] = $id; } + } - if ($type === 'settings') { - $settingsMenu = SettingsMenus::where('menu_group', $setting)->first(); - $settingsKeys = Setting::where([ - ['group_id', '=', $settingsMenu->id], - ['hidden', '=', false], - ])->pluck('key')->toArray(); - if ($settingsMenu) { - $config['id'] = $settingsKeys; - $config['type'] = $type; - } + if ($type === 'settings') { + $settingsMenu = SettingsMenus::where('menu_group', $setting)->first(); + $settingsKeys = Setting::where([ + ['group_id', '=', $settingsMenu->id], + ['hidden', '=', false], + ])->pluck('key')->toArray(); + if ($settingsMenu) { + $config['id'] = $settingsKeys; + $config['type'] = $type; } - - BundleSetting::create([ - 'bundle_id' => $this->id, - 'setting' => $setting, - 'config' => json_encode($config), - ]); } + + BundleSetting::create([ + 'bundle_id' => $this->id, + 'setting' => $setting, + 'config' => json_encode($config), + ]); } } @@ -312,42 +323,40 @@ public function installSettingsPayloads(array $payloads, $mode, $logger = null) $assets = []; foreach ($payloads as $payload) { - if (isset($payload['export'])) { + if (isset($payload[0]['export'])) { $logger->status('Installing bundle settings on the this instance'); - $logger->setSteps($payloads); - $assets[] = DevLink::import($payload, $options, $logger); + $logger->setSteps($payloads[0]); + $assets[] = DevLink::import($payload[0], $options, $logger); } else { - switch ($payload['setting_type']) { + switch ($payload[0]['setting_type']) { case 'auth_clients': $clientRepository->create( null, - $payload['name'], - $payload['redirect'], - $payload['provider'], - $payload['personal_access_client'], - $payload['password_client'] + $payload[0]['name'], + $payload[0]['redirect'], + $payload[0]['provider'], + $payload[0]['personal_access_client'], + $payload[0]['password_client'] ); break; case 'User Settings': case 'Email': case 'Integrations': case 'Log-In & Auth': - $settingsMenu = SettingsMenus::where('menu_group', $payload['setting_type'])->first(); - foreach ($payload['id'] as $key) { - Setting::updateOrCreate([ - 'key' => $key, - ], [ - 'config' => $payload['config'], - 'name' => $payload['name'], - 'helper' => $payload['helper'], - 'format' => $payload['format'], - 'hidden' => $payload['hidden'], - 'read_only' => $payload['read_only'], - 'ui' => $payload['ui'], - 'group' => $payload['group'], - 'group_id' => $settingsMenu->id, - ]); - } + $settingsMenu = SettingsMenus::where('menu_group', $payload[0]['setting_type'])->first(); + Setting::updateOrCreate([ + 'key' => $payload[0]['key'], + ], [ + 'config' => $payload[0]['config'], + 'name' => $payload[0]['name'], + 'helper' => $payload[0]['helper'], + 'format' => $payload[0]['format'], + 'hidden' => $payload[0]['hidden'], + 'readonly' => $payload[0]['readonly'], + 'ui' => $payload[0]['ui'], + 'group_id' => $settingsMenu->id, + 'group' => $payload[0]['group'], + ]); break; } } diff --git a/ProcessMaker/Models/DevLink.php b/ProcessMaker/Models/DevLink.php index a00a1cd420..9fd0724379 100644 --- a/ProcessMaker/Models/DevLink.php +++ b/ProcessMaker/Models/DevLink.php @@ -164,7 +164,7 @@ public function installRemoteBundle($remoteBundleId, $updateType) ); $bundle->install($bundleExport['payloads'], $updateType, $this->logger); - $bundle->installSettingsPayloads($bundleSettingsPayloads['payloads'][0], $updateType, $this->logger); + $bundle->installSettingsPayloads($bundleSettingsPayloads['payloads'], $updateType, $this->logger); $bundle->installSettings($bundleSettingsExport['settings']); $this->logger->setStatus('done'); diff --git a/resources/js/components/shared/AddToBundle.vue b/resources/js/components/shared/AddToBundle.vue index 8c58b00c5f..1efa6aaa66 100644 --- a/resources/js/components/shared/AddToBundle.vue +++ b/resources/js/components/shared/AddToBundle.vue @@ -37,7 +37,7 @@ const save = (event) => { if (props.setting) { window.ProcessMaker.apiClient.post(`devlink/local-bundles/${selected.value.id}/add-settings`, { setting: props.assetType, - config: null, + config: assetId.value, type: props.settingType || null }) .then(() => { @@ -64,7 +64,7 @@ const save = (event) => { if (props.setting) { const setting = { 'setting': props.assetType, - 'config': null, + 'config': assetId.value, 'bundles': bundles, 'type': props.settingType || null };