diff --git a/controllers/admin/AdminCoreUpdaterController.php b/controllers/admin/AdminCoreUpdaterController.php index d5c6e06..eb24275 100644 --- a/controllers/admin/AdminCoreUpdaterController.php +++ b/controllers/admin/AdminCoreUpdaterController.php @@ -49,6 +49,7 @@ class AdminCoreUpdaterController extends ModuleAdminController const ACTION_GET_DATABASE_DIFFERENCES = "GET_DATABASE_DIFFERENCES"; const ACTION_APPLY_DATABASE_FIX = 'APPLY_DATABASE_FIX'; const ACTION_RUN_POST_UPDATE_PROCESSES = 'RUN_POST_UPDATE_PROCESSES'; + const ACTION_PREVIEW_FILE = 'PREVIEW_FILE'; const SELECTED_PROCESS_MIGRATE_DB = 'SELECTED_PROCESS_MIGRATE_DB'; const SELECTED_PROCESS_INITIALIZATION_CALLBACK = 'SELECTED_PROCESS_INITIALIZATION_CALLBACK'; @@ -777,6 +778,8 @@ protected function processAction($action) return $this->getDatabaseDifferences(); case static::ACTION_APPLY_DATABASE_FIX: return $this->applyDatabaseFix(Tools::getValue('ids')); + case static::ACTION_PREVIEW_FILE: + return $this->previewFile(); default: throw new PrestaShopException("Invalid action: $action"); } @@ -935,7 +938,8 @@ public function createCompareResult($compareProcessId, $result, $installedRevisi 'versionType' => $versionType, 'installedRevision' => $installedRevision, 'targetRevision' => $targetRevision, - 'changeSet' => $changeSet + 'changeSet' => $changeSet, + 'developerMode' => Settings::isDeveloperMode(), ]); return [ @@ -955,6 +959,22 @@ protected function initUpdateProcess() if (! $result) { throw new PrestaShopException("Comparision result not found. Please reload the page and try again"); } + $ignored = null; + if (Settings::isDeveloperMode()) { + $ignored = Tools::getValue('ignoreFiles'); + if ($ignored && !is_array($ignored)) { + $ignored = [$ignored]; + } + if ($ignored) { + foreach ($ignored as $path) { + foreach (['change','add','remove'] as $type) { + if (isset($result['changeSet'][$type][$path])) { + unset($result['changeSet'][$type][$path]); + } + } + } + } + } $targetFileList = $comparator->getFileList( $compareProcessId, $result['targetRevision'], @@ -979,6 +999,72 @@ protected function initUpdateProcess() ]; } + /** + * Returns preview of given file + * + * @return array + * + * @throws PrestaShopException + */ + protected function previewFile() + { + if (!Settings::isDeveloperMode()) { + throw new PrestaShopException('Developer mode is not enabled'); + } + $compareProcessId = Tools::getValue('compareProcessId'); + $file = Tools::getValue('file'); + if (!$file) { + throw new PrestaShopException('File not specified'); + } + $comparator = $this->factory->getComparator(); + $result = $comparator->getResult($compareProcessId); + if (!$result) { + throw new PrestaShopException('Comparision result not found. Please reload the page and try again'); + } + $apiPath = preg_replace('#^' . preg_quote(basename(_PS_ADMIN_DIR_) . '/') . '#', 'admin/', $file); + $tmp = tempnam(_PS_CACHE_DIR_, 'cu'); + try { + $this->factory->getApi()->downloadFiles( + $result['targetPHPVersion'], + $result['targetRevision'], + [ $apiPath ], + $tmp + ); + $tar = new Archive_Tar($tmp); + $remoteContent = $tar->extractInString($apiPath); + } finally { + @unlink($tmp); + } + + $localPath = _PS_ROOT_DIR_ . '/' . $this->fixAdminDirectory($file); + $localContent = file_exists($localPath) ? file_get_contents($localPath) : ''; + + $tmpRemote = tempnam(_PS_CACHE_DIR_, 'cu'); + $tmpLocal = tempnam(_PS_CACHE_DIR_, 'cu'); + file_put_contents($tmpRemote, $remoteContent); + file_put_contents($tmpLocal, $localContent); + $cmd = sprintf('diff -u %s %s 2>&1', escapeshellarg($tmpLocal), escapeshellarg($tmpRemote)); + $diff = shell_exec($cmd); + @unlink($tmpRemote); + @unlink($tmpLocal); + + return [ + 'diff' => base64_encode($diff === null ? '' : $diff), + ]; + } + + /** + * Replace admin directory placeholder with real directory name + * + * @param string $file + * @return string + */ + protected function fixAdminDirectory($file) + { + $adminDir = basename(_PS_ADMIN_DIR_); + return preg_replace('#^admin/#', $adminDir . '/', $file); + } + /** * Returns currently selected tab * diff --git a/views/css/coreupdater.css b/views/css/coreupdater.css index 3752f68..270b873 100644 --- a/views/css/coreupdater.css +++ b/views/css/coreupdater.css @@ -96,3 +96,19 @@ top: 50%; left: 50%; } + +/* File preview diff styles */ +#file-preview-diff { + max-height: 70vh; + overflow: auto; + background: #f8f8f8; + padding: 10px; +} +#file-preview-diff .diff-add { background-color: #c8f7cf; } +#file-preview-diff .diff-del { background-color: #ffd2d7; } +#file-preview-diff .diff-hunk { background-color: #e0ecff; } + +.ignore-label { + font-weight: normal !important; + margin: 0 0 0 5px; +} diff --git a/views/js/controller.js b/views/js/controller.js index 520c8d7..1d03efa 100644 --- a/views/js/controller.js +++ b/views/js/controller.js @@ -174,13 +174,21 @@ window.initializeCoreUpdater = function(translations) { incrementProcess('UPDATE', process, endProgress); }; - var update = function(compareProcessId) { + var update = function(compareProcessId, ignored) { initProgress(translations.UPDATE, translations.UPDATE_DESCRIPTION); - executeAction('INIT_UPDATE', { compareProcessId: compareProcessId }) + var params = { compareProcessId: compareProcessId }; + if (ignored && ignored.length > 0) { + params.ignoreFiles = ignored; + } + executeAction('INIT_UPDATE', params) .then(runUpdate) .catch(displayError); }; + var preview = function(compareProcessId, file) { + return executeAction('PREVIEW_FILE', { compareProcessId: compareProcessId, file: file }); + }; + var checkDatabase = function() { document.getElementById('db-changes').className = 'status-running'; executeAction('GET_DATABASE_DIFFERENCES') @@ -282,6 +290,7 @@ window.initializeCoreUpdater = function(translations) { compare: compare, update: update, checkDatabase: checkDatabase, + preview: preview, } }; diff --git a/views/templates/admin/result.tpl b/views/templates/admin/result.tpl index 3e8fb95..0339aa1 100644 --- a/views/templates/admin/result.tpl +++ b/views/templates/admin/result.tpl @@ -71,6 +71,9 @@
{l s='Oh, bummer. Some of thirty bees core files have been [1]modified[/1]. That makes it a little bit harder to update your store.' tags=[''] mod='coreupdater'}
+ {if $developerMode} +{l s='You are using Developer mode and few functions are visible. Use them at your own risk and only if you know what they do.' mod='coreupdater'}
+ {/if}
{l s='Modification of core files is not recommended. It makes it very hard to keep your store updated.' tags=[''] mod='coreupdater'}
{l s='You should [1]extract[/1] your modifications to overrides or to module. If unsure how to do that, please contact [2]thirty bees support[/2], we can help.' tags=['', ''] mod='coreupdater'}
@@ -115,6 +118,10 @@
{if $modified}
{l s='modified' mod='coreupdater'}
{/if}
+ {if $developerMode}
+ {l s='Preview' mod='coreupdater'}
+
+ {/if}
{/foreach}
@@ -131,6 +138,10 @@
{if $modified}
{l s='modified' mod='coreupdater'}
{/if}
+ {if $developerMode}
+ {l s='Preview' mod='coreupdater'}
+
+ {/if}
{/foreach}
@@ -147,6 +158,10 @@
{if $modified}
{l s='modified' mod='coreupdater'}
{/if}
+ {if $developerMode}
+ {l s='Preview' mod='coreupdater'}
+
+ {/if}
{/foreach}
@@ -160,10 +175,60 @@
{l s='Update store' mod='coreupdater'}
-
{/if}
+
+{if $developerMode}
+