mirror of
https://github.com/DanielnetoDotCom/YouPHPTube
synced 2025-10-03 09:49:28 +02:00
Now you can create plugins directly from the AVideo
This commit is contained in:
parent
011066baa9
commit
bcd92a864c
7 changed files with 448 additions and 262 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -105,3 +105,4 @@ install/bulkCreateUser.php
|
|||
plugin/WebAuthnLogin/
|
||||
plugin/UserOTPLogin/
|
||||
test*
|
||||
CreatePlugin/plugins/
|
||||
|
|
|
@ -1,265 +1,227 @@
|
|||
<?php
|
||||
require_once __DIR__.'/../videos/configuration.php';
|
||||
|
||||
header('Content-Type: application/json');
|
||||
|
||||
if(!User::isAdmin()){
|
||||
forbiddenPage('You Must be admin');
|
||||
}
|
||||
|
||||
|
||||
if(!empty($global['disableAdvancedConfigurations'])){
|
||||
forbiddenPage('Configuration disabled');
|
||||
}
|
||||
|
||||
use iamcal\SQLParser;
|
||||
|
||||
$parser = new SQLParser();
|
||||
try {
|
||||
$parser = new SQLParser();
|
||||
|
||||
$pluginName = $_REQUEST['pluginName'];
|
||||
$sql = $_REQUEST['createTableSQL'];
|
||||
// Plugin name and SQL file (replace these with dynamic input as needed)
|
||||
$pluginName = $_REQUEST['pluginName'];
|
||||
$sql = $_REQUEST['createTableSQL'];
|
||||
|
||||
$parser->parse($sql);
|
||||
//var_dump($parser->tables);exit;
|
||||
$pluginDir = __DIR__."/plugins/{$pluginName}/";
|
||||
echo $pluginDir, PHP_EOL;
|
||||
_mkdir($pluginDir);
|
||||
// Sanitize and format plugin name
|
||||
$pluginName = preg_replace('/[^a-zA-Z0-9_]/', '', ucfirst($pluginName));
|
||||
if (!preg_match('/^[A-Z][A-Za-z0-9_]*$/', $pluginName)) {
|
||||
throw new Exception('Invalid plugin name. It must start with an uppercase letter and contain only letters, numbers, and underscores.');
|
||||
}
|
||||
|
||||
$pluginDirInstall = "{$pluginDir}/install/";
|
||||
_mkdir($pluginDirInstall);
|
||||
file_put_contents($pluginDirInstall . "install.sql", $sql);
|
||||
$parser->parse($sql);
|
||||
|
||||
$pluginDirObjects = "{$pluginDir}/Objects/";
|
||||
_mkdir($pluginDirObjects);
|
||||
// Define plugin directories
|
||||
$pluginZip = "plugins/{$pluginName}.zip";
|
||||
$pluginDir = "plugins/{$pluginName}/";
|
||||
_mkdir($pluginDir);
|
||||
|
||||
$pluginDirView = "{$pluginDir}/View/";
|
||||
_mkdir($pluginDirView);
|
||||
$pluginDirInstall = "{$pluginDir}install/";
|
||||
_mkdir($pluginDirInstall);
|
||||
$installFilePath = $pluginDirInstall . "install.sql";
|
||||
file_put_contents($installFilePath, $sql);
|
||||
$response['createdFiles'][] = $installFilePath;
|
||||
|
||||
$includeTables = array();
|
||||
$editorNavTabs = array();
|
||||
$editorNavContent = array();
|
||||
$active = true;
|
||||
foreach ($parser->tables as $value) {
|
||||
$classname = ucwords($value['name']);
|
||||
$tableName = ucwords(str_replace("_", " ", $value['name']));
|
||||
$pluginDirObjects = "{$pluginDir}Objects/";
|
||||
_mkdir($pluginDirObjects);
|
||||
|
||||
$pluginDirView = "{$pluginDir}View/";
|
||||
_mkdir($pluginDirView);
|
||||
|
||||
// Initialize arrays to build templates and file paths
|
||||
$includeTables = [];
|
||||
$editorNavTabs = [];
|
||||
$editorNavContent = [];
|
||||
$active = true;
|
||||
|
||||
$response['tables'] = array();
|
||||
|
||||
// Process each table found in SQL
|
||||
foreach ($parser->tables as $table) {
|
||||
$tableName = $table['name'];
|
||||
$response['tables'][] = $tableName; // Add table name to response
|
||||
|
||||
$classname = ucwords($tableName);
|
||||
$includeTables[] = "require_once \$global['systemRootPath'] . 'plugin/{$pluginName}/Objects/{$classname}.php';";
|
||||
|
||||
// HTML for editor navigation
|
||||
$editorNavTabs[] = "<li class=\"" . ($active ? "active" : "") . "\"><a data-toggle=\"tab\" href=\"#{$classname}\"><?php echo __(\"{$tableName}\"); ?></a></li>";
|
||||
$editorNavContent[] = "<div id=\"{$classname}\" class=\"tab-pane fade " . ($active ? "in active" : "") . "\" style=\"padding: 10px;\">
|
||||
<?php
|
||||
include \$global['systemRootPath'] . 'plugin/{$pluginName}/View/{$classname}/index_body.php';
|
||||
?>
|
||||
<?php include \$global['systemRootPath'] . 'plugin/{$pluginName}/View/{$classname}/index_body.php'; ?>
|
||||
</div>";
|
||||
$active = false;
|
||||
$includeTables[] = "require_once \$global['systemRootPath'] . 'plugin/{$pluginName}/Objects/{$classname}.php';";
|
||||
$columnsVars = array();
|
||||
$columnsString = array();
|
||||
$columnsGet = array();
|
||||
$columnsSet = array();
|
||||
$columnsForm = array();
|
||||
$columnsFooter = array();
|
||||
$columnsGrid = array();
|
||||
$columnsClearJQuery = array();
|
||||
$columnsDatatable = array();
|
||||
$columnsEdit = array();
|
||||
$columnsAdd = array();
|
||||
$columnsGetAll = array();
|
||||
|
||||
foreach ($value['fields'] as $value2) {
|
||||
if ($value2['name'] == 'created' || $value2['name'] == 'modified') {
|
||||
// Initialize column-specific arrays
|
||||
$columnsVars = [];
|
||||
$columnsString = [];
|
||||
$columnsGet = [];
|
||||
$columnsSet = [];
|
||||
$columnsForm = [];
|
||||
$columnsFooter = [];
|
||||
$columnsGrid = [];
|
||||
$columnsClearJQuery = [];
|
||||
$columnsDatatable = [];
|
||||
$columnsEdit = [];
|
||||
$columnsAdd = [];
|
||||
$columnsGetAll = [];
|
||||
|
||||
// Process each field in the table
|
||||
foreach ($table['fields'] as $field) {
|
||||
if ($field['name'] === 'created' || $field['name'] === 'modified') {
|
||||
continue;
|
||||
}
|
||||
$columnsVars[] = '$' . $value2['name'];
|
||||
$type = strtolower($value2['type']);
|
||||
if ($type == 'text' || $type == 'varchar') {
|
||||
$columnsString[] = "'{$value2['name']}'";
|
||||
// Initialize fields
|
||||
$columnsVars[] = '$' . $field['name'];
|
||||
$type = strtolower($field['type']);
|
||||
$fieldName = ucwords(str_replace("_", " ", $field['name']));
|
||||
|
||||
if ($type === 'text' || $type === 'varchar') {
|
||||
$columnsString[] = "'{$field['name']}'";
|
||||
}
|
||||
$fieldName = ucwords(str_replace("_", " ", $value2['name']));
|
||||
$columnsClearJQuery[] = "$('#{$classname}{$value2['name']}').val('');";
|
||||
$columnsEdit[] = "$('#{$classname}{$value2['name']}').val(data.{$value2['name']});";
|
||||
if ($value2['name'] != 'id') {
|
||||
$columnsAdd[] = "\$o->set" . ucfirst($value2['name']) . "(\$_POST['{$value2['name']}']);";
|
||||
|
||||
// Generate field-related template replacements based on type
|
||||
if ($field['name'] != 'id') {
|
||||
$columnsAdd[] = "\$o->set" . ucfirst($field['name']) . "(\$_POST['{$field['name']}']);";
|
||||
}
|
||||
|
||||
if ($type == 'int' || $type == 'tinyint') {
|
||||
$columnsGet[] = "
|
||||
function get" . ucfirst($value2['name']) . "() {
|
||||
return intval(\$this->{$value2['name']});
|
||||
} ";
|
||||
|
||||
$columnsSet[] = "
|
||||
function set" . ucfirst($value2['name']) . "(\${$value2['name']}) {
|
||||
\$this->{$value2['name']} = intval(\${$value2['name']});
|
||||
} ";
|
||||
} else if ($type == 'float') {
|
||||
$columnsGet[] = "
|
||||
function get" . ucfirst($value2['name']) . "() {
|
||||
return floatval(\$this->{$value2['name']});
|
||||
} ";
|
||||
|
||||
$columnsSet[] = "
|
||||
function set" . ucfirst($value2['name']) . "(\${$value2['name']}) {
|
||||
\$this->{$value2['name']} = floatval(\${$value2['name']});
|
||||
} ";
|
||||
$columnsGet[] = "function get" . ucfirst($field['name']) . "() { return intval(\$this->{$field['name']}); }";
|
||||
$columnsSet[] = "function set" . ucfirst($field['name']) . "(\${$field['name']}) { \$this->{$field['name']} = intval(\${$field['name']}); }";
|
||||
} elseif ($type == 'float') {
|
||||
$columnsGet[] = "function get" . ucfirst($field['name']) . "() { return floatval(\$this->{$field['name']}); }";
|
||||
$columnsSet[] = "function set" . ucfirst($field['name']) . "(\${$field['name']}) { \$this->{$field['name']} = floatval(\${$field['name']}); }";
|
||||
} else {
|
||||
$columnsGet[] = "
|
||||
function get" . ucfirst($value2['name']) . "() {
|
||||
return \$this->{$value2['name']};
|
||||
} ";
|
||||
|
||||
$columnsSet[] = "
|
||||
function set" . ucfirst($value2['name']) . "(\${$value2['name']}) {
|
||||
\$this->{$value2['name']} = \${$value2['name']};
|
||||
} ";
|
||||
$columnsGet[] = "function get" . ucfirst($field['name']) . "() { return \$this->{$field['name']}; }";
|
||||
$columnsSet[] = "function set" . ucfirst($field['name']) . "(\${$field['name']}) { \$this->{$field['name']} = \${$field['name']}; }";
|
||||
}
|
||||
|
||||
if(preg_match("/^(.*)_id/i", $value2['name'], $matches)){
|
||||
|
||||
// Example code for creating getAll functions based on field name pattern
|
||||
if (preg_match("/^(.*)_id/i", $field['name'], $matches)) {
|
||||
$columnsGetAll[] = "static function getAll" . ucfirst($matches[1]) . "() {
|
||||
global \$global;
|
||||
\$table = \"{$matches[1]}\";
|
||||
\$sql = \"SELECT * FROM {\$table} WHERE 1=1 \";
|
||||
|
||||
\$sql .= self::getSqlFromPost();
|
||||
\$res = sqlDAL::readSql(\$sql);
|
||||
\$fullData = sqlDAL::fetchAllAssoc(\$res);
|
||||
\$rows = sqlDAL::fetchAllAssoc(\$res);
|
||||
sqlDAL::close(\$res);
|
||||
\$rows = array();
|
||||
if (\$res != false) {
|
||||
foreach (\$fullData as \$row) {
|
||||
\$rows[] = \$row;
|
||||
}
|
||||
} else {
|
||||
/**
|
||||
*
|
||||
* @var array \$global
|
||||
* @var object \$global['mysqli']
|
||||
*/
|
||||
_error_log(\$sql . ' Error : (' . \$global['mysqli']->errno . ') ' . \$global['mysqli']->error);
|
||||
}
|
||||
return \$rows;
|
||||
}";
|
||||
$columnsForm[] = '<div class="form-group col-sm-12">
|
||||
<label for="' . $classname . $value2['name'] . '"><?php echo __("' . $fieldName . '"); ?>:</label>
|
||||
<select class="form-control input-sm" name="' . $value2['name'] . '" id="' . $classname . $value2['name'] . '">
|
||||
<?php
|
||||
$options = '.$classname.'::getAll' . ucfirst($matches[1]) . '();
|
||||
foreach ($options as $value) {
|
||||
echo \'<option value="\'.$value[\'id\'].\'">\'.$value[\'id\'].\'</option>\';
|
||||
}
|
||||
?>
|
||||
</select>
|
||||
</div>';
|
||||
}else if ($value2['name'] == 'id') {
|
||||
$columnsGrid[] = "<th>#</th>";
|
||||
$columnsDatatable[] = '{"data": "id"}';
|
||||
$columnsForm[] = '<input type="hidden" name="id" id="' . $classname . 'id" value="" >';
|
||||
} else if ($value2['name'] == 'status') {
|
||||
$columnsGrid[] = '<th><?php echo __("' . $fieldName . '"); ?></th>';
|
||||
$columnsDatatable[] = '{"data": "' . $value2['name'] . '"}';
|
||||
$columnsForm[] = '<div class="form-group col-sm-12">
|
||||
<label for="status"><?php echo __("Status"); ?>:</label>
|
||||
<select class="form-control input-sm" name="status" id="' . $classname . 'status">
|
||||
<option value="a"><?php echo __("Active"); ?></option>
|
||||
<option value="i"><?php echo __("Inactive"); ?></option>
|
||||
</select>
|
||||
</div>';
|
||||
} else {
|
||||
$columnsGrid[] = '<th><?php echo __("' . $fieldName . '"); ?></th>';
|
||||
$columnsDatatable[] = '{"data": "' . $value2['name'] . '"}';
|
||||
if($type == 'text'){
|
||||
$columnsForm[] = '<div class="form-group col-sm-12">
|
||||
<label for="' . $classname . $value2['name'] . '"><?php echo __("' . $fieldName . '"); ?>:</label>
|
||||
<textarea id="' . $classname . $value2['name'] . '" name="' . $value2['name'] . '" class="form-control input-sm" placeholder="<?php echo __("' . $fieldName . '"); ?>" required="true"></textarea>
|
||||
</div>';
|
||||
}else if($type == 'int'){
|
||||
$columnsForm[] = '<div class="form-group col-sm-12">
|
||||
<label for="' . $classname . $value2['name'] . '"><?php echo __("' . $fieldName . '"); ?>:</label>
|
||||
<input type="number" step="1" id="' . $classname . $value2['name'] . '" name="' . $value2['name'] . '" class="form-control input-sm" placeholder="<?php echo __("' . $fieldName . '"); ?>" required="true">
|
||||
</div>';
|
||||
}else if($type == 'float'){
|
||||
$columnsForm[] = '<div class="form-group col-sm-12">
|
||||
<label for="' . $classname . $value2['name'] . '"><?php echo __("' . $fieldName . '"); ?>:</label>
|
||||
<input type="number" step="0.01" id="' . $classname . $value2['name'] . '" name="' . $value2['name'] . '" class="form-control input-sm" placeholder="<?php echo __("' . $fieldName . '"); ?>" required="true">
|
||||
</div>';
|
||||
|
||||
}else if($type == 'datetime'){
|
||||
$columnsForm[] = '<div class="form-group col-sm-12">
|
||||
<label for="' . $classname . $value2['name'] . '"><?php echo __("' . $fieldName . '"); ?>:</label>
|
||||
<input type="text" id="' . $classname . $value2['name'] . '" name="' . $value2['name'] . '" class="form-control input-sm" placeholder="<?php echo __("' . $fieldName . '"); ?>" required="true" autocomplete="off">
|
||||
</div>';
|
||||
$columnsFooter[] = '<script> $(document).ready(function () {$(\'#' . $classname . $value2['name'] . '\').datetimepicker({format: \'yyyy-mm-dd hh:ii\',autoclose: true });});</script>';
|
||||
|
||||
}else{
|
||||
$columnsForm[] = '<div class="form-group col-sm-12">
|
||||
<label for="' . $classname . $value2['name'] . '"><?php echo __("' . $fieldName . '"); ?>:</label>
|
||||
<input type="text" id="' . $classname . $value2['name'] . '" name="' . $value2['name'] . '" class="form-control input-sm" placeholder="<?php echo __("' . $fieldName . '"); ?>" required="true">
|
||||
</div>';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$templatesDir = __DIR__.'/templates/';
|
||||
|
||||
// Create class and view files for each table
|
||||
$classFile = "{$pluginDirObjects}{$classname}.php";
|
||||
$modelTemplate = file_get_contents("{$templatesDir}model.php");
|
||||
$search = array('{classname}', '{tablename}', '{pluginName}', '{columnsVars}', '{columnsString}', '{columnsGetAll}', '{columnsGet}', '{columnsSet}');
|
||||
$replace = array($classname, $value['name'], $pluginName, implode(",", $columnsVars), implode(",", $columnsString), implode(PHP_EOL, $columnsGetAll), implode(PHP_EOL, $columnsGet), implode(PHP_EOL, $columnsSet));
|
||||
$data = str_replace($search, $replace, $modelTemplate);
|
||||
$modelTemplate = file_get_contents("templates/model.php");
|
||||
$data = str_replace(
|
||||
['{classname}', '{tablename}', '{pluginName}', '{columnsVars}', '{columnsString}', '{columnsGetAll}', '{columnsGet}', '{columnsSet}'],
|
||||
[$classname, $tableName, $pluginName, implode(",", $columnsVars), implode(",", $columnsString), implode(PHP_EOL, $columnsGetAll), implode(PHP_EOL, $columnsGet), implode(PHP_EOL, $columnsSet)],
|
||||
$modelTemplate
|
||||
);
|
||||
file_put_contents($classFile, $data);
|
||||
|
||||
$response['createdFiles'][] = $classFile;
|
||||
|
||||
$dir = "{$pluginDirView}{$classname}/";
|
||||
_mkdir($dir);
|
||||
|
||||
$file = "{$dir}index.php";
|
||||
$modelTemplate = file_get_contents("{$templatesDir}index.php");
|
||||
$search = array('{classname}', '{pluginName}');
|
||||
$replace = array($classname, $pluginName);
|
||||
$data = str_replace($search, $replace, $modelTemplate);
|
||||
file_put_contents($file, $data);
|
||||
// index.php
|
||||
$indexFile = "{$dir}index.php";
|
||||
$indexTemplate = file_get_contents("templates/index.php");
|
||||
$indexData = str_replace(['{classname}', '{pluginName}'], [$classname, $pluginName], $indexTemplate);
|
||||
file_put_contents($indexFile, $indexData);
|
||||
$response['createdFiles'][] = $indexFile;
|
||||
|
||||
$file = "{$dir}index_body.php";
|
||||
$modelTemplate = file_get_contents("{$templatesDir}index_body.php");
|
||||
$search = array('{classname}','{tablename}', '{pluginName}', '{columnsForm}', '{columnsFooter}', '{columnsGrid}', '{$columnsClearJQuery}', '{columnsDatatable}', '{$columnsEdit}');
|
||||
$replace = array($classname,$value['name'], $pluginName, implode(PHP_EOL, $columnsForm), implode(PHP_EOL, $columnsFooter), implode(PHP_EOL, $columnsGrid), implode(PHP_EOL, $columnsClearJQuery), implode("," . PHP_EOL, $columnsDatatable), implode(PHP_EOL, $columnsEdit));
|
||||
$data = str_replace($search, $replace, $modelTemplate);
|
||||
file_put_contents($file, $data);
|
||||
// index_body.php
|
||||
$indexBodyFile = "{$dir}index_body.php";
|
||||
$indexBodyTemplate = file_get_contents("templates/index_body.php");
|
||||
$indexBodyData = str_replace(
|
||||
['{classname}', '{tablename}', '{pluginName}', '{columnsForm}', '{columnsFooter}', '{columnsGrid}', '{$columnsClearJQuery}', '{columnsDatatable}', '{$columnsEdit}'],
|
||||
[$classname, $tableName, $pluginName, implode(PHP_EOL, $columnsForm), implode(PHP_EOL, $columnsFooter), implode(PHP_EOL, $columnsGrid), implode(PHP_EOL, $columnsClearJQuery), implode("," . PHP_EOL, $columnsDatatable), implode(PHP_EOL, $columnsEdit)],
|
||||
$indexBodyTemplate
|
||||
);
|
||||
file_put_contents($indexBodyFile, $indexBodyData);
|
||||
$response['createdFiles'][] = $indexBodyFile;
|
||||
|
||||
$file = "{$dir}list.json.php";
|
||||
$modelTemplate = file_get_contents("{$templatesDir}list.json.php");
|
||||
$search = array('{classname}', '{pluginName}');
|
||||
$replace = array($classname, $pluginName);
|
||||
$data = str_replace($search, $replace, $modelTemplate);
|
||||
file_put_contents($file, $data);
|
||||
// list.json.php
|
||||
$listFile = "{$dir}list.json.php";
|
||||
$listTemplate = file_get_contents("templates/list.json.php");
|
||||
$listData = str_replace(['{classname}', '{pluginName}'], [$classname, $pluginName], $listTemplate);
|
||||
file_put_contents($listFile, $listData);
|
||||
$response['createdFiles'][] = $listFile;
|
||||
|
||||
$file = "{$dir}delete.json.php";
|
||||
$modelTemplate = file_get_contents("{$templatesDir}delete.json.php");
|
||||
$search = array('{classname}', '{pluginName}');
|
||||
$replace = array($classname, $pluginName);
|
||||
$data = str_replace($search, $replace, $modelTemplate);
|
||||
file_put_contents($file, $data);
|
||||
// delete.json.php
|
||||
$deleteFile = "{$dir}delete.json.php";
|
||||
$deleteTemplate = file_get_contents("templates/delete.json.php");
|
||||
$deleteData = str_replace(['{classname}', '{pluginName}'], [$classname, $pluginName], $deleteTemplate);
|
||||
file_put_contents($deleteFile, $deleteData);
|
||||
$response['createdFiles'][] = $deleteFile;
|
||||
|
||||
$file = "{$dir}add.json.php";
|
||||
$modelTemplate = file_get_contents("{$templatesDir}add.json.php");
|
||||
$search = array('{classname}', '{pluginName}', '{columnsAdd}');
|
||||
$replace = array($classname, $pluginName, implode(PHP_EOL, $columnsAdd));
|
||||
$data = str_replace($search, $replace, $modelTemplate);
|
||||
file_put_contents($file, $data);
|
||||
// add.json.php
|
||||
$addFile = "{$dir}add.json.php";
|
||||
$addTemplate = file_get_contents("templates/add.json.php");
|
||||
$addData = str_replace(['{classname}', '{pluginName}', '{columnsAdd}'], [$classname, $pluginName, implode(PHP_EOL, $columnsAdd)], $addTemplate);
|
||||
file_put_contents($addFile, $addData);
|
||||
$response['createdFiles'][] = $addFile;
|
||||
}
|
||||
|
||||
// Finalize main plugin and editor files
|
||||
$pluginFile = "{$pluginDir}{$pluginName}.php";
|
||||
$pluginTemplate = file_get_contents("templates/plugin.php");
|
||||
$pluginData = str_replace(
|
||||
['{pluginName}', '{includeTables}', '{tablename}', '{uid}'],
|
||||
[$pluginName, implode(PHP_EOL, $includeTables), $pluginName, uniqid()],
|
||||
$pluginTemplate
|
||||
);
|
||||
file_put_contents($pluginFile, $pluginData);
|
||||
$response['createdFiles'][] = $pluginFile;
|
||||
|
||||
$editorFile = "{$pluginDir}View/editor.php";
|
||||
$editorTemplate = file_get_contents("templates/editor.php");
|
||||
$editorData = str_replace(
|
||||
['{pluginName}', '{editorNavTabs}', '{editorNavContent}'],
|
||||
[$pluginName, implode(PHP_EOL, $editorNavTabs), implode(PHP_EOL, $editorNavContent)],
|
||||
$editorTemplate
|
||||
);
|
||||
file_put_contents($editorFile, $editorData);
|
||||
$response['createdFiles'][] = $editorFile;
|
||||
|
||||
// Populate response with plugin details
|
||||
$response['pluginName'] = $pluginName;
|
||||
$response['pluginDir'] = $pluginDir;
|
||||
$response['msg'] = "Plugin '{$pluginName}' created successfully.";
|
||||
|
||||
$response['zipDirectory'] = zipDirectory( __DIR__."/{$pluginDir}", __DIR__."/{$pluginZip}");
|
||||
|
||||
$response['zipDownload'] = "{$global['webSiteRootURL']}CreatePlugin/{$pluginZip}";
|
||||
|
||||
rrmdir(__DIR__."/{$pluginDir}");
|
||||
|
||||
} catch (Exception $e) {
|
||||
$response['error'] = true;
|
||||
$response['msg'] = $e->getMessage();
|
||||
}
|
||||
|
||||
$pluginFile = "{$pluginDir}$pluginName.php";
|
||||
$pluginTemplate = file_get_contents("{$templatesDir}plugin.php");
|
||||
$search = array('{pluginName}', '{includeTables}', '{tablename}', '{uid}');
|
||||
$replace = array($pluginName, implode(PHP_EOL, $includeTables), $pluginName, "5ee8405eaaa16");
|
||||
$data = str_replace($search, $replace, $pluginTemplate);
|
||||
file_put_contents($pluginFile, $data);
|
||||
|
||||
$pluginFile = "{$pluginDir}View/editor.php";
|
||||
$pluginTemplate = file_get_contents("{$templatesDir}editor.php");
|
||||
$search = array('{pluginName}', '{editorNavTabs}', '{editorNavContent}');
|
||||
$replace = array($pluginName, implode(PHP_EOL, $editorNavTabs), implode(PHP_EOL, $editorNavContent));
|
||||
$data = str_replace($search, $replace, $pluginTemplate);
|
||||
file_put_contents($pluginFile, $data);
|
||||
echo json_encode($response);
|
||||
|
||||
// Helper function to create directories if they don't exist
|
||||
function _mkdir($dir) {
|
||||
if (!is_dir($dir)) {
|
||||
mkdir($dir);
|
||||
mkdir($dir, 0777, true);
|
||||
}
|
||||
}
|
||||
|
|
38
CreatePlugin/delete_zip_file.php
Normal file
38
CreatePlugin/delete_zip_file.php
Normal file
|
@ -0,0 +1,38 @@
|
|||
<?php
|
||||
require_once __DIR__.'/../videos/configuration.php';
|
||||
|
||||
header('Content-Type: application/json');
|
||||
|
||||
if(!User::isAdmin()){
|
||||
forbiddenPage('You Must be admin');
|
||||
}
|
||||
|
||||
if(!empty($global['disableAdvancedConfigurations'])){
|
||||
forbiddenPage('Configuration disabled');
|
||||
}
|
||||
|
||||
$response = ['error' => false, 'msg' => ''];
|
||||
|
||||
if (!isset($_POST['fileName'])) {
|
||||
$response['error'] = true;
|
||||
$response['msg'] = 'File name not specified.';
|
||||
echo json_encode($response);
|
||||
exit;
|
||||
}
|
||||
|
||||
$fileName = basename($_POST['fileName']); // Sanitize file name
|
||||
$filePath = __DIR__ . '/plugins/' . $fileName;
|
||||
|
||||
if (file_exists($filePath) && pathinfo($filePath, PATHINFO_EXTENSION) === 'zip') {
|
||||
if (unlink($filePath)) {
|
||||
$response['msg'] = 'File deleted successfully.';
|
||||
} else {
|
||||
$response['error'] = true;
|
||||
$response['msg'] = 'Failed to delete the file.';
|
||||
}
|
||||
} else {
|
||||
$response['error'] = true;
|
||||
$response['msg'] = 'File does not exist or is not a zip file.';
|
||||
}
|
||||
|
||||
echo json_encode($response);
|
|
@ -10,74 +10,156 @@ if (!empty($global['disableAdvancedConfigurations'])) {
|
|||
}
|
||||
|
||||
$page = new Page('Create plugin');
|
||||
|
||||
// Define the plugins directory
|
||||
$pluginsDir = __DIR__ . '/plugins/';
|
||||
?>
|
||||
<div class="container">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<h2>Create New Plugin</h2>
|
||||
<h2><i class="fas fa-plug"></i> Create New Plugin</h2>
|
||||
<p>
|
||||
<i class="fas fa-info-circle"></i>
|
||||
This tool will generate a base code structure for a new plugin based on the SQL you provide.
|
||||
This is not the final plugin code but serves as a starting point to help you kickstart your plugin development process.
|
||||
After creating this base, you can add custom logic and features as needed to complete your plugin.
|
||||
</p>
|
||||
<ul>
|
||||
<li><i class="fas fa-file-signature"></i> Provide a name for the plugin.</li>
|
||||
<li><i class="fas fa-database"></i> Optionally, enter the SQL code to create your plugin's table in the text area below.</li>
|
||||
<li><i class="fas fa-check-circle"></i> Click "<i class="fas fa-plus-circle"></i> Create Plugin" to submit the data.</li>
|
||||
</ul>
|
||||
<small>
|
||||
For more detailed instructions on how to further develop and customize your plugin, please refer to the
|
||||
<a href="https://github.com/WWBN/AVideo/wiki/How-to-code-a-AVideo-Platform-plugin" target="_blank">AVideo Plugin Development Guide</a> on GitHub.
|
||||
</small>
|
||||
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<form id="createPluginForm">
|
||||
<div class="form-group">
|
||||
<label for="pluginName">Plugin Name</label>
|
||||
<label for="pluginName"><i class="fas fa-tag"></i> Plugin Name</label>
|
||||
<input type="text" class="form-control" id="pluginName" name="pluginName" placeholder="Enter Plugin Name" required>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="createTableSQL">CREATE TABLE SQL</label>
|
||||
<textarea class="form-control" id="createTableSQL" name="createTableSQL" rows="5" placeholder="Paste your CREATE TABLE SQL here" required></textarea>
|
||||
<label for="createTableSQL"><i class="fas fa-database"></i> CREATE TABLE SQL (Optional)</label>
|
||||
<textarea class="form-control" id="createTableSQL" name="createTableSQL" rows="5" placeholder="Paste your CREATE TABLE SQL here (optional)"></textarea>
|
||||
</div>
|
||||
<button type="button" id="createPluginButton" class="btn btn-primary btn-block">Create Plugin</button>
|
||||
<button type="button" id="createPluginButton" class="btn btn-success btn-block"><i class="fas fa-plus-circle"></i> Create Plugin</button>
|
||||
</form>
|
||||
<div id="responseMessage" class="alert" style="display:none; margin-top: 10px;"></div>
|
||||
</div>
|
||||
|
||||
<!-- Section for additional information -->
|
||||
<div class="panel-footer">
|
||||
<h3>Instructions:</h3>
|
||||
<ul>
|
||||
<li>Enter the SQL code to create your plugin's table in the text area below.</li>
|
||||
<li>Provide a name for the plugin. The name must start with an uppercase letter, contain only letters, numbers, and underscores, and should have no spaces.</li>
|
||||
<li>Invalid characters will be automatically removed as you type.</li>
|
||||
<li>Click "Create Plugin" to submit the data.</li>
|
||||
</ul>
|
||||
<h3><i class="fas fa-folder-open"></i> Existing Plugin Zips</h3>
|
||||
<div id="zipFilesList">
|
||||
<!-- Zip files list will be loaded here -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<script>
|
||||
var listModal = getPleaseWait();
|
||||
var deleteModal = getPleaseWait();
|
||||
$(document).ready(function() {
|
||||
// Auto-format plugin name input
|
||||
$('#pluginName').on('input', function() {
|
||||
let value = $(this).val();
|
||||
// Remove invalid characters and ensure the first letter is uppercase
|
||||
value = value.replace(/[^a-zA-Z0-9_]/g, ''); // Remove any character that is not a letter, number, or underscore
|
||||
value = value.replace(/[^a-zA-Z0-9_]/g, ''); // Remove any invalid character
|
||||
if (value.length > 0) {
|
||||
value = value.charAt(0).toUpperCase() + value.slice(1); // Ensure the first letter is uppercase
|
||||
value = value.charAt(0).toUpperCase() + value.slice(1); // Capitalize first letter
|
||||
}
|
||||
$(this).val(value);
|
||||
});
|
||||
|
||||
// AJAX submit on button click
|
||||
// AJAX to create plugin
|
||||
$('#createPluginButton').on('click', function() {
|
||||
let pluginName = $('#pluginName').val();
|
||||
let createTableSQL = $('#createTableSQL').val();
|
||||
|
||||
if (pluginName && createTableSQL) {
|
||||
if (pluginName) {
|
||||
modal.showPleaseWait();
|
||||
$.ajax({
|
||||
url: webSiteRootURL + 'CreatePlugin/create.json.php',
|
||||
type: 'POST',
|
||||
data: {
|
||||
pluginName: pluginName,
|
||||
createTableSQL: createTableSQL
|
||||
pluginName,
|
||||
createTableSQL
|
||||
},
|
||||
success: function(response) {
|
||||
$('#responseMessage').removeClass('alert-danger').addClass('alert-success').text('Plugin created successfully!').show();
|
||||
modal.hidePleaseWait();
|
||||
if (response.error) {
|
||||
$('#responseMessage').removeClass('alert-success').addClass('alert-danger').text('Error: ' + response.msg).show();
|
||||
} else {
|
||||
let successMessage = '<i class="fas fa-check-circle"></i> Plugin created successfully!<br>' +
|
||||
'<i class="fas fa-plug"></i> Plugin Name: ' + response.pluginName + '<br>' +
|
||||
'<i class="fas fa-folder"></i> Plugin Directory: ' + response.pluginDir + '<br>' +
|
||||
'<i class="fas fa-database"></i> Tables Found: ' + response.tables.join(', ') + '<br>' +
|
||||
'<i class="fas fa-file-code"></i> Files Created: <ul>';
|
||||
response.createdFiles.forEach(file => successMessage += '<li>' + file + '</li>');
|
||||
successMessage += '</ul>';
|
||||
|
||||
$('#responseMessage').removeClass('alert-danger').addClass('alert-success').html(successMessage).show();
|
||||
loadZipFiles();
|
||||
}
|
||||
},
|
||||
error: function() {
|
||||
$('#responseMessage').removeClass('alert-success').addClass('alert-danger').text('An error occurred while creating the plugin.').show();
|
||||
modal.hidePleaseWait();
|
||||
$('#responseMessage').removeClass('alert-success').addClass('alert-danger').text('An error occurred while creating the plugin. Please try again later.').show();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
$('#responseMessage').removeClass('alert-success').addClass('alert-danger').text('Please fill in both fields.').show();
|
||||
$('#responseMessage').removeClass('alert-success').addClass('alert-danger').text('Please fill the name').show();
|
||||
}
|
||||
});
|
||||
|
||||
// Function to load zip files
|
||||
function loadZipFiles() {
|
||||
listModal.showPleaseWait();
|
||||
$.getJSON(webSiteRootURL + 'CreatePlugin/list_zip_files.php', function(data) {
|
||||
listModal.hidePleaseWait();
|
||||
if (data.length === 0) {
|
||||
$('#zipFilesList').html('<p><i class="fas fa-info-circle"></i> No zip files available.</p>');
|
||||
} else {
|
||||
let listHtml = '<ul class="list-group">';
|
||||
data.forEach(file => {
|
||||
listHtml += '<li class="list-group-item">' +
|
||||
' <a href="' + webSiteRootURL + 'CreatePlugin/plugins/' + file + '" class="btn btn-sm btn-primary" download><i class="fas fa-download"></i> Download</a> ' +
|
||||
' <button class="btn btn-sm btn-danger" onclick="deleteZipFile(\'' + file + '\')"><i class="fas fa-trash-alt"></i> Delete</button> ' +
|
||||
file +
|
||||
'</li>';
|
||||
});
|
||||
listHtml += '</ul>';
|
||||
$('#zipFilesList').html(listHtml);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Function to delete zip file
|
||||
window.deleteZipFile = function(fileName) {
|
||||
deleteModal.showPleaseWait();
|
||||
$.ajax({
|
||||
url: webSiteRootURL + 'CreatePlugin/delete_zip_file.php',
|
||||
type: 'POST',
|
||||
data: {
|
||||
fileName
|
||||
},
|
||||
success: function(response) {
|
||||
deleteModal.hidePleaseWait();
|
||||
if (response.error) {
|
||||
alert('Error: ' + response.msg);
|
||||
} else {
|
||||
loadZipFiles(); // Refresh list
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// Initial load of zip files
|
||||
loadZipFiles();
|
||||
});
|
||||
</script>
|
||||
<?php
|
||||
|
|
24
CreatePlugin/list_zip_files.php
Normal file
24
CreatePlugin/list_zip_files.php
Normal file
|
@ -0,0 +1,24 @@
|
|||
<?php
|
||||
require_once __DIR__.'/../videos/configuration.php';
|
||||
|
||||
header('Content-Type: application/json');
|
||||
|
||||
if(!User::isAdmin()){
|
||||
forbiddenPage('You Must be admin');
|
||||
}
|
||||
|
||||
if(!empty($global['disableAdvancedConfigurations'])){
|
||||
forbiddenPage('Configuration disabled');
|
||||
}
|
||||
|
||||
$pluginsDir = __DIR__ . '/plugins/';
|
||||
$files = [];
|
||||
|
||||
// Check if directory exists
|
||||
if (is_dir($pluginsDir)) {
|
||||
foreach (glob($pluginsDir . "*.zip") as $file) {
|
||||
$files[] = basename($file); // Add only the file name
|
||||
}
|
||||
}
|
||||
|
||||
echo json_encode($files);
|
|
@ -23,14 +23,14 @@ function getDurationFromFile($file)
|
|||
if (!file_exists($videoFile)) {
|
||||
$file_headers = @get_headers($videoFile);
|
||||
if (!$file_headers || $file_headers[0] == 'HTTP/1.1 404 Not Found') {
|
||||
error_log('getDurationFromFile try 1, File (' . $videoFile . ') Not Found original='.$file);
|
||||
error_log('getDurationFromFile try 1, File (' . $videoFile . ') Not Found original=' . $file);
|
||||
$videoFile = $hls;
|
||||
}
|
||||
}
|
||||
if (!file_exists($videoFile)) {
|
||||
$file_headers = @get_headers($videoFile);
|
||||
if (!$file_headers || $file_headers[0] == 'HTTP/1.1 404 Not Found') {
|
||||
error_log('getDurationFromFile try 2, File (' . $videoFile . ') Not Found original='.$file);
|
||||
error_log('getDurationFromFile try 2, File (' . $videoFile . ') Not Found original=' . $file);
|
||||
$videoFile = '';
|
||||
}
|
||||
}
|
||||
|
@ -243,6 +243,82 @@ function unzipDirectory($filename, $destination)
|
|||
return $return_val === 0;
|
||||
}
|
||||
|
||||
function zipDirectory($source, $destination)
|
||||
{
|
||||
// Set memory limit and execution time to avoid issues with large files
|
||||
ini_set('memory_limit', '-1');
|
||||
set_time_limit(0);
|
||||
|
||||
// Check if the source directory exists
|
||||
if (!is_dir($source)) {
|
||||
_error_log("zipDirectory: Source directory does not exist: {$source}");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Ensure the destination directory exists, create it if it doesn't
|
||||
$destinationDir = dirname($destination);
|
||||
if (!is_dir($destinationDir)) {
|
||||
if (!mkdir($destinationDir, 0755, true)) {
|
||||
_error_log("zipDirectory: Failed to create destination directory: {$destinationDir}");
|
||||
return false;
|
||||
}
|
||||
_error_log("zipDirectory: Destination directory created: {$destinationDir}");
|
||||
}
|
||||
chmod($source, 0755);
|
||||
|
||||
// Escape the input parameters to prevent command injection attacks
|
||||
$sourceOriginal = rtrim($source, '/'); // Remove trailing slash for consistency
|
||||
$destinationOriginal = $destination;
|
||||
$source = escapeshellarg($source);
|
||||
$destination = escapeshellarg($destination);
|
||||
|
||||
// Build the command for zipping the directory
|
||||
$cmd = "zip -r -q {$destination} {$source} 2>&1";
|
||||
|
||||
// Log the command for debugging purposes
|
||||
_error_log("zipDirectory: {$cmd}");
|
||||
|
||||
// Execute the command and capture the output and return value
|
||||
exec($cmd, $output, $return_val);
|
||||
|
||||
if ($return_val !== 0) {
|
||||
// Log the output and return value
|
||||
_error_log("zipDirectory: Command failed with return value {$return_val}");
|
||||
_error_log("zipDirectory: Command output: " . implode("\n", $output));
|
||||
|
||||
// Try using PHP's ZipArchive class as a fallback
|
||||
if (class_exists('ZipArchive')) {
|
||||
$zip = new ZipArchive();
|
||||
if ($zip->open($destinationOriginal, ZipArchive::CREATE | ZipArchive::OVERWRITE) === true) {
|
||||
$dirIterator = new RecursiveDirectoryIterator($sourceOriginal);
|
||||
$files = new RecursiveIteratorIterator($dirIterator, RecursiveIteratorIterator::LEAVES_ONLY);
|
||||
|
||||
// Get the base directory name to use as root folder in the zip
|
||||
$baseFolder = basename($sourceOriginal);
|
||||
|
||||
foreach ($files as $name => $file) {
|
||||
if (!$file->isDir()) {
|
||||
$filePath = $file->getRealPath();
|
||||
// Calculate relative path, including the base folder
|
||||
$relativePath = $baseFolder . '/' . substr($filePath, strlen($sourceOriginal) + 1);
|
||||
$zip->addFile($filePath, $relativePath);
|
||||
}
|
||||
}
|
||||
|
||||
$zip->close();
|
||||
_error_log("zipDirectory: Success using ZipArchive for {$destination}");
|
||||
} else {
|
||||
_error_log("zipDirectory: Error opening zip archive using ZipArchive: {$destination}");
|
||||
}
|
||||
} else {
|
||||
_error_log("zipDirectory: Error: ZipArchive class is not available");
|
||||
}
|
||||
} else {
|
||||
_error_log("zipDirectory: Success {$destination}");
|
||||
}
|
||||
|
||||
return file_exists($destinationOriginal);
|
||||
}
|
||||
|
||||
|
||||
function getPIDUsingPort($port)
|
||||
|
@ -396,7 +472,7 @@ function execAsync($command, $keyword = null)
|
|||
}
|
||||
}
|
||||
} else {
|
||||
if(empty($output)){
|
||||
if (empty($output)) {
|
||||
return $output;
|
||||
}
|
||||
$pid = (int)$output[0];
|
||||
|
@ -420,12 +496,12 @@ function findProcess($keyword)
|
|||
//var_dump($pgrepOutput);
|
||||
if ($retval === 0) {
|
||||
foreach ($pgrepOutput as $pgrepPid) {
|
||||
if(preg_match('/pgrep /i', $pgrepPid)){
|
||||
if (preg_match('/pgrep /i', $pgrepPid)) {
|
||||
continue;
|
||||
}
|
||||
if(preg_match('/([0-9]+) (.*)/i', $pgrepPid, $matches)){
|
||||
if(!empty($matches[2])){
|
||||
$output[] = array('pid'=>(int)$matches[1], 'command'=>trim($matches[2]));
|
||||
if (preg_match('/([0-9]+) (.*)/i', $pgrepPid, $matches)) {
|
||||
if (!empty($matches[2])) {
|
||||
$output[] = array('pid' => (int)$matches[1], 'command' => trim($matches[2]));
|
||||
}
|
||||
}
|
||||
//$output[] = (int)$pgrepPid;
|
||||
|
|
|
@ -68,6 +68,9 @@ $wwbnIndexPlugin = AVideoPlugin::isEnabledByName('WWBNIndex');
|
|||
<button type="button" class="btn btn-default" id="upload">
|
||||
<i class="fas fa-plus"></i> <?php echo __("Upload a Plugin"); ?>
|
||||
</button>
|
||||
<button type="button" class="btn btn-primary" id="createPlugin" onclick="avideoModalIframeFull(webSiteRootURL + 'CreatePlugin/');">
|
||||
<i class="fas fa-plus-circle"></i> <?php echo __("Create a Plugin"); ?>
|
||||
</button>
|
||||
</div>
|
||||
<div style="text-align: right; padding: 5px;">
|
||||
<span class="badge" id="PluginTagsTotal">...</span>
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue