Skip to content

Commit

Permalink
Version 0.2.0
Browse files Browse the repository at this point in the history
Add database updater with automatic backup
Add getter for distribution configuration
Enhance error handling
  • Loading branch information
nioc committed Nov 10, 2018
1 parent 547da0a commit f464acf
Show file tree
Hide file tree
Showing 7 changed files with 173 additions and 23 deletions.
25 changes: 12 additions & 13 deletions money-front-vue/src/components/Setup.vue
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
</li>
</ul>

<div v-else class="content has-text-grey has-text-centered">All is fine</div>
<div v-else class="content has-text-grey has-text-centered">There is nothing to do</div>

<form @submit.prevent="validateBeforeSubmit" novalidate class="section is-max-width-form" v-if="steps.length > 0">
<div v-if="steps[currentStep].help" v-html="steps[currentStep].help" class="content has-text-grey has-text-centered"/>
Expand All @@ -40,23 +40,22 @@
</div>
</div>

<div class="field is-horizontal">
<div class="field-label is-normal">
</div>
<div class="field-body">
<div class="message is-danger" v-if="error">
<div class="message-body">
{{ error }}
</div>
</div>
</div>
</div>

<div class="has-text-centered" v-if="currentStep < steps.length-1">
<button class="button is-primary" :disabled="errors.any()"><span class="icon"><i class="fa fa-arrow-circle-right"/></span><span>Next</span></button>
</div>

</form>

<div class="is-centered columns" v-if="error">
<div class="column is-narrow">
<div class="message is-danger">
<div class="message-body">
{{ error }}
</div>
</div>
</div>
</div>

<b-loading :is-full-page="false" :active.sync="isLoading"></b-loading>
</div>
</div>
Expand Down
5 changes: 5 additions & 0 deletions server/api/steps.php
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,11 @@
case 'GET':
//query steps
$steps = Step::getAll();
if (is_string($steps)) {
$api->output(500, $steps);
//return steps list
return;
}
$api->output(200, $steps);
//return steps list
return;
Expand Down
32 changes: 32 additions & 0 deletions server/configuration/alter-database-0.2.0.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
DROP TABLE IF EXISTS `pattern`;
CREATE TABLE `pattern` (
`user` smallint(3) UNSIGNED NOT NULL,
`id` mediumint(8) UNSIGNED NOT NULL,
`label` varchar(200) NOT NULL,
`category` smallint(3) UNSIGNED DEFAULT NULL,
`subcategory` smallint(3) UNSIGNED DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

DROP TABLE IF EXISTS `version`;
CREATE TABLE `version` (
`version` varchar(12) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

ALTER TABLE `pattern`
ADD PRIMARY KEY (`user`,`id`),
ADD KEY `id` (`id`),
ADD KEY `fk_pattern_category_1` (`category`),
ADD KEY `fk_pattern_subcategory_1` (`subcategory`);

ALTER TABLE `version`
ADD PRIMARY KEY (`version`);

ALTER TABLE `pattern`
MODIFY `id` mediumint(8) UNSIGNED NOT NULL AUTO_INCREMENT;

ALTER TABLE `pattern`
ADD CONSTRAINT `fk_pattern_category_1` FOREIGN KEY (`category`) REFERENCES `category` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
ADD CONSTRAINT `fk_pattern_subcategory_1` FOREIGN KEY (`subcategory`) REFERENCES `category` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
ADD CONSTRAINT `fk_pattern_user_1` FOREIGN KEY (`user`) REFERENCES `user` (`id`) ON DELETE CASCADE ON UPDATE CASCADE;

INSERT INTO `version` (`version`) VALUES ('0.2.0');
2 changes: 1 addition & 1 deletion server/configuration/configuration.ini
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

[system]
; OwnMyMoney version
version = 0.1.0
version = 0.2.0
; installation status
setup = 0

Expand Down
10 changes: 10 additions & 0 deletions server/configuration/create-database.sql
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,11 @@ CREATE TABLE `user` (
`lastLoginAttemptFailed` int(11) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

DROP TABLE IF EXISTS `version`;
CREATE TABLE `version` (
`version` varchar(12) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;


ALTER TABLE `account`
ADD PRIMARY KEY (`id`),
Expand Down Expand Up @@ -114,6 +119,9 @@ ALTER TABLE `user`
ADD PRIMARY KEY (`id`),
ADD UNIQUE KEY `login` (`login`);

ALTER TABLE `version`
ADD PRIMARY KEY (`version`);


ALTER TABLE `account`
MODIFY `id` int(11) NOT NULL AUTO_INCREMENT;
Expand Down Expand Up @@ -147,3 +155,5 @@ ALTER TABLE `transaction`
ADD CONSTRAINT `account id` FOREIGN KEY (`aid`) REFERENCES `account` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
ADD CONSTRAINT `category` FOREIGN KEY (`category`) REFERENCES `category` (`id`) ON UPDATE CASCADE,
ADD CONSTRAINT `subcategory` FOREIGN KEY (`subcategory`) REFERENCES `category` (`id`) ON UPDATE CASCADE;

INSERT INTO `version` (`version`) VALUES ('0.2.0');
15 changes: 7 additions & 8 deletions server/lib/Configuration.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,17 +14,20 @@ class Configuration
*/
private $configuration;

public function __construct()
public function __construct($includeLocal = true)
{
$confDist = array();
$confLocal = array();
//get original configuration
if (is_file($_SERVER['DOCUMENT_ROOT'].'/server/configuration/configuration.ini')) {
$confDist = parse_ini_file($_SERVER['DOCUMENT_ROOT'].'/server/configuration/configuration.ini');
}
//get local configuration
if (is_file($_SERVER['DOCUMENT_ROOT'].'/server/configuration/local.ini')) {
$confLocal = parse_ini_file($_SERVER['DOCUMENT_ROOT'].'/server/configuration/local.ini');
$confLocal = [];
if ($includeLocal) {
//get local configuration
if (is_file($_SERVER['DOCUMENT_ROOT'].'/server/configuration/local.ini')) {
$confLocal = parse_ini_file($_SERVER['DOCUMENT_ROOT'].'/server/configuration/local.ini');
}
}
//merge configurations (local override original)
$this->configuration = array_merge($confDist, $confLocal);
Expand Down Expand Up @@ -79,10 +82,6 @@ public function set($key, $value)
//unknown key
return false;
}
if ($oldValue === $value) {
//no change
return true;
}
$path = $_SERVER['DOCUMENT_ROOT'].'/server/configuration/local.ini';
$localConfiguration = file_get_contents($path);
if (!$localConfiguration) {
Expand Down
107 changes: 106 additions & 1 deletion server/lib/Step.php
Original file line number Diff line number Diff line change
Expand Up @@ -77,9 +77,22 @@ public static function getAll()
require_once $_SERVER['DOCUMENT_ROOT'].'/server/lib/Configuration.php';
$configuration = new Configuration();
if ($configuration->get('setup') === '1') {
//setup is already done, return no step for installation
//initial setup is already done, check updates
$distConfiguration = new Configuration(false);
$installedVersion = $configuration->get('version');
$distVersion = $distConfiguration->get('version');
if ($installedVersion !== $distVersion) {
//there are update to do
return Step::getUpdateSteps($installedVersion);
}
//nothing to do, return no step
return [];
}
return Step::getInstallationSteps();
}

private static function getInstallationSteps()
{
//check database exists
$databaseConfigured = true;
try {
Expand All @@ -95,11 +108,40 @@ public static function getAll()
new Step('set-mailer', 'Setup mailer', 'fa-envelope', 'The application can send emails if your host has a SMTP server, in this step we configure the mail system', $databaseConfigured ? true : false),
new Step('set-security', 'Setup security', 'fa-lock', 'Authorization process uses signed JWT, it requires you set your own secret key for generating the HMAC', false),
new Step('create-user', 'Create user', 'fa-user', 'This step will create your (super) user account', false),
new Step('finalize-setup', 'Finalize setup', 'fa-cogs', 'This step will complete your setup', false),
new Step('confirmation', 'Confirmation', 'fa-check', 'That\'s all, installation process has been completed, you can now <a href="/">signin</a> into the application', false)
];
return $steps;
}

private static function getUpdateSteps($installedVersion)
{
$hasDatabaseAlter = false;
switch ($installedVersion) {
//check if there is some database change
case '0.1.0':
$hasDatabaseAlter = true;
break;
default:
return 'Unknown installed version';
break;
}
$steps = [];
if ($hasDatabaseAlter) {
array_push(
$steps,
new Step('backup-database', 'Create backup', 'fa-life-ring', 'Your data matters, application will create a local backup of your database', false),
new Step('update-database', 'Update database', 'fa-table', 'Now, application will update MySQL tables', false)
);
}
array_push(
$steps,
new Step('finalize-setup', 'Finalize update', 'fa-cogs', 'This step will complete this update', false),
new Step('confirmation', 'Confirmation', 'fa-check', 'That\'s all, update process has been completed, you can now go back to the <a href="/">home</a> and discover the new features', false)
);
return $steps;
}

/**
* Return the requested step field value
*
Expand Down Expand Up @@ -167,6 +209,9 @@ private function getFields()
];
break;

case 'backup-database':
case 'update-database':
case 'finalize-setup':
case 'confirmation':
$this->fields = [
];
Expand Down Expand Up @@ -315,6 +360,66 @@ public function process($fields)
if (!$user->insert($error)) {
return 'Error during user creation'.$error;
}
return true;
break;

case 'backup-database':
$filename = $_SERVER['DOCUMENT_ROOT'].'/money-db-backup-'.time().'.sql';
$dbName = $configuration->get('dbName');
$dbUser = $configuration->get('dbUser');
$dbPwd = $configuration->get('dbPwd');
exec("mysqldump $dbName --password=$dbPwd --user=$dbUser --single-transaction >$filename", $output);
if (!file_exists($filename) || filesize($filename) === 0) {
return 'Error during backup creation'.join(' ', $output);
}
return true;
break;

case 'update-database':
//connect to MySQL with application credentials
try {
require_once $_SERVER['DOCUMENT_ROOT'].'/server/lib/DatabaseConnection.php';
$connection = new DatabaseConnection();
} catch (PDOException $e) {
return $e->getMessage();
}
//alter existing tables and create new ones according to the installed version
$installedVersion = $configuration->get('version');
switch ($installedVersion) {
case '0.1.0':
$sql = file_get_contents($_SERVER['DOCUMENT_ROOT'].'/server/configuration/alter-database-0.2.0.sql');
$connection->exec($sql);

//cumulative scripts, break will be shared
break;
default:
break;
}
//check the database has expected version
$query = $connection->prepare('SELECT `version` FROM `version`;');
if ($query->execute()) {
$distConfiguration = new Configuration(false);
if (!$distVersion = $distConfiguration->get('version')) {
return 'Failed to get configuration `version`';
}
$databaseVersion = $query->fetchColumn();
if ($distVersion === $databaseVersion) {
return true;
}
return "Error during database update (current $databaseVersion ≠ target $distVersion)";
}
return 'Error during database update (can not read database version)';
break;

case 'finalize-setup':
//set the version installed
$distConfiguration = new Configuration(false);
if (!$version = $distConfiguration->get('version')) {
return 'Failed to get configuration `version`';
}
if (!$configuration->set('version', $version)) {
return 'Failed to set configuration `version`';
}
//set the installation steps are completed
if (!$configuration->set('setup', '1')) {
return 'Failed to set configuration `setup`';
Expand Down

0 comments on commit f464acf

Please sign in to comment.