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:
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;