diff --git a/build/api/module/department/saveController.php b/build/api/module/department/saveController.php deleted file mode 100644 index 13f5ec1..0000000 --- a/build/api/module/department/saveController.php +++ /dev/null @@ -1,140 +0,0 @@ -originDBName = $dbName; - - if(!is_dir(__BACKUP__."/$dbName/")){ - mkdir(__BACKUP__."/$dbName/"); - } - - $this->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 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 - 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 department $depRepo */ - $depRepo = Repo::getRepo("department"); - - 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']]; - - } - } - -} \ No newline at end of file diff --git a/build/api/module/department/versionController.php b/build/api/module/department/versionController.php new file mode 100644 index 0000000..0a2d063 --- /dev/null +++ b/build/api/module/department/versionController.php @@ -0,0 +1,296 @@ +backup_path = null; + $this->origin_dbname = null; + } + + + + + + /* (2) Initializes a directory + * + * @db_name The database name + * + * @return outName outDesc + * + --------------------------------------------------------*/ + private function initDir(string $db_name){ + + /* (1) Manage 'BACKUP' root directory + ---------------------------------------------------------*/ + /* (1) If not exists -> try to create it */ + if( !is_dir(__BACKUP__) ) + mkdir(__BACKUP__); + + /* (2) Try to override permissions */ + chmod(__BACKUP__, 0775); + + + + /* (2) Manage sub-directory + ---------------------------------------------------------*/ + /* (1) If @db_name is 'preview_@database_hash' -> extract @database */ + if( preg_match('/^preview_(\w+)_[a-f0-9]+$/', $db_name, $m) ) + $db_name = $m[1]; + + /* (2) Store @db_name as origin */ + $this->origin_dbname = $db_name; + + /* (3) Store backup path */ + $this->backup_path =__BACKUP__."/$db_name"; + + /* (4) If dir. already exists -> do nothing more */ + if( is_dir($this->backup_path) ) + return; + + /* (4) Else -> try to create + set permissions */ + mkdir($this->backup_path); + chmod($this->backup_path, 0775); + + } + + + /* (3) Scan directory files + * + * @path Directory path + * + * @return files Array containing file names + * + ---------------------------------------------------------*/ + private function scandir(string $path) : array { + + /* (1) Return [] if not a directory */ + if( !is_dir($path) ) + return []; + + /* (2) Scan the directory */ + $files = scandir($path); + + /* (3) Remove '.' and '..' (2 first elements) */ + $files = array_slice($files, 2); + + /* (4) Return file list */ + return $files; + + } + + + + /* (4) List available versions for this department + * + * @return versions Version list + * + ---------------------------------------------------------*/ + public function get($args){ + + /* (1) Initialize directory for current database (department) */ + $this->initDir( $_SESSION['CurrentDatabase'] ); + + /* (2) Strip extensions */ + $versions = array_map( + function($e){ return pathinfo($e, PATHINFO_FILENAME); }, + $this->scandir($this->backup_path) + ); + + /* (3) Return versions */ + return ['versions' => $versions]; + + } + + + + /* (5) Remove an existing version for this department + * + * @version Version name (typically snapshot date) + * + * @return deleted Whether the version has been deleted + * + ---------------------------------------------------------*/ + public function delete($args){ + $version = null; + extract($args); + + /* (1) Initialize directory for current database (department) */ + $this->initDir( $_SESSION['CurrentDatabase'] ); + + /* (2) Dispatch 'unlink' result */ + return [ 'deleted' => unlink($this->backup_path."/$version.sql") ]; + } + + + + /* (6) Creates a new version (snapshot of database) from now + * + * @return created_id The created version id (date) + * + ---------------------------------------------------------*/ + public function post($args){ + + + /* (1) Initialize directory for current database (department) */ + $this->initDir( $_SESSION['CurrentDatabase'] ); + + /* (2) Try to create the snapshot */ + try{ + + /* (2.1) Get database configuration */ + $conf = Repo::getDBConfig(); + + /* (2.2) Try to dump the database */ + $dump = new Mysqldump( + 'mysql:host='.$conf['host'].';dbname='.$conf['dbname'], + $conf['username'], + $conf['password'], + [ "compress" => Mysqldump::GZIP ] + ); + + /* (2.3) Get current date (for naming the version) */ + $current_date = date('d-m-Y'); + + /* (2.4) Store the version */ + $dump->start($this->backup_path."/$current_date.sql"); + + /* (2.5) Return status */ + return ['created_id' => $current_date ]; + + /* (3) On error -> dispatch error */ + }catch(\Exception $e){ + + return ['error' => new Error(Err::RepoError)]; + + } + + } + + + /* (6) ( Switches to preview || Applies on prod ) for a version + * + * @apply If 0 -> preview version + * If 1 -> apply version into prod database + * @version [OPT] Version name to use (if ommited, switch back to prod database) + * + * @return created_id The created version id (date) + * + ---------------------------------------------------------*/ + public function put($args){ + $apply = null; + $version = null; + extract($args); + + + /* (1) Initialisation + ---------------------------------------------------------*/ + /* (1) Initialize directory for current database (department) */ + $this->initDir( $_SESSION['CurrentDatabase'] ); + + /* (2) Get department repository */ + /** @var department $dept_repo */ + $dept_repo = Repo::getRepo('department'); + + /* (2) Check whether we have to [apply OR preview] */ + $apply = ( $apply === '1' ); + + + + + /* (2) If back to 'prod' database + ---------------------------------------------------------*/ + if( is_null($version) ){ + + /* (1) Reset database to 'prod' */ + $_SESSION['CurrentDatabase'] = $this->origin_dbname; + + /* (2) Return success */ + return [ 'updated' => true ]; + + } + + + + /* (3) Read the backup version + ---------------------------------------------------------*/ + /* (1) Start buffer */ + ob_start(); + + /* (2) Read backup file */ + readgzfile($this->backup_path."/$version.sql"); + + /* (3) Store & Flush buffer into variable */ + $snapshot = ob_get_clean(); + + /* (4) Manage error */ + if( strlen($snapshot) === 0 ) + return ['error' => new Error(Err::RepoError)]; + + + + /* (4) APPLY into 'prod' database + ---------------------------------------------------------*/ + if( $apply ){ + + /* (1) Restore from this version */ + $restored = $dept_repo->restore($this->origin_dbname, $snapshot); + + /* (2) Dispatch repo execution status */ + return [ 'updated' => $restored ]; + + } + + + /* (5) PREVIEW version database + ---------------------------------------------------------*/ + /* (1) Try to get 'preview' database name */ + $preview_dbname = $dept_repo->previewExists($this->origin_dbname, $version); + + /* (2) If does not exist -> create it */ + if( is_null($preview_dbname) ){ + + /* 1. Try to create preview */ + $preview_dbname = $dept_repo->createPreview($this->origin_dbname, $version); + + /* 2. Switch to preview */ + $dept_repo->restore($preview_dbname, $snapshot); + + } + + /* (3) Store 'preview' database in session */ + $_SESSION['CurrentDatabase'] = $preview_dbname; + + + /* (4) Return status */ + return [ 'updated' => true ]; + + } + +} \ No newline at end of file diff --git a/config/modules.json b/config/modules.json index 21fe028..9247ab8 100644 --- a/config/modules.json +++ b/config/modules.json @@ -98,26 +98,42 @@ } } }, - "save":{ + "version":{ "GET": { - "des": "Get the list of the saves of the department database", + "des": "Get the list of the versions of the department", "per": [], - "par": { + "par": {}, + "output": { + "versions": { "des": "List of available versions", "typ": "array" } } }, "POST": { "des": "Create a backup if the name is empty, execute the backup if the name is set", "per": [], + "par": {}, + "output": { + "created_id": { "des": "The id of the created version", "typ": "varchar(10,10,alphanumeric)" } + } + }, + "PUT": { + "des": "Switches to a older version or to current state", + "per": [], "par": { - "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} + "URL0": { "des": "0 to preview, 1 to apply", "typ": "id", "ren": "apply" }, + "URL1": { "des": "The version name, current state if ommited", "typ": "varchar(10,10,alphanumeric)", "ren": "version", "opt": true } + }, + "output": { + "updated": { "des": "Whether the version has been switched|applied", "typ": "bool" } } }, "DELETE": { "des": "Delete a backup", "per": [], "par": { - "backupName": {"des": "Backup name", "typ": "varchar(1,10,alphanumeric)"} + "URL0": { "des": "The version name", "typ": "varchar(10,10,alphanumeric)", "ren": "version" } + }, + "output": { + "deleted": { "des": "Whether the version has been deleted", "typ": "bool" } } } }