partkeepr

fork of partkeepr
git clone https://git.e1e0.net/partkeepr.git
Log | Files | Refs | Submodules | README | LICENSE

commit aab9aee250cd62fb452110e2851197cd86409714
parent 51f392f570ded10d3b7c59c15e326ca4c2416437
Author: Felicitus <felicitus@felicitus.org>
Date:   Thu, 16 Feb 2012 05:41:45 +0100

Refactored the setup so that the user can choose if he likes to save or view the generated configuration file.

Also includes the following improvements to the setup:
- If decoding the response fails, display the raw response from the server for debugging
- Steps can now return a custom response

Diffstat:
Msrc/backend/de/RaumZeitLabor/PartKeepr/Setup/ConfigFileSetup.php | 69+++++++++++++++++++++++++++++++++++++++++++++++++++------------------
Msrc/backend/de/RaumZeitLabor/PartKeepr/Setup/Setup.php | 17++++++++++++-----
Msrc/setup/index.html | 8++++++++
Asrc/setup/js/Cards/ConfigDisplayCard.js | 77+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/setup/js/Cards/ConfigFileActionCard.js | 54++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/setup/js/Cards/ConfigFileModeCard.js | 91+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/setup/js/Cards/ConfigSaveCard.js | 121+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/setup/js/Cards/DatabaseSetupCard.js | 1-
Msrc/setup/js/SetupTests/AbstractTest.js | 11++++++++++-
Asrc/setup/js/SetupTests/ConfigSaveAction.js | 16++++++++++++++++
Msrc/setup/js/SetupWizard.js | 3+++
Msrc/setup/setup.php | 13+++++++++++--
12 files changed, 454 insertions(+), 27 deletions(-)

diff --git a/src/backend/de/RaumZeitLabor/PartKeepr/Setup/ConfigFileSetup.php b/src/backend/de/RaumZeitLabor/PartKeepr/Setup/ConfigFileSetup.php @@ -6,27 +6,60 @@ use de\RaumZeitLabor\PartKeepr\Util\Configuration, de\RaumZeitLabor\PartKeepr\Util\SerializableException; /** - * Creates a new config file + * Creates or returns a new config file */ class ConfigFileSetup extends AbstractSetup { + + /** + * (non-PHPdoc) + * @see de\RaumZeitLabor\PartKeepr\Setup.AbstractSetup::run() + */ public function run () { - $configFile = PartKeepr::getRootDirectory()."/config.php"; - if (file_exists($configFile)) { - if (!is_writable($configFile)) { - $message = "The config.php file could not be written, because it already exists and the webserver has "; - $message .= "no write access to it."; - - throw new SerializableException($message, 10000); - /*echo json_encode(array("error" => true, "errormessage" => )); - exit;*/ - } - } else { - if (!is_writable(PartKeepr::getRootDirectory())) { - $message = "The config.php file could not be written, because the webserver has no write access to it."; - - throw new SerializableException($message, 10001); - } + switch ($_REQUEST["mode"]) { + case "save": + $this->saveConfig(); + break; + case "display": + return $this->displayConfig(); + break; } - file_put_contents($configFile, Configuration::dumpConfig()); + + return null; + } + + /** + * Returns the configuration file as string, so that it can be displayed + * during setup. + * + * @param none + * @return array An array, where the "config" key contains the configuration. + */ + private function displayConfig () { + return array("config" => Configuration::dumpConfig()); + } + + /** + * Saves the configuration file. + * + * @throws SerializableException An exception which describes what has been going wrong + */ + private function saveConfig () { + $configFile = PartKeepr::getRootDirectory()."/config.php"; + + if (file_exists($configFile)) { + if (!is_writable($configFile)) { + $message = "The config.php file could not be written, because it already exists and the webserver has "; + $message .= "no write access to it."; + + throw new SerializableException($message, 10000); + } + } else { + if (!is_writable(PartKeepr::getRootDirectory())) { + $message = "The config.php file could not be written, because the webserver has no write access to it."; + + throw new SerializableException($message, 10001); + } + } + file_put_contents($configFile, Configuration::dumpConfig()); } } \ No newline at end of file diff --git a/src/backend/de/RaumZeitLabor/PartKeepr/Setup/Setup.php b/src/backend/de/RaumZeitLabor/PartKeepr/Setup/Setup.php @@ -37,7 +37,8 @@ class Setup { /** * Runs a specific setup step, or all steps. - * @param string $step + * + * @param string $step The step to execute * @throws \Exception */ public function runStep ($step) { @@ -53,10 +54,12 @@ class Setup { "unit" => new UnitSetup($entityManager), "manufacturer" => new ManufacturerSetup($entityManager), "schemamigration" => new SchemaMigrationSetup($entityManager), - "configfile" => new ConfigFileSetup($entityManager), "miscsettings" => new MiscSettingsSetup($entityManager) ); + $aActions = array( + "configfile" => new ConfigFileSetup($entityManager) + ); if ($step == "all") { foreach ($aSteps as $step) { $step->setConsole($this->console); @@ -64,10 +67,14 @@ class Setup { } } else { if (array_key_exists($step, $aSteps)) { - $aSteps[$step]->run(); - } else { - throw new \Exception(sprintf("Setup step %s doesn't exist", $step)); + return $aSteps[$step]->run(); } + + if (array_key_exists($step, $aActions)) { + return $aActions[$step]->run(); + } + + throw new \Exception(sprintf("Setup step %s doesn't exist", $step)); } } diff --git a/src/setup/index.html b/src/setup/index.html @@ -37,6 +37,11 @@ <script type="text/javascript" src="js/Cards/DatabaseParametersCard.PostgreSQL.js"></script> <script type="text/javascript" src="js/Cards/DatabaseConnectivityTestCard.js"></script> <script type="text/javascript" src="js/Cards/DatabaseSetupCard.js"></script> + <script type="text/javascript" src="js/Cards/ConfigFileModeCard.js"></script> + <script type="text/javascript" src="js/Cards/ConfigFileActionCard.js"></script> + <script type="text/javascript" src="js/Cards/ConfigSaveCard.js"></script> + <script type="text/javascript" src="js/Cards/ConfigDisplayCard.js"></script> + <script type="text/javascript" src="js/Cards/ConfigDownloadCard.js"></script> <script type="text/javascript" src="js/SetupTests/AbstractTest.js"></script> <script type="text/javascript" src="js/SetupTests/PHPTest.js"></script> @@ -46,6 +51,9 @@ <script type="text/javascript" src="js/SetupTests/PHPSettingsTest.js"></script> <script type="text/javascript" src="js/SetupTests/FilesystemPermissionTest.js"></script> + <script type="text/javascript" src="js/SetupTests/ConfigSaveAction.js"></script> + <script type="text/javascript" src="js/SetupTests/ConfigDownloadAction.js"></script> + <script type="text/javascript" src="js/SetupSteps/SchemaSetup.js"></script> <script type="text/javascript" src="js/SetupSteps/AdminUserSetup.js"></script> <script type="text/javascript" src="js/SetupSteps/ManufacturerSetup.js"></script> diff --git a/src/setup/js/Cards/ConfigDisplayCard.js b/src/setup/js/Cards/ConfigDisplayCard.js @@ -0,0 +1,77 @@ +/** + * This card tests the database connectivity for the MySQL database. + * + * Basically this submits all connection settings to a special PHP script, + * which then attempts to establish the database connection. + */ +Ext.define('PartKeeprSetup.ConfigDisplayCard', { + extend: 'Ext.panel.Panel', + + /** + * Misc style settings + */ + border: false, + bodyStyle: 'background: none;', + layout: { + type: 'vbox', + align : 'stretch', + pack : 'start', + }, + + /** + * Inits the component + */ + initComponent: function () { + + /** + * Creates a text area which displays the configuration file + */ + this.textArea = new Ext.form.field.TextArea({ + fieldStyle: "font-family: monospace;", + readOnly: true, + flex: 1, + anchor: '100%' + }); + + this.items = [ + { + xtype: 'displayfield', + value: "Copy and paste the contents into the config.php file, which needs to be placed " + + "in your PartKeepr's root directory." + }, + this.textArea + ]; + + this.callParent(); + + this.on("activateCard", this.onActivate, this); + }, + /** + * When the card is activated, automatically invoke all tests. + */ + onActivate: function () { + var params = Ext.getCmp("database-parameters-card").dbparams; + params.mode = "display"; + params.step = "configfile"; + + Ext.Ajax.request({ + url: "setup.php", + success: this.onConfigFileRetrieved, + scope: this, + params: params, + timeout: 120000 + }); + }, + /** + * Fills the text area with the config file. + * + * @param data The data as received from the AJAX call + */ + onConfigFileRetrieved: function (data) { + var obj = Ext.decode(data.responseText); + + this.textArea.setValue(obj.config); + + this.ownerCt.ownerCt.ownerCt.nextButton.setDisabled(false); + } +}); diff --git a/src/setup/js/Cards/ConfigFileActionCard.js b/src/setup/js/Cards/ConfigFileActionCard.js @@ -0,0 +1,53 @@ +/** + * This card executes the chosen configuration file mode. + */ +Ext.define('PartKeeprSetup.ConfigFileActionCard', { + extend: 'Ext.ux.wizard.Card', + + /** + * Various Style Settings + */ + title: 'Configuration File', + showTitle: true, + titleCls: '', + titleStyle: 'font-size: 2.5em;', + cls: 'x-partkeepr-setup-basecard', + id: 'config-action-card', + autoScroll: true, + mode: null, + layout: 'card', + + /** + * Inits the component + */ + initComponent: function () { + this.items = [ + this.createSaveCard(), + this.createDisplayCard() + ]; + + this.callParent(); + this.on("activate", this.onActivate, this); + }, + createSaveCard: function () { + return Ext.create("PartKeeprSetup.ConfigSaveCard", { + itemId: 'card-action-save' + }); + }, + createDisplayCard: function () { + return Ext.create("PartKeeprSetup.ConfigDisplayCard", { + itemId: 'card-action-display' + }); + }, + /** + * Gets called when the card is activated + */ + onActivate: function () { + console.log("Activating "+ Ext.getCmp("config-mode-card").mode); + + this.getLayout().setActiveItem('card-action-' + Ext.getCmp("config-mode-card").mode); + this.getLayout().activeItem.fireEvent("activateCard"); + // Disable the "next" button, this needs to get enabled by the database cards + this.ownerCt.ownerCt.nextButton.setDisabled(true); + } +});+ \ No newline at end of file diff --git a/src/setup/js/Cards/ConfigFileModeCard.js b/src/setup/js/Cards/ConfigFileModeCard.js @@ -0,0 +1,90 @@ +/** + * This card manages the config file creation. + */ +Ext.define('PartKeeprSetup.ConfigFileModeCard', { + extend: 'Ext.ux.wizard.Card', + + /** + * Various Style Settings + */ + title: 'Configuration File', + showTitle: true, + titleCls: '', + titleStyle: 'font-size: 2.5em;', + cls: 'x-partkeepr-setup-basecard', + id: 'config-mode-card', + autoScroll: true, + mode: null, + + /** + * Inits the component + */ + initComponent: function () { + + this.saveOption = Ext.create("Ext.form.field.Radio", { + name: 'configfilemode', + inputValue: 'save', + boxLabel: 'Save', + listeners: { + scope: this, + change: this.setConfigFileMode + } + }); + + this.displayOption = Ext.create("Ext.form.field.Radio", { + name: 'configfilemode', + inputValue: 'display', + boxLabel: 'Display', + listeners: { + scope: this, + change: this.setConfigFileMode + } + }); + + this.items = [{ + xtype: 'displayfield', + value: 'PartKeepr needs a configuration file to operate. Please choose how to proceed:', + style: 'margin-bottom: 20px;' + }, + this.saveOption, + { + xtype: 'displayfield', + value: 'Attempts to save the configuration file. The configuration file may not exist, and it must be' + + 'writable by your web server.', + style: 'margin-left: 17px; margin-bottom: 5px;' + + }, + this.displayOption, + { + xtype: 'displayfield', + value: 'Displays the configuration file, so you can use copy and paste.', + style: 'margin-left: 17px; margin-bottom: 5px;' + }]; + + this.callParent(); + this.on("activate", this.onActivate, this); + }, + setConfigFileMode: function () { + if (this.saveOption.getValue()) { + this.mode = "save"; + } + + if (this.displayOption.getValue()) { + this.mode = "display"; + } + + this.ownerCt.ownerCt.nextButton.setDisabled(false); + }, + /** + * Gets called when the card is activated + */ + onActivate: function () { + // Disable the "next" button, this needs to get enabled by the database cards + if (this.saveOption.getValue() || this.displayOption.getValue()) { + this.ownerCt.ownerCt.nextButton.setDisabled(false); + } else { + this.ownerCt.ownerCt.nextButton.setDisabled(true); + } + + } +});+ \ No newline at end of file diff --git a/src/setup/js/Cards/ConfigSaveCard.js b/src/setup/js/Cards/ConfigSaveCard.js @@ -0,0 +1,121 @@ +/** + * This card attempts to save the configuration file. + * + */ +Ext.define('PartKeeprSetup.ConfigSaveCard', { + extend: 'Ext.panel.Panel', + + /** + * Contains the test results for this card + * @var PartKeeprSetup.TestResultPanel + */ + testResultPanel: null, + + /** + * Contains the initially hidden "Re-test" button to re-trigger the tests. + */ + retestButton: null, + + /** + * Contains the test which will be run + * @var array + */ + tests: null, + + border: false, + + bodyStyle: 'background: none;', + + rerunTestText: "Retry", + + /** + * Inits the component + */ + initComponent: function () { + this.testResultPanel = Ext.create("PartKeeprSetup.TestResultPanel", { + + }); + + this.testResultPanel.on("test-error", this.onTestError, this); + + this.retestButton = Ext.create("Ext.button.Button", { + text: this.rerunTestText, + hidden: true + }); + + this.retestButton.on("click", this.retest, this); + + this.items = [{ + border: false, + bodyStyle: 'background:none;padding-bottom: 10px;', + html: this.cardMessage + }, + this.testResultPanel, + this.retestButton ]; + + this.tests = new Array(); + + this.testRunner = Ext.create("PartKeeprSetup.TestRunner"); + this.testRunner.on("success", this.onTestSuccessful, this); + + this.setupTests(); + this.callParent(); + this.on("activateCard", this.onActivate, this); + }, + /** + * Re-runs the configured tests and hides the Re-test button, + * because we don't know if the tests will be successful. + */ + retest: function () { + this.retestButton.hide(); + this.runTests(); + }, + /** + * Called when an error occurs. Shows the "re-test" button + * and disables the "next" button. + */ + onTestError: function () { + this.retestButton.show(); + this.ownerCt.ownerCt.ownerCt.nextButton.setDisabled(true); + }, + /** + * Called when all tests are successful. Hides the "re-test" + * button and enables the "next" button. + */ + onTestSuccessful: function () { + this.retestButton.hide(); + this.ownerCt.ownerCt.ownerCt.nextButton.setDisabled(false); + }, + /** + * Invokes the test runner with all configured tests + */ + runTests: function () { + this.testResultPanel.clear(); + + // We need to clone the test array, because we wouldn't be able to run all tests twice + var clonedTests = this.tests.slice(0); + this.testRunner.run(clonedTests, this.testResultPanel); + + }, + /** + * When the card is activated, automatically invoke all tests. + */ + onActivate: function () { + this.ownerCt.ownerCt.ownerCt.nextButton.setDisabled(true); + this.retestButton.hide(); + + this.runTests(); + }, + /** + * This method needs to be overridden by subclasses. Subclasses + * need to append tests to the "tests" array, e.g. + * + * var j = Ext.create("PartKeeprSetup.FilesystemPermissionTest"); + * j.callback = this.testResultPanel; + * this.tests.push(j); + * + */ + setupTests: function () { + this.tests.push(new PartKeeprSetup.ConfigSaveAction()); + } +}); diff --git a/src/setup/js/Cards/DatabaseSetupCard.js b/src/setup/js/Cards/DatabaseSetupCard.js @@ -24,6 +24,5 @@ Ext.define('PartKeeprSetup.DatabaseSetupCard', { this.tests.push(new PartKeeprSetup.ManufacturerSetup()); this.tests.push(new PartKeeprSetup.SchemaMigrationSetup()); this.tests.push(new PartKeeprSetup.MiscSetup()); - this.tests.push(new PartKeeprSetup.ConfigFileSetup()); } }); diff --git a/src/setup/js/SetupTests/AbstractTest.js b/src/setup/js/SetupTests/AbstractTest.js @@ -69,7 +69,16 @@ Ext.define('PartKeeprSetup.AbstractTest', { * @param response */ onSuccess: function (response) { - var obj = Ext.decode(response.responseText); + var obj; + + try { + obj = Ext.decode(response.responseText); + } catch (exception) { + obj = {}; + obj.error = true; + obj.message = "Invalid Response from server: "+response.responseText; + } + if (obj.error === false) { this.success = true; diff --git a/src/setup/js/SetupTests/ConfigSaveAction.js b/src/setup/js/SetupTests/ConfigSaveAction.js @@ -0,0 +1,15 @@ +/** + * Attempts to save the configuration file + */ +Ext.define('PartKeeprSetup.ConfigSaveAction', { + extend: 'PartKeeprSetup.AbstractTest', + url: 'setup.php', + name: "Config File", + message: "Saving the configuration file", + + onBeforeRunTest: function () { + this.params = Ext.getCmp("database-parameters-card").dbparams; + this.params.mode = "save"; + this.params.step = "configfile"; + } +});+ \ No newline at end of file diff --git a/src/setup/js/SetupWizard.js b/src/setup/js/SetupWizard.js @@ -76,6 +76,9 @@ Ext.define('PartKeeprSetup.SetupWizard', { cards.push(Ext.create("PartKeeprSetup.DatabaseConnectivityTestCard")); cards.push(Ext.create("PartKeeprSetup.DatabaseSetupCard")); + cards.push(Ext.create("PartKeeprSetup.ConfigFileModeCard")); + cards.push(Ext.create("PartKeeprSetup.ConfigFileActionCard")); + cards.push(Ext.create('Ext.ux.wizard.Card', { title: 'Cron Setup', showTitle: true, diff --git a/src/setup/setup.php b/src/setup/setup.php @@ -29,8 +29,17 @@ try { if ($_REQUEST["step"] == "footprint") { @set_time_limit(0); } - $setup->runStep($_REQUEST["step"]); - echo json_encode(array("error" => false)); + $result = $setup->runStep($_REQUEST["step"]); + + //var_dump($result); + + if ($result !== null) { + $aResult = array_merge($result, array("error" => false)); + echo json_encode($aResult); + } else { + echo json_encode(array("error" => false)); + } + } catch (SerializableException $e) { $error = $e->serialize(); $error["error"] = true;