From d240b14a9e51cc59f2b988344fe2a79404f9b298 Mon Sep 17 00:00:00 2001 From: Unknown Date: Fri, 16 Mar 2018 20:40:04 +0100 Subject: [PATCH] Implemented backup preview --- .../api/module/departement/saveController.php | 94 ------------------- .../api/module/department/saveController.php | 50 +++++++++- build/database/repo/cours.php | 2 +- build/database/repo/department.php | 30 +++++- build/database/repo/td.php | 2 +- build/database/repo/tp.php | 2 +- composer.lock | 54 +++++------ config/modules.json | 10 +- 8 files changed, 112 insertions(+), 132 deletions(-) delete mode 100644 build/api/module/departement/saveController.php diff --git a/build/api/module/departement/saveController.php b/build/api/module/departement/saveController.php deleted file mode 100644 index 05175aa..0000000 --- a/build/api/module/departement/saveController.php +++ /dev/null @@ -1,94 +0,0 @@ -backupPath =__BACKUP__."/$dbName/"; - } - - private function scandir(string $path) : array { - //scan the directory - $arr = scandir($path); - - //strip the useless "." and ".." - unset($arr[0],$arr[1]); - - //make the arry start at 0 again - $arr = array_values($arr); - - return $arr; - } - - public function get($args){ - $this->initDir($_SESSION["CurrentDatabase"]); - - //strip extensions - $backupNames = array_map(function($e){ - return pathinfo($e, PATHINFO_FILENAME); - }, $this->scandir($this->backupPath)); - - return ["data" => $backupNames]; - } - - public function post($args){ - $this->initDir($_SESSION["CurrentDatabase"]); - - $backupName = ""; - extract($args); - - //if the backup name is empty we create it - if($backupName == ""){ - try { - $conf = Repo::getDBConfig(); - - $dump = new Mysqldump("mysql:host={$conf["host"]};dbname={$conf["dbname"]}", $conf["username"], $conf["password"], - [ - "compress" => Mysqldump::GZIP - ]); - - $date = date("Y-W-d"); - - $dump->start($this->backupPath.$date.".sql"); - - return ["success" => true,"backupName" => $date]; - - } catch (\Exception $e) { - return ["success" => false]; - } - }else{ - //read the backup - ob_start(); - readgzfile($this->backupPath.$backupName.".sql"); - $sql = ob_get_clean(); - - /** @var departement $depRepo */ - $depRepo = Repo::getRepo("departement"); - - $depRepo->restore($sql); - - return ["success" => true]; - } - } - -} \ No newline at end of file diff --git a/build/api/module/department/saveController.php b/build/api/module/department/saveController.php index e48ecb3..13f5ec1 100644 --- a/build/api/module/department/saveController.php +++ b/build/api/module/department/saveController.php @@ -17,9 +17,21 @@ class saveController { private $backupPath = ""; + private $originDBName = ""; private function initDir(string $dbName){ + //match preview_DATABASENAME_sha1 in order to determine if we init the directory or not + $matches = []; + $reg = preg_match("/preview_(\w*)_\w*/",$dbName,$matches); + + //if the dbname match we store the original database name + if($reg == 1){ + $dbName = $matches[1]; + } + + $this->originDBName = $dbName; + if(!is_dir(__BACKUP__."/$dbName/")){ mkdir(__BACKUP__."/$dbName/"); } @@ -51,10 +63,21 @@ class saveController return ["data" => $backupNames]; } + public function delete($args){ + $this->initDir($_SESSION["CurrentDatabase"]); + + $backupName = ""; + + extract($args); + + return ["success" => unlink($this->backupPath.$backupName.".sql")]; + } + public function post($args){ $this->initDir($_SESSION["CurrentDatabase"]); $backupName = ""; + $apply = false; extract($args); //if the backup name is empty we create it @@ -85,9 +108,32 @@ class saveController /** @var department $depRepo */ $depRepo = Repo::getRepo("department"); - $depRepo->restore($sql); + if($sql == "") return ["success" => false]; + + if($apply){ + + $depRepo->restore($this->originDBName,$sql); + + return ["success" => true]; + }else{ + + if($backupName == "origin"){ + $_SESSION['CurrentDatabase'] = $this->originDBName; + return ["success" => true]; + } + + $previewDBName = $depRepo->previewExists($this->originDBName,$backupName); + + if($previewDBName == null){ + $previewDBName = $depRepo->createPreview($this->originDBName,$backupName); + $depRepo->restore($previewDBName,$sql); + } + + $_SESSION['CurrentDatabase'] = $previewDBName; + } + + return ["success" => true, "currentDatabase" => $_SESSION['CurrentDatabase']]; - return ["success" => true]; } } diff --git a/build/database/repo/cours.php b/build/database/repo/cours.php index f05607a..509b115 100644 --- a/build/database/repo/cours.php +++ b/build/database/repo/cours.php @@ -24,7 +24,7 @@ class cours extends Repo_i { * @return created_id UID of the created Cours (NULL on error) * ---------------------------------------------------------*/ - public function create(string $code, ?int $idProf, float $volume, array $formations) : int{ + public function create(string $code, ?int $idProf, float $volume, array $formations) : ?int{ /* (1) Prepare statement */ $st = $this->pdo->prepare('INSERT INTO Cours(UE_code, Professeur_idProfesseur, volume) diff --git a/build/database/repo/department.php b/build/database/repo/department.php index 603faa2..17d0687 100644 --- a/build/database/repo/department.php +++ b/build/database/repo/department.php @@ -167,14 +167,36 @@ class department extends Repo_i } - public function restore(string $SQL) : bool{ + public function restore(string $dbName, string $SQL) : bool{ //get the list of command to execute - $this->pdo->exec("DROP DATABASE ".$_SESSION['CurrentDatabase'].";"); - $this->pdo->exec("CREATE DATABASE ".$_SESSION['CurrentDatabase'].";"); - $this->pdo->exec("USE ".$_SESSION['CurrentDatabase'].";"); + $this->pdo->exec("DROP DATABASE $dbName;"); + $this->pdo->exec("CREATE DATABASE $dbName;"); + $this->pdo->exec("USE $dbName;"); return $this->pdo->exec($SQL); } + private static function generatePreviewDBName(string $bdName, string $backupName) : string{ + return "preview_{$bdName}_".sha1($bdName.$backupName); + } + + public function previewExists(string $dbName, string $backupname) : ?string { + $previewDBName = static::generatePreviewDBName($dbName,$backupname); + + $st = $this->pdo->prepare("SELECT SCHEMA_NAME FROM INFORMATION_SCHEMA.SCHEMATA WHERE SCHEMA_NAME = :dbName"); + $st->execute(["dbName" => $previewDBName]); + + if($st->fetch() === false) return null; + else return $previewDBName; + } + + public function createPreview(string $dbName, string $backupname) : string { + $previewDBName = static::generatePreviewDBName($dbName,$backupname); + + $this->pdo->exec("CREATE OR REPLACE DATABASE $previewDBName"); + + return $previewDBName; + } + } \ No newline at end of file diff --git a/build/database/repo/td.php b/build/database/repo/td.php index 0104294..2d8a086 100644 --- a/build/database/repo/td.php +++ b/build/database/repo/td.php @@ -24,7 +24,7 @@ class td extends Repo_i { * @return created_id UID of the created TD (NULL on error) * ---------------------------------------------------------*/ - public function create(string $code, ?int $idProf, float $volume, array $formations) : int{ + public function create(string $code, ?int $idProf, float $volume, array $formations) : ?int{ /* (1) Prepare statement */ $st = $this->pdo->prepare('INSERT INTO TD(UE_code, Professeur_idProfesseur, volume) diff --git a/build/database/repo/tp.php b/build/database/repo/tp.php index 1e9ad18..659434f 100644 --- a/build/database/repo/tp.php +++ b/build/database/repo/tp.php @@ -24,7 +24,7 @@ class tp extends Repo_i { * @return created_id UID of the created TP (NULL on error) * ---------------------------------------------------------*/ - public function create(string $code, ?int $idProf, float $volume, array $formations) : int{ + public function create(string $code, ?int $idProf, float $volume, array $formations) : ?int{ /* (1) Prepare statement */ $st = $this->pdo->prepare('INSERT INTO TP(UE_code, Professeur_idProfesseur, volume) diff --git a/composer.lock b/composer.lock index af1c277..fb9984d 100644 --- a/composer.lock +++ b/composer.lock @@ -575,16 +575,16 @@ }, { "name": "nikic/php-parser", - "version": "v3.1.4", + "version": "v3.1.5", "source": { "type": "git", "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "e57b3a09784f846411aa7ed664eedb73e3399078" + "reference": "bb87e28e7d7b8d9a7fda231d37457c9210faf6ce" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/e57b3a09784f846411aa7ed664eedb73e3399078", - "reference": "e57b3a09784f846411aa7ed664eedb73e3399078", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/bb87e28e7d7b8d9a7fda231d37457c9210faf6ce", + "reference": "bb87e28e7d7b8d9a7fda231d37457c9210faf6ce", "shasum": "" }, "require": { @@ -622,7 +622,7 @@ "parser", "php" ], - "time": "2018-01-25T21:31:33+00:00" + "time": "2018-02-28T20:30:58+00:00" }, { "name": "ocramius/package-versions", @@ -675,16 +675,16 @@ }, { "name": "phpoffice/phpspreadsheet", - "version": "1.1.0", + "version": "1.2.0", "source": { "type": "git", "url": "https://github.com/PHPOffice/PhpSpreadsheet.git", - "reference": "a2771e562e3a17c0d512d2009e38fd628beece90" + "reference": "8380fb3ad28242093c18d0baa9b7e67fb429ea84" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/PHPOffice/PhpSpreadsheet/zipball/a2771e562e3a17c0d512d2009e38fd628beece90", - "reference": "a2771e562e3a17c0d512d2009e38fd628beece90", + "url": "https://api.github.com/repos/PHPOffice/PhpSpreadsheet/zipball/8380fb3ad28242093c18d0baa9b7e67fb429ea84", + "reference": "8380fb3ad28242093c18d0baa9b7e67fb429ea84", "shasum": "" }, "require": { @@ -714,8 +714,6 @@ }, "suggest": { "dompdf/dompdf": "Option for rendering PDF with PDF Writer", - "ext-dom": "Option to read and write HTML files", - "ext-gd": "Required for exact column width autocalculation", "jpgraph/jpgraph": "Option for rendering charts, or including charts with PDF or HTML Writers", "mpdf/mpdf": "Option for rendering PDF with PDF Writer", "tecnick.com/tcpdf": "Option for rendering PDF with PDF Writer" @@ -728,7 +726,7 @@ }, "notification-url": "https://packagist.org/downloads/", "license": [ - "LGPL-2.1" + "LGPL-2.1-or-later" ], "authors": [ { @@ -759,7 +757,7 @@ "xls", "xlsx" ], - "time": "2018-01-28T12:37:15+00:00" + "time": "2018-03-04T20:41:15+00:00" }, { "name": "phpstan/phpdoc-parser", @@ -871,16 +869,16 @@ }, { "name": "psr/simple-cache", - "version": "1.0.0", + "version": "1.0.1", "source": { "type": "git", "url": "https://github.com/php-fig/simple-cache.git", - "reference": "753fa598e8f3b9966c886fe13f370baa45ef0e24" + "reference": "408d5eafb83c57f6365a3ca330ff23aa4a5fa39b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-fig/simple-cache/zipball/753fa598e8f3b9966c886fe13f370baa45ef0e24", - "reference": "753fa598e8f3b9966c886fe13f370baa45ef0e24", + "url": "https://api.github.com/repos/php-fig/simple-cache/zipball/408d5eafb83c57f6365a3ca330ff23aa4a5fa39b", + "reference": "408d5eafb83c57f6365a3ca330ff23aa4a5fa39b", "shasum": "" }, "require": { @@ -915,20 +913,20 @@ "psr-16", "simple-cache" ], - "time": "2017-01-02T13:31:39+00:00" + "time": "2017-10-23T01:57:42+00:00" }, { "name": "symfony/console", - "version": "v4.0.4", + "version": "v4.0.6", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "36d5b41e7d4e1ccf0370f6babe966c08ef0a1488" + "reference": "555c8dbe0ae9e561740451eabdbed2cc554b6a51" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/36d5b41e7d4e1ccf0370f6babe966c08ef0a1488", - "reference": "36d5b41e7d4e1ccf0370f6babe966c08ef0a1488", + "url": "https://api.github.com/repos/symfony/console/zipball/555c8dbe0ae9e561740451eabdbed2cc554b6a51", + "reference": "555c8dbe0ae9e561740451eabdbed2cc554b6a51", "shasum": "" }, "require": { @@ -983,20 +981,20 @@ ], "description": "Symfony Console Component", "homepage": "https://symfony.com", - "time": "2018-01-29T09:06:29+00:00" + "time": "2018-02-26T15:55:47+00:00" }, { "name": "symfony/finder", - "version": "v4.0.4", + "version": "v4.0.6", "source": { "type": "git", "url": "https://github.com/symfony/finder.git", - "reference": "8b08180f2b7ccb41062366b9ad91fbc4f1af8601" + "reference": "44a796d2ecc2a16a5fc8f2956a34ee617934d55f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/8b08180f2b7ccb41062366b9ad91fbc4f1af8601", - "reference": "8b08180f2b7ccb41062366b9ad91fbc4f1af8601", + "url": "https://api.github.com/repos/symfony/finder/zipball/44a796d2ecc2a16a5fc8f2956a34ee617934d55f", + "reference": "44a796d2ecc2a16a5fc8f2956a34ee617934d55f", "shasum": "" }, "require": { @@ -1032,7 +1030,7 @@ ], "description": "Symfony Finder Component", "homepage": "https://symfony.com", - "time": "2018-01-03T07:38:00+00:00" + "time": "2018-03-05T18:28:26+00:00" }, { "name": "symfony/polyfill-mbstring", diff --git a/config/modules.json b/config/modules.json index 248ad2e..f4c8271 100644 --- a/config/modules.json +++ b/config/modules.json @@ -109,7 +109,15 @@ "des": "Create a backup if the name is empty, execute the backup if the name is set", "per": [], "par": { - "backupName": {"des": "Backup name", "typ": "varchar(10,10,alphanumeric)", "opt" : true} + "backupName" : {"des": "Backup name", "typ": "varchar(1,10,alphanumeric)", "opt" : true}, + "apply" : {"des": "Should we apply the backup on production or just preview it (true : apply, false : preview)", "typ": "boolean", "opt" : true} + } + }, + "DELETE": { + "des": "Delete a backup", + "per": [], + "par": { + "backupName": {"des": "Backup name", "typ": "varchar(1,10,alphanumeric)"} } } }