patch sql -> cli
This commit is contained in:
parent
186083a315
commit
ebdece7144
@ -37,7 +37,7 @@ The compiled dist files will be automatically moved to `/js`.
|
||||
|
||||
Each API endpoint has usually one overlying category, for example all user and authorization endpoints belong to the [UserAPI](/core/Api/UserAPI.class.php).
|
||||
These endpoints can be accessed by requesting URLs starting with `/api/user`, for example: `/api/user/login`. There are also endpoints, which don't have
|
||||
a category, e.g. [PatchSQL](/core/Api/PatchSQL.class.php). These functions can be called directly, for example with `/api/patchSQL`. Both methods have one thing in common:
|
||||
a category, e.g. [VerifyCaptcha](/core/Api/VerifyCaptcha.class.php). These functions can be called directly, for example with `/api/verifyCaptcha`. Both methods have one thing in common:
|
||||
Each endpoint is represented by a class inheriting the [Request Class](/core/Api/Request.class.php). An example endpoint looks like this:
|
||||
|
||||
```php
|
||||
@ -112,7 +112,7 @@ If any result is expected from the api call, the `$req->getResult()` method can
|
||||
This step is not really required, as and changes made to the database must not be presented inside the code.
|
||||
On the other hand, it is recommended to keep track of any modifications for later use or to deploy the application
|
||||
to other systems. Therefore, either the [default installation script](/core/Configuration/CreateDatabase.class.php) or
|
||||
an additional patch file, which can be executed using the API (`/api/PatchSQL`), can be created. The patch files are usually
|
||||
an additional patch file, which can be executed using the [CLI](/cli.php), can be created. The patch files are usually
|
||||
located in [/core/Configuration/Patch](/core/Configuration/Patch) and have the following structure:
|
||||
|
||||
```php
|
||||
|
157
cli.php
157
cli.php
@ -44,76 +44,117 @@ function printHelp() {
|
||||
function handleDatabase($argv) {
|
||||
$action = $argv[2] ?? "";
|
||||
|
||||
switch ($action) {
|
||||
case 'migrate':
|
||||
$class = $argv[3] ?? null;
|
||||
if (!$class) {
|
||||
die("Usage: cli.php db migrate <class name>\n");
|
||||
if ($action === "migrate") {
|
||||
$class = $argv[3] ?? null;
|
||||
if (!$class) {
|
||||
die("Usage: cli.php db migrate <class name>\n");
|
||||
}
|
||||
|
||||
$class = str_replace('/', '\\', $class);
|
||||
$className = "\\Configuration\\$class";
|
||||
$classPath = getClassPath($className);
|
||||
if (!file_exists($classPath) || !is_readable($classPath)) {
|
||||
die("Database script file does not exist or is not readable\n");
|
||||
}
|
||||
|
||||
include_once $classPath;
|
||||
$obj = new $className();
|
||||
if (!($obj instanceof DatabaseScript)) {
|
||||
die("Not a database script\n");
|
||||
}
|
||||
|
||||
$db = connectDatabase();
|
||||
$queries = $obj->createQueries($db);
|
||||
foreach ($queries as $query) {
|
||||
if (!$query->execute($db)) {
|
||||
die($db->getLastError());
|
||||
}
|
||||
}
|
||||
|
||||
$db->close();
|
||||
} else if ($action === "export" || $action === "import") {
|
||||
|
||||
// database config
|
||||
$config = getDatabaseConfig();
|
||||
$dbType = $config->getProperty("type") ?? null;
|
||||
$user = $config->getLogin();
|
||||
$password = $config->getPassword();
|
||||
$database = $config->getProperty("database");
|
||||
$host = $config->getHost();
|
||||
$port = $config->getPort();
|
||||
|
||||
// subprocess config
|
||||
$env = [];
|
||||
$options = array_slice($argv, 3);
|
||||
$dataOnly = in_array("--data-only", $options) || in_array("-d", $options);
|
||||
$descriptorSpec = [STDIN, STDOUT, STDOUT];
|
||||
$inputData = null;
|
||||
|
||||
// argument config
|
||||
if ($action === "import") {
|
||||
$file = $argv[3] ?? null;
|
||||
if (!$file) {
|
||||
die("Usage: cli.php db import <path>\n");
|
||||
}
|
||||
|
||||
$class = str_replace('/', '\\', $class);
|
||||
$className = "\\Configuration\\$class";
|
||||
$classPath = getClassPath($className);
|
||||
if (!file_exists($classPath) || !is_readable($classPath)) {
|
||||
die("Database script file does not exist or is not readable\n");
|
||||
if (!file_exists($file) || !is_readable($file)) {
|
||||
die("File not found or not readable\n");
|
||||
}
|
||||
|
||||
include_once $classPath;
|
||||
$obj = new $className();
|
||||
if (!($obj instanceof DatabaseScript)) {
|
||||
die("Not a database script\n");
|
||||
}
|
||||
$inputData = file_get_contents($file);
|
||||
}
|
||||
|
||||
$db = connectDatabase();
|
||||
$queries = $obj->createQueries($db);
|
||||
foreach ($queries as $query) {
|
||||
if (!$query->execute($db)) {
|
||||
die($db->getLastError());
|
||||
if ($dbType === "mysql") {
|
||||
$command_args = ["-u", $user, '-h', $host, '-P', $port, "--password=$password"];
|
||||
if ($action === "export") {
|
||||
$command_bin = "mysqldump";
|
||||
if ($dataOnly) {
|
||||
$command_args[] = "--skip-triggers";
|
||||
$command_args[] = "--compact";
|
||||
$command_args[] = "--no-create-info";
|
||||
}
|
||||
}
|
||||
|
||||
$db->close();
|
||||
break;
|
||||
case 'export':
|
||||
$config = getDatabaseConfig();
|
||||
$dbType = $config->getProperty("type") ?? null;
|
||||
$user = $config->getLogin();
|
||||
$password = $config->getPassword();
|
||||
$database = $config->getProperty("database");
|
||||
$host = $config->getHost();
|
||||
$port = $config->getPort();
|
||||
|
||||
$env = [];
|
||||
$output = $argv[3] ?? null;
|
||||
$descriptorSpec = [STDIN, STDOUT, STDOUT];
|
||||
|
||||
if ($dbType === "mysql") {
|
||||
|
||||
$command = ["mysqldump", "-u", $user, '-h', $host, '-P', $port, "--password=$password"];
|
||||
if ($database) {
|
||||
$command[] = $database;
|
||||
}
|
||||
|
||||
} else if ($dbType === "postgres") {
|
||||
$command = ["pg_dump", "-U", $user, '-h', $host, '-p', $port];
|
||||
if ($database) {
|
||||
$command[] = $database;
|
||||
}
|
||||
|
||||
$env["PGPASSWORD"] = $password;
|
||||
} else if ($action === "import") {
|
||||
$command_bin = "mysql";
|
||||
$descriptorSpec[0] = ["pipe", "r"];
|
||||
} else {
|
||||
die("Unsupported database type\n");
|
||||
die("Unsupported action\n");
|
||||
}
|
||||
} else if ($dbType === "postgres") {
|
||||
|
||||
$env["PGPASSWORD"] = $password;
|
||||
$command_args = ["-U", $user, '-h', $host, '-p', $port];
|
||||
|
||||
if ($action === "export") {
|
||||
$command_bin = "/usr/bin/pg_dump";
|
||||
if ($dataOnly) {
|
||||
$command_args[] = "--data-only";
|
||||
}
|
||||
} else if ($action === "import") {
|
||||
$command_bin = "/usr/bin/psql";
|
||||
$descriptorSpec[0] = ["pipe", "r"];
|
||||
} else {
|
||||
die("Unsupported action\n");
|
||||
}
|
||||
|
||||
if ($output) {
|
||||
$descriptorSpec[1] = ["file", $output, "w"];
|
||||
} else {
|
||||
die("Unsupported database type\n");
|
||||
}
|
||||
|
||||
if ($database) {
|
||||
$command_args[] = $database;
|
||||
}
|
||||
|
||||
$command = array_merge([$command_bin], $command_args);
|
||||
$process = proc_open($command, $descriptorSpec, $pipes, null, $env);
|
||||
|
||||
if (is_resource($process)) {
|
||||
if ($action === "import" && $inputData && count($pipes) > 0) {
|
||||
fwrite($pipes[0], $inputData);
|
||||
fclose($pipes[0]);
|
||||
}
|
||||
|
||||
$process = proc_open($command, $descriptorSpec, $pipes, null, $env);
|
||||
proc_close($process);
|
||||
break;
|
||||
default:
|
||||
die("Usage: cli.php db <import|export|migrate>\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,65 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Api;
|
||||
|
||||
use Api\Parameter\StringType;
|
||||
use Configuration\DatabaseScript;
|
||||
use Objects\User;
|
||||
|
||||
class PatchSQL extends Request {
|
||||
|
||||
public function __construct(User $user, bool $externalCall = false) {
|
||||
parent::__construct($user, $externalCall, array(
|
||||
"className" => new StringType("className", 64)
|
||||
));
|
||||
$this->loginRequired = true;
|
||||
$this->csrfTokenRequired = false;
|
||||
}
|
||||
|
||||
public function execute($values = array()): bool {
|
||||
if (!parent::execute($values)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$className = $this->getParam("className");
|
||||
$fullClassName = "\\Configuration\\Patch\\" . $className;
|
||||
$path = getClassPath($fullClassName, true);
|
||||
if (!file_exists($path)) {
|
||||
return $this->createError("File not found");
|
||||
}
|
||||
|
||||
if(!class_exists($fullClassName)) {
|
||||
return $this->createError("Class not found.");
|
||||
}
|
||||
|
||||
try {
|
||||
$reflection = new \ReflectionClass($fullClassName);
|
||||
if (!$reflection->isInstantiable()) {
|
||||
return $this->createError("Class is not instantiable");
|
||||
}
|
||||
|
||||
if (!$reflection->isSubclassOf(DatabaseScript::class)) {
|
||||
return $this->createError("Not a database script.");
|
||||
}
|
||||
|
||||
$sql = $this->user->getSQL();
|
||||
$obj = $reflection->newInstance();
|
||||
$queries = $obj->createQueries($sql);
|
||||
if (!is_array($queries)) {
|
||||
return $this->createError("Database script returned invalid values");
|
||||
}
|
||||
|
||||
foreach($queries as $query) {
|
||||
if (!$query->execute()) {
|
||||
return $this->createError("Query error: " . $sql->getLastError());
|
||||
}
|
||||
}
|
||||
|
||||
$this->success = true;
|
||||
} catch (\ReflectionException $e) {
|
||||
return $this->createError("Error reflecting class: " . $e->getMessage());
|
||||
}
|
||||
|
||||
return $this->success;
|
||||
}
|
||||
}
|
@ -193,8 +193,7 @@ class CreateDatabase extends DatabaseScript {
|
||||
->addRow("User/edit", array(USER_GROUP_ADMIN), "Allows users to edit details and group memberships of any user")
|
||||
->addRow("User/delete", array(USER_GROUP_ADMIN), "Allows users to delete any other user")
|
||||
->addRow("Permission/fetch", array(USER_GROUP_ADMIN), "Allows users to list all API permissions")
|
||||
->addRow("Visitors/stats", array(USER_GROUP_ADMIN, USER_GROUP_SUPPORT), "Allows users to see visitor statistics")
|
||||
->addRow("PatchSQL", array(USER_GROUP_ADMIN), "Allows users to import database patches");
|
||||
->addRow("Visitors/stats", array(USER_GROUP_ADMIN, USER_GROUP_SUPPORT), "Allows users to see visitor statistics");
|
||||
|
||||
self::loadPatches($queries, $sql);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user