From 00c5a014b420d6852b23c79333e5d46266fe67eb Mon Sep 17 00:00:00 2001 From: Roland Gruber Date: Sun, 12 Apr 2020 21:51:19 +0200 Subject: [PATCH] import main config --- lam/lib/config.inc | 2 +- lam/lib/persistence.inc | 137 +++++++++++++++++++++- lam/templates/config/confImportExport.php | 86 +++++++++++++- lam/tests/lib/LAMCfgMainTest.php | 2 + lam/tests/lib/persistenceTest.php | 2 +- 5 files changed, 223 insertions(+), 6 deletions(-) diff --git a/lam/lib/config.inc b/lam/lib/config.inc index 50b95c91..201ddf2c 100644 --- a/lam/lib/config.inc +++ b/lam/lib/config.inc @@ -2705,7 +2705,7 @@ class LAMCfgMain { logNewMessage(LOG_WARNING, 'Ignored setting during import: ' . $dataKey); continue; } - if (!(is_array($dataValue) || is_string($dataValue) || is_int($dataValue) || is_bool($dataValue))) { + if (!(($dataValue === null) || is_array($dataValue) || is_string($dataValue) || is_int($dataValue) || is_bool($dataValue))) { throw new LAMException('Invalid import data type for ' . htmlspecialchars($dataKey) . ': ' . gettype($dataValue)); } $this->$dataKey = $dataValue; diff --git a/lam/lib/persistence.inc b/lam/lib/persistence.inc index 60f54783..dadbeb31 100644 --- a/lam/lib/persistence.inc +++ b/lam/lib/persistence.inc @@ -1,5 +1,8 @@ _getMainConfigData(); + $jsonData['mainConfig'] = $this->_getMainConfigData(); return json_encode($jsonData); } @@ -50,9 +53,137 @@ class ConfigDataExporter { * @return array data */ public function _getMainConfigData() { - $mainCfg = new \LAMCfgMain(); + $mainCfg = new LAMCfgMain(); return $mainCfg->exportData(); } } +/** + * Importer for LAM's configuration data. + */ +class ConfigDataImporter { + + /** + * Returns a list of possible import objects. + * + * @param string $json JSON data + * @return ImporterStep[] steps + * @throws LAMException if invalid format + */ + public function getPossibleImportSteps($json) { + $data = json_decode($json); + if ($data === null) { + throw new LAMException(_('Unable to read import file.')); + } + $steps = array(); + foreach ($data as $key => $value) { + switch ($key) { + case 'mainConfig': + $steps[] = new ImporterStep(_('General settings'), 'mainConfig', $value); + break; + default: + logNewMessage(LOG_WARNING, 'Unknown import type: ' . $key); + } + } + if (empty($steps)) { + throw new LAMException(_('Unable to read import file.')); + } + return $steps; + } + + /** + * Runs the actual import. + * + * @param ImporterStep[] $steps import steps + * @throws LAMException if error occured + */ + public function runImport($steps) { + foreach ($steps as $step) { + if (!$step->isActive()) { + continue; + } + $key = $step->getKey(); + switch ($key) { + case 'mainConfig': + $cfgMain = new LAMCfgMain(); + $cfgMain->importData($step->getValue()); + $cfgMain->save(); + break; + default: + logNewMessage(LOG_WARNING, 'Unknown import type: ' . $key); + } + } + } + +} + +/** + * Step of the import process. + */ +class ImporterStep { + + private $label; + private $key; + private $value; + private $active = false; + + /** + * Constructor. + * + * @param string $label label + * @param string $key key + * @param array $value value + */ + public function __construct($label, $key, &$value) { + $this->label = $label; + $this->key = $key; + $this->value = $value; + } + + /** + * Returns the label. + * + * @return string label + */ + public function getLabel() { + return $this->label; + } + + /** + * Returns the key. + * + * @return string key + */ + public function getKey() { + return $this->key; + } + + /** + * Returns if this step should be executed. + * + * @return bool active + */ + public function isActive(): bool { + return $this->active; + } + + /** + * Sets if this step should be executed. + * + * @param bool $active active + */ + public function setActive(bool $active) { + $this->active = $active; + } + + /** + * Returns the value. + * + * @return string value + */ + public function getValue() { + return $this->value; + } + +} diff --git a/lam/templates/config/confImportExport.php b/lam/templates/config/confImportExport.php index d51b8cda..0f461f71 100644 --- a/lam/templates/config/confImportExport.php +++ b/lam/templates/config/confImportExport.php @@ -1,13 +1,18 @@ -
+

setIsPassword(true); + $pwdInput->setCSSClasses(array('lam-initial-focus')); $loginContent->add($pwdInput, 12); $loginContent->addLabel(new htmlOutputText(' ', false)); $loginContent->addField(new htmlButton('submitLogin', _("Ok"))); @@ -127,8 +133,21 @@ printHeaderContents(_("Import and export configuration"), '../..'); $content->add($loginContent, 12); parseHtml(null, $content, array(), false, $tabindex, null); + renderBackLink(); } + /** + * Renders the link back to login page. + */ + function renderBackLink() { + $tabindex = 0; + $content = new htmlResponsiveRow(); + $content->addVerticalSpacer('2rem'); + $content->add(new htmlLink(_('Back to login'), '../login.php', '../../graphics/undo.png'), 12); + $content->addVerticalSpacer('1rem'); + parseHtml(null, $content, array(), false, $tabindex, null); + } + /** * Checks the login password. * @@ -158,8 +177,73 @@ printHeaderContents(_("Import and export configuration"), '../..'); $content->add(new htmlButton('exportConfig', _('Export')), 12); $content->add(new htmlSubTitle(_('Import')), 12); + renderImportPart($content); parseHtml(null, $content, array(), false, $tabindex, null); + renderBackLink(); + } + + /** + * Renders the import area. + * + * @param htmlResponsiveRow $content content where to add import part + */ + function renderImportPart($content) { + $fileContent = null; + $validUpload = false; + $importSteps = array(); + if (isset($_POST['importConfig'])) { + $handle = fopen($_FILES['import-file']['tmp_name'], "r"); + $data = fread($handle, 100000000); + fclose($handle); + try { + $importer = new ConfigDataImporter(); + $importSteps = $importer->getPossibleImportSteps($data); + $tmpFile = __DIR__ . '/../../tmp/internal/import_' . getRandomNumber() . '.tmp'; + $file = @fopen($tmpFile, "w"); + if ($file) { + fputs($file, $data); + fclose($file); + chmod($tmpFile, 0600); + } + $_SESSION['configImportFile'] = $tmpFile; + $validUpload = true; + } + catch (LAMException $e) { + $content->add(new htmlStatusMessage('ERROR', $e->getTitle(), $e->getMessage()), 12); + } + } + if (!isset($_POST['importConfigConfirm']) && !$validUpload) { + $content->add(new htmlInputFileUpload('import-file'), 12); + $content->add(new htmlButton('importConfig', _('Submit')), 12); + } + elseif (isset($_POST['importConfig'])) { + $content->add(new htmlOutputText(_('Import steps')), 12); + foreach ($importSteps as $importStep) { + $content->add(new htmlResponsiveInputCheckbox('step_' . $importStep->getKey(), true, $importStep->getLabel()), 12); + } + $content->add(new htmlButton('importConfigConfirm', _('Import')), 12); + $content->add(new htmlButton('importCancel', _('Cancel')), 12); + } + elseif (isset($_POST['importConfigConfirm'])) { + $handle = fopen($_SESSION['configImportFile'], "r"); + $data = fread($handle, 100000000); + fclose($handle); + try { + $importer = new ConfigDataImporter(); + $importSteps = $importer->getPossibleImportSteps($data); + foreach ($importSteps as $importStep) { + $importStep->setActive(isset($_POST['step_' . $importStep->getKey()])); + } + $importer->runImport($importSteps); + unlink($_SESSION['configImportFile']); + $content->add(new htmlStatusMessage('INFO', _('Configuration import ended successful.')), 12); + } + catch (LAMException $e) { + $content->add(new htmlStatusMessage('ERROR', $e->getTitle(), $e->getMessage()), 12); + $content->add(new htmlButton('importCancel', _('Cancel')), 12); + } + } } ?> diff --git a/lam/tests/lib/LAMCfgMainTest.php b/lam/tests/lib/LAMCfgMainTest.php index 812c2a95..d622ddd2 100644 --- a/lam/tests/lib/LAMCfgMainTest.php +++ b/lam/tests/lib/LAMCfgMainTest.php @@ -146,6 +146,7 @@ class LAMCfgMainTest extends TestCase { $importData['sessionTimeout'] = 240; $importData['logLevel'] = LOG_ERR; $importData['mailServer'] = 'mailserver'; + $importData['allowedHosts'] = null; $importData['IGNORE_ME'] = 'ignore'; $this->conf->importData($importData); @@ -154,6 +155,7 @@ class LAMCfgMainTest extends TestCase { $this->assertEquals(240, $this->conf->sessionTimeout); $this->assertEquals(LOG_ERR, $this->conf->logLevel); $this->assertEquals('mailserver', $this->conf->mailServer); + $this->assertNull($this->conf->allowedHosts); } /** diff --git a/lam/tests/lib/persistenceTest.php b/lam/tests/lib/persistenceTest.php index 1e511569..a02e031d 100644 --- a/lam/tests/lib/persistenceTest.php +++ b/lam/tests/lib/persistenceTest.php @@ -37,7 +37,7 @@ class ConfigDataExporterTest extends TestCase { 'confMainKey2' => 4, 'confMainKey3' => '', ); - $expectedJson = json_encode(array('mainconfig' => $mainData)); + $expectedJson = json_encode(array('mainConfig' => $mainData)); $exporter = $this->getMockBuilder('\LAM\PERSISTENCE\ConfigDataExporter') ->setMethods(array('_getMainConfigData'))