New version managing API
This commit is contained in:
parent
367d3c5988
commit
c6b46e1b88
|
@ -26,7 +26,7 @@
|
|||
if( !isset($_SESSION['CAS']) || !is_array($_SESSION['CAS']) ) $_SESSION['CAS'] = [];
|
||||
if( !isset($_SESSION['AUTH']) || !is_array($_SESSION['AUTH']) ) $_SESSION['AUTH'] = [];
|
||||
if( !isset($_SESSION['AvailableDepartments']) || !is_array($_SESSION['AvailableDepartments']) ) $_SESSION['AvailableDepartments'] = [];
|
||||
if( !isset($_SESSION['VERSION']) || !is_string($_SESSION['VERSION']) ) $_SESSION['VERSION'] = null;
|
||||
if( !isset($_SESSION['VERSION']) || !is_int($_SESSION['VERSION']) ) $_SESSION['VERSION'] = null;
|
||||
if( !isset($_SESSION['CurrentDepartmentId']) || !is_int($_SESSION['CurrentDepartmentId']) ) $_SESSION['CurrentDepartmentId'] = null;
|
||||
|
||||
|
||||
|
|
|
@ -146,7 +146,7 @@ class casController{
|
|||
$_SESSION['AvailableDepartments'] = $departments;
|
||||
|
||||
/* (4) Choose first department by default */
|
||||
$_SESSION['CurrentDatabase'] = $departments[0]['dbName'];
|
||||
$_SESSION['CurrentDatabase'] = $departments[0]['versions'][0]['dbName'];
|
||||
$_SESSION['CurrentDepartmentId'] = $departments[0]['idDep'];
|
||||
|
||||
/* (5) Use this department's database */
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
<?php
|
||||
/**
|
||||
* Created by PhpStorm.
|
||||
* User: lucas
|
||||
* Date: 07/05/18
|
||||
* Time: 17:59
|
||||
*/
|
||||
|
||||
namespace api\module\department\version;
|
||||
|
||||
|
||||
use database\core\Repo;
|
||||
|
||||
class switchController
|
||||
{
|
||||
|
||||
public function get($args){
|
||||
$version = null;
|
||||
extract($args);
|
||||
|
||||
$versionData = Repo::getRepo("meta")->getVersionById($version);
|
||||
$_SESSION['CurrentDatabase'] = $versionData["dbName"];
|
||||
$_SESSION['VERSION'] = $version;
|
||||
|
||||
return ["success" => true];
|
||||
}
|
||||
|
||||
}
|
|
@ -10,6 +10,7 @@ namespace api\module\department;
|
|||
|
||||
|
||||
use database\core\Repo;
|
||||
use database\repo\meta;
|
||||
use error\core\Error;
|
||||
use error\core\Err;
|
||||
use database\repo\department;
|
||||
|
@ -18,95 +19,6 @@ use Ifsnop\Mysqldump\Mysqldump;
|
|||
class versionController{
|
||||
|
||||
|
||||
/* Attributes
|
||||
---------------------------------------------------------*/
|
||||
private $backup_path;
|
||||
private $origin_dbname;
|
||||
|
||||
|
||||
|
||||
|
||||
/* (1) Initialize object
|
||||
*
|
||||
---------------------------------------------------------*/
|
||||
public function __construct(){
|
||||
$this->backup_path = null;
|
||||
$this->origin_dbname = null;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/* (2) Initializes a directory
|
||||
*
|
||||
* @db_name<String> The database name
|
||||
*
|
||||
* @return outName<outType> 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<String> Directory path
|
||||
*
|
||||
* @return files<array> 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<array> Version list
|
||||
|
@ -114,17 +26,12 @@ class versionController{
|
|||
---------------------------------------------------------*/
|
||||
public function get($args){
|
||||
|
||||
/* (1) Initialize directory for current database (department) */
|
||||
$this->initDir( $_SESSION['CurrentDatabase'] );
|
||||
//search for the current department in the session and return its versions
|
||||
/** @var meta $depRepo */
|
||||
$depRepo = Repo::getRepo("meta");
|
||||
|
||||
/* (2) Strip extensions */
|
||||
$versions = array_map(
|
||||
function($e){ return pathinfo($e, PATHINFO_FILENAME); },
|
||||
$this->scandir($this->backup_path)
|
||||
);
|
||||
|
||||
/* (3) Return versions */
|
||||
return ['versions' => $versions ];
|
||||
//if no department found, return an empty array
|
||||
return ['versions' => $depRepo->getAllVersions($_SESSION['CurrentDepartmentId']) ];
|
||||
|
||||
}
|
||||
|
||||
|
@ -132,7 +39,7 @@ class versionController{
|
|||
|
||||
/* (5) Remove an existing version for this department
|
||||
*
|
||||
* @version<String> Version name (typically snapshot date)
|
||||
* @version<int> Version name (typically snapshot date)
|
||||
*
|
||||
* @return deleted<bool> Whether the version has been deleted
|
||||
*
|
||||
|
@ -141,11 +48,8 @@ class versionController{
|
|||
$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") ];
|
||||
/* (1) Dispatch 'deleteVersion' result */
|
||||
return [ 'deleted' => Repo::getRepo("meta")->deleteVersion($version) ];
|
||||
}
|
||||
|
||||
|
||||
|
@ -156,10 +60,8 @@ class versionController{
|
|||
*
|
||||
---------------------------------------------------------*/
|
||||
public function post($args){
|
||||
|
||||
|
||||
/* (1) Initialize directory for current database (department) */
|
||||
$this->initDir( $_SESSION['CurrentDatabase'] );
|
||||
$label = null;
|
||||
extract($args);
|
||||
|
||||
/* (2) Try to create the snapshot */
|
||||
try{
|
||||
|
@ -168,21 +70,33 @@ class versionController{
|
|||
$conf = Repo::getDBConfig();
|
||||
|
||||
/* (2.2) Try to dump the database */
|
||||
/** @var Mysqldump*/
|
||||
$dump = new Mysqldump(
|
||||
'mysql:host='.$conf['host'].';dbname='.$conf['dbname'],
|
||||
'mysql:host='.$conf['host'].';dbname='.$_SESSION['CurrentDatabase'],
|
||||
$conf['username'],
|
||||
$conf['password'],
|
||||
[ "compress" => Mysqldump::GZIP ]
|
||||
$conf['password']
|
||||
);
|
||||
|
||||
/* (2.3) Get current date (for naming the version) */
|
||||
$current_date = date('d-m-Y');
|
||||
//create temporary file;
|
||||
$file = tmpfile();
|
||||
//get URI
|
||||
$metaDatas = stream_get_meta_data($file);
|
||||
$tmpFilename = $metaDatas['uri'];
|
||||
//close file pointer
|
||||
fclose($file);
|
||||
//fill the file with sql dump
|
||||
$dump->start($tmpFilename);
|
||||
|
||||
/* (2.4) Store the version */
|
||||
$dump->start($this->backup_path."/$current_date.sql");
|
||||
/** @var department $depRepo */
|
||||
$depRepo = Repo::getRepo("department");
|
||||
$dbName = $depRepo->createVersionDatabase($_SESSION['CurrentDepartmentId'],file_get_contents($tmpFilename));
|
||||
|
||||
/** @var meta $metaRep */
|
||||
$metaRep = Repo::getRepo("meta");
|
||||
$versionId = $metaRep->createVersion($label, $dbName,$_SESSION['CurrentDepartmentId'] ,false);
|
||||
|
||||
/* (2.5) Return status */
|
||||
return ['created_id' => $current_date ];
|
||||
return ['created_id' => $versionId ];
|
||||
|
||||
/* (3) On error -> dispatch error */
|
||||
}catch(\Exception $e){
|
||||
|
@ -194,106 +108,24 @@ class versionController{
|
|||
}
|
||||
|
||||
|
||||
/* (6) ( Switches to preview || Applies on prod ) for a version
|
||||
/* (6) Modify a version and use it
|
||||
*
|
||||
* @apply<int> If 0 -> preview version
|
||||
* If 1 -> apply version into prod database
|
||||
* @version<String> [OPT] Version name to use (if ommited, switch back to prod database)
|
||||
*
|
||||
* @return created_id<String> The created version id (date)
|
||||
* @return bool success
|
||||
*
|
||||
---------------------------------------------------------*/
|
||||
public function put($args){
|
||||
$apply = null;
|
||||
$label = null;
|
||||
$version = null;
|
||||
$default = 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');
|
||||
|
||||
/* (3) 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;
|
||||
$_SESSION['VERSION'] = null;
|
||||
|
||||
/* (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);
|
||||
$_SESSION['VERSION'] = null;
|
||||
|
||||
/* (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;
|
||||
$_SESSION['VERSION'] = $version;
|
||||
/** @var meta $metaRepo */
|
||||
$metaRepo = Repo::getRepo("meta");
|
||||
|
||||
|
||||
/* (4) Return status */
|
||||
return [ 'updated' => true ];
|
||||
return [ 'updated' => $metaRepo->updateVersion($version,$label,$default) ];
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -167,36 +167,13 @@ class department extends Repo_i
|
|||
|
||||
}
|
||||
|
||||
public function restore(string $dbName, string $SQL) : bool{
|
||||
public function createVersionDatabase(String $depId, String $SQL) : String{
|
||||
$dbName = uniqid($depId)."";
|
||||
|
||||
//get the list of command to execute
|
||||
$this->pdo->exec("DROP DATABASE $dbName;");
|
||||
$this->pdo->exec("CREATE DATABASE $dbName;");
|
||||
$this->pdo->exec("USE $dbName;");
|
||||
$this->pdo->exec("CREATE DATABASE $dbName; USE $dbName;".$SQL."USE {$_SESSION["CurrentDatabase"]};SET autocommit=1;");
|
||||
$this->pdo->setAttribute(\PDO::ATTR_AUTOCOMMIT,1);
|
||||
|
||||
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;
|
||||
return $dbName;
|
||||
}
|
||||
|
||||
}
|
|
@ -88,7 +88,7 @@ class meta extends Repo_i {
|
|||
public function get_prof_departments(String $casLogin) : array{
|
||||
|
||||
/* (1) Prepare Statement */
|
||||
$st = $this->pdo->prepare("SELECT d2.iddepartement idDep, d2.label labelDep, d2.databaseName dbName
|
||||
$st = $this->pdo->prepare("SELECT d2.iddepartement idDep, d2.label labelDep
|
||||
FROM meta_vhost.casUser
|
||||
JOIN meta_vhost.linkedDep D ON casUser.casLogin = D.casUser_casLogin
|
||||
JOIN meta_vhost.departement d2 ON D.departement_iddepartement = d2.iddepartement
|
||||
|
@ -112,7 +112,17 @@ class meta extends Repo_i {
|
|||
if( $fetched === false )
|
||||
return [];
|
||||
|
||||
/* (7) Return data */
|
||||
/* (7) Add all possible databases to the department */
|
||||
foreach ($fetched as &$dep){
|
||||
$st = $this->pdo->prepare("SELECT *
|
||||
FROM meta_vhost.`databases`
|
||||
WHERE departement_iddepartement = :idDep
|
||||
ORDER BY meta_vhost.`databases`.`default` DESC ");
|
||||
$st->execute(["idDep" => $dep["idDep"]]);
|
||||
$dep["versions"] = $st->fetchAll();
|
||||
}
|
||||
|
||||
/* (8) Return data */
|
||||
return $fetched;
|
||||
|
||||
}
|
||||
|
@ -145,15 +155,6 @@ class meta extends Repo_i {
|
|||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/* (5) Check if a link exists
|
||||
*
|
||||
* @casLogin<String> The professor's cas login
|
||||
|
@ -254,4 +255,75 @@ class meta extends Repo_i {
|
|||
|
||||
}
|
||||
|
||||
public function deleteVersion(int $version) : bool{
|
||||
//get version data
|
||||
$st = $this->pdo->prepare("SELECT * FROM meta_vhost.`databases` WHERE iddatabase = :id");
|
||||
$st->execute(["id" => $version]);
|
||||
|
||||
$versionData = $st->fetch();
|
||||
|
||||
if($versionData == false){
|
||||
return false;
|
||||
}
|
||||
|
||||
//delete database
|
||||
$this->pdo->exec("DROP DATABASE {$versionData["dbName"]}");
|
||||
|
||||
//remove from meta
|
||||
$st = $this->pdo->prepare("DELETE FROM meta_vhost.`databases` WHERE iddatabase = :id");
|
||||
return $st->execute(["id" => $version]);
|
||||
}
|
||||
|
||||
public function createVersion(String $label, String $dbName, int $depId, bool $isDefault = false) : int{
|
||||
|
||||
$st = $this->pdo->prepare("INSERT INTO meta_vhost.`databases`(label, dbName, `default`, departement_iddepartement)
|
||||
VALUE (:label,:dbName,:default,:depId)");
|
||||
$st->execute([
|
||||
"label" => $label,
|
||||
"dbName" => $dbName,
|
||||
"default" => $isDefault? 1 : 0,
|
||||
"depId" => $depId
|
||||
]);
|
||||
|
||||
return $this->pdo->lastInsertId();
|
||||
}
|
||||
|
||||
public function getVersionById(int $id) : array{
|
||||
$st = $this->pdo->prepare("SELECT * FROM meta_vhost.`databases` WHERE iddatabase = :idVersion");
|
||||
$st->execute(["idVersion" => $id]);
|
||||
|
||||
$fetched = $st->fetch();
|
||||
|
||||
return $fetched == false ? [] : $fetched;
|
||||
}
|
||||
|
||||
public function getAllVersions(int $idDep) : array {
|
||||
$st = $this->pdo->prepare("SELECT * FROM meta_vhost.`databases` WHERE departement_iddepartement = :idDep");
|
||||
$st->execute(["idDep" => $idDep]);
|
||||
|
||||
return $st->fetchAll();
|
||||
}
|
||||
|
||||
public function updateVersion(int $version, ?String $label, ?bool $default) : bool{
|
||||
$set = "";
|
||||
$execute = [];
|
||||
|
||||
if($label != null){
|
||||
$set .= "label=:label,";
|
||||
$execute["label"] = $label;
|
||||
}
|
||||
|
||||
if($default != null){
|
||||
$set .= "default=:default,";
|
||||
$execute["default"] = $default?1:0;
|
||||
}
|
||||
|
||||
$set = rtrim($set,",");
|
||||
|
||||
$execute["idVersion"] = $version;
|
||||
|
||||
$st = $this->pdo->prepare("UPDATE meta_vhost.`databases` SET $set WHERE iddatabase=:idVersion");
|
||||
|
||||
return $st->execute($execute);
|
||||
}
|
||||
}
|
|
@ -29,6 +29,7 @@
|
|||
"phpstan/phpstan": "^0.9.2",
|
||||
"ifsnop/mysqldump-php": "2.*",
|
||||
"setasign/fpdf": "1.8.1",
|
||||
"mpdf/mpdf": "^7.0"
|
||||
"mpdf/mpdf": "^7.0",
|
||||
"php" : ">= 7.1"
|
||||
}
|
||||
}
|
||||
|
|
Binary file not shown.
|
@ -110,6 +110,18 @@
|
|||
}
|
||||
},
|
||||
"version":{
|
||||
"switch":{
|
||||
"GET": {
|
||||
"des": "Switch database version for the current session",
|
||||
"per": [["cas_admin"]],
|
||||
"par": {
|
||||
"URL0": { "des": "The version id", "typ": "id", "ren": "version" }
|
||||
},
|
||||
"output": {
|
||||
"sucess": { "des": "success of the operation", "typ": "bool" }
|
||||
}
|
||||
}
|
||||
},
|
||||
"GET": {
|
||||
"des": "Get the list of the versions of the department",
|
||||
"per": [["cas_admin"]],
|
||||
|
@ -121,17 +133,20 @@
|
|||
"POST": {
|
||||
"des": "Create a backup if the name is empty, execute the backup if the name is set",
|
||||
"per": [["cas_admin"]],
|
||||
"par": {},
|
||||
"par": {
|
||||
"label": { "des": "Label of the version","typ": "text"}
|
||||
},
|
||||
"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",
|
||||
"des": "Update a version and switch to this version",
|
||||
"per": [["cas_admin"]],
|
||||
"par": {
|
||||
"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 }
|
||||
"URL0": { "des": "id of the version","typ": "id","ren": "version"},
|
||||
"label" : { "des": "Label de la version", "typ": "text", "opt":true},
|
||||
"default": { "des": "true if this version is the one that should be used by default on login", "typ": "bool","opt":true}
|
||||
},
|
||||
"output": {
|
||||
"updated": { "des": "Whether the version has been switched|applied", "typ": "bool" }
|
||||
|
@ -141,7 +156,7 @@
|
|||
"des": "Delete a backup",
|
||||
"per": [["cas_admin"]],
|
||||
"par": {
|
||||
"URL0": { "des": "The version name", "typ": "varchar(10,10,alphanumeric)", "ren": "version" }
|
||||
"URL0": { "des": "The version id", "typ": "id", "ren": "version" }
|
||||
},
|
||||
"output": {
|
||||
"deleted": { "des": "Whether the version has been deleted", "typ": "bool" }
|
||||
|
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue